diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..b629c6a --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,16 @@ +# Copyright Antony Polukhin 2011. Use, modification, and distribution are +# subject to the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +using quickbook ; +import boostbook : boostbook ; + +xml lexical_cast : lexical_cast.qbk ; +boostbook standalone + : + lexical_cast + : + boost.root=../../../.. + pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html + ; + diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk new file mode 100644 index 0000000..b540267 --- /dev/null +++ b/doc/lexical_cast.qbk @@ -0,0 +1,607 @@ +[library Boost.Lexical_Cast + [quickbook 1.5] + [version 1.0] + [copyright 2000-2005 Kevlin Henney] + [copyright 2006-2010 Alexander Nasonov] + [copyright 2011 Antony Polukhin] + [category String and text processing] + [category Miscellaneous] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] +] + +[def __numericcast__ [@boost:libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html `boost::numeric_cast`]] +[def __proposallong__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973 by Kevlin Henney and Beman Dawes]] +[def __proposalshort__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973]] + +[section Motivation] +Sometimes a value must be converted to a literal text form, such as an [c++] `int` represented as a `std::string`, or vice-versa, when a `std::string` is interpreted as an `int`. Such examples are common when converting between data types internal to a program and representation external to a program, such as windows and configuration files. + +The standard C and C++ libraries offer a number of facilities for performing such conversions. However, they vary with their ease of use, extensibility, and safety. + +For instance, there are a number of limitations with the family of standard C functions typified by `atoi`: + +* Conversion is supported in one direction only: from text to internal data type. Converting the other way using the C library requires either the inconvenience and compromised safety of the `sprintf` function, or the loss of portability associated with non-standard functions such as `itoa`. +* The range of types supported is only a subset of the built-in numeric types, namely `int`, `long`, and `double`. +* The range of types cannot be extended in a uniform manner. For instance, conversion from string representation to complex or rational. + +The standard C functions typified by `strtol` have the same basic limitations, but offer finer control over the conversion process. However, for the common case such control is often either not required or not used. The `scanf` family of functions offer even greater control, but also lack safety and ease of use. + +The standard C++ library offers `stringstream` for the kind of in-core formatting being discussed. It offers a great deal of control over the formatting and conversion of I/O to and from arbitrary types through text. However, for simple conversions direct use of `stringstream` can be either clumsy (with the introduction of extra local variables and the loss of infix-expression convenience) or obscure (where `stringstream` objects are created as temporary objects in an expression). Facets provide a comprehensive concept and facility for controlling textual representation, but their perceived complexity and high entry level requires an extreme degree of involvement for simple conversions, and excludes all but a few programmers. + +The `lexical_cast` function template offers a convenient and consistent form for supporting common conversions to and from arbitrary types when they are represented as text. The simplification it offers is in expression-level convenience for such conversions. For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of `lexical_cast`, the conventional `std::stringstream` approach is recommended. Where the conversions are numeric to numeric, __numericcast__ may offer more reasonable behavior than `lexical_cast`. + +For a good discussion of the options and issues involved in string-based formatting, including comparison of `stringstream`, `lexical_cast`, and others, see Herb Sutter's article, [@http://www.gotw.ca/publications/mill19.htm The String Formatters of Manor Farm]. Also, take a look at the [link boost_lexical_cast.performance Performance] section. +[endsect] + +[section Examples] +The following example treats command line arguments as a sequence of numeric data: +`` + int main(int argc, char * argv[]) + { + using boost::lexical_cast; + using boost::bad_lexical_cast; + + std::vector args; + + while(*++argv) + { + try + { + args.push_back(lexical_cast(*argv)); + } + catch(bad_lexical_cast &) + { + args.push_back(0); + } + } + ... + } +`` +The following example uses numeric data in a string expression: +`` + void log_message(const std::string &); + + void log_errno(int yoko) + { + log_message("Error " + boost::lexical_cast(yoko) + ": " + strerror(yoko)); + } +`` +[endsect] + +[section Synopsis] +Library features defined in [@boost:boost/lexical_cast.hpp boost/lexical_cast.hpp]: +`` + namespace boost + { + class bad_lexical_cast; + template + Target lexical_cast(const Source& arg); + } +`` + +[section lexical_cast] +`` + template + Target lexical_cast(const Source& arg); +`` +Returns the result of streaming arg into a standard library string-based stream and then out as a Target object. Where Target is either `std::string` or `std::wstring`, stream extraction takes the whole content of the string, including spaces, rather than relying on the default `operator>>` behavior. If the conversion is unsuccessful, a `bad_lexical_cast` exception is thrown. + +The requirements on the argument and result types are: + +* Source is OutputStreamable, meaning that an `operator<<` is defined that takes a `std::ostream` or `std::wostream` object on the left hand side and an instance of the argument type on the right. +* Target is InputStreamable, meaning that an `operator>>` is defined that takes a `std::istream` or `std::wistream` object on the left hand side and an instance of the result type on the right. +* Target is CopyConstructible [20.1.3]. +* Target is DefaultConstructible, meaning that it is possible to default-initialize an object of that type [8.5, 20.1.4]. + +The character type of the underlying stream is assumed to be char unless either the Source or the Target requires wide-character streaming, in which case the underlying stream uses `wchar_t`. Source types that require wide-character streaming are `wchar_t`, `wchar_t *`, and `std::wstring`. Target types that require wide-character streaming are `wchar_t` and `std::wstring`. + +Where a higher degree of control is required over conversions, `std::stringstream` and `std::wstringstream` offer a more appropriate path. Where non-stream-based conversions are required, `lexical_cast` is the wrong tool for the job and is not special-cased for such scenarios. +[endsect] + +[section bad_lexical_cast] +`` + class bad_lexical_cast : public std::bad_cast + { + public: + ... // same member function interface as std::exception + }; +`` +Exception used to indicate runtime lexical_cast failure. +[endsect] + +[endsect] + +[section Frequently Asked Questions] + +* [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? + * [*Answer:] The type `int8_t` is a `typedef` to `char` or `signed char`. Lexical conversion to these types is simply reading a byte from source but since the source has more than one byte, the exception is thrown. +Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also +call __numericcast__: +`numeric_cast(lexical_cast("127"));` + +[pre +] + +* [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? + * [*Answer:] Lexical conversion to any char type is simply reading a byte from source. But since the source has more than one byte, the exception is thrown. +Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also +call __numericcast__: +`numeric_cast(lexical_cast("127"));` + +[pre +] + +* [*Question:] What does `lexical_cast` of an `int8_t` or `uint8_t` not do what I expect? + * [*Answer:] As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid +this, cast to an integer type first: `lexical_cast(static_cast(n));` + +[pre +] + +* [*Question:] The implementation always resets the `ios_base::skipws` flag of an underlying stream object. +It breaks my `operator>>` that works only in presence of this flag. Can you remove code that resets the flag? + * [*Answer:] May be in a future version. There is no requirement in +__proposallong__ to reset the flag but +remember that __proposalshort__ is not yet accepted by the committee. By the way, it's a great opportunity to +make your `operator>>` conform to the standard. +Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html `ios_state_saver`]. + +[pre +] + +* [*Question:] Why `std::cout << boost::lexical_cast("-1");` does not throw, but outputs 4294967295? + * [*Answer:] `boost::lexical_cast` has the behavior of `std::stringstream`, which uses `num_get` functions of +`std::locale` to convert numbers. If we look at the Programming languages — C++, we'll see, that `num_get` uses +the rules of `scanf` for conversions. And in the C99 standard for unsigned input value minus sign is optional, so +if a negative number is read, no errors will arise and the result will be the two's complement. + +[endsect] + +[section Changes] +* [*boost 1.48.0 :] + + * Added code to work with Inf and NaN on any platform. + * Better performance and less memory usage for conversions to float type (and to double type, if `sizeof(double) < sizeof(long double)`). + +* [*boost 1.47.0 :] + + * Optimizations for "C" and other locales without number grouping. + * Better performance and less memory usage for unsigned char and signed char conversions. + * Better performance and less memory usage for conversions to arithmetic types. + * Better performance and less memory usage for conversions from arithmetic type to arithmetic type. + * Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others). + +* [*boost 1.34.0 :] + + * Better performance for many combinations of Source and Target types. For more details refer to Alexander Nasonovs article [@http://accu.org/index.php/journals/1375 Fine Tuning for lexical_cast, Overload #74, August 2006] [@http://www.accu.org/var/uploads/journals/overload74.pdf (PDF)]. + +* [*boost 1.33.0 :] + + * Call-by-const reference for the parameters. This requires partial specialization of class templates, so it doesn't work for MSVC 6, and it uses the original pass by value there. + * The MSVC 6 support is deprecated, and will be removed in a future Boost version. + +* [*Earlier :] + + * The previous version of lexical_cast used the default stream precision for reading and writing floating-point numbers. For numerics that have a corresponding specialization of `std::numeric_limits`, the current version now chooses a precision to match. + * The previous version of lexical_cast did not support conversion to or from any wide-character-based types. For compilers with full language and library support for wide characters, `lexical_cast` now supports conversions from `wchar_t`, `wchar_t *`, and `std::wstring` and to `wchar_t` and `std::wstring`. + * The previous version of `lexical_cast` assumed that the conventional stream extractor operators were sufficient for reading values. However, string I/O is asymmetric, with the result that spaces play the role of I/O separators rather than string content. The current version fixes this error for `std::string` and, where supported, `std::wstring`: `lexical_cast("Hello, World")` succeeds instead of failing with a `bad_lexical_cast` exception. + * The previous version of `lexical_cast` allowed unsafe and meaningless conversions to pointers. The current version now throws a `bad_lexical_cast` for conversions to pointers: `lexical_cast("Goodbye, World")` now throws an exception instead of causing undefined behavior. + +[endsect] + +[section Performance] + +In most cases `boost::lexical_cast` is faster than `scanf`, `printf`, `std::stringstream`. For more detailed info you can look at the tables below. + +[section Tests description] +All the tests measure execution speed in milliseconds for 10000 iterations of the following code blocks: +[table:legend Tests source code +[[Test name] [Code]] +[[lexical_cast] + [`` + _out = boost::lexical_cast(_in); + ``] + ] +[[std::stringstream with construction] + [`` + std::stringstream ss; + ss << _in; + if (ss.fail()) throw std::logic_error(descr); + ss >> _out; + if (ss.fail()) throw std::logic_error(descr); + ``] + ] +[[std::stringstream without construction] + [`` + ss << _in; // ss is an instance of std::stringstream + if (ss.fail()) throw std::logic_error(descr); + ss >> _out; + if (ss.fail()) throw std::logic_error(descr); + /* reseting std::stringstream to use it again */ + ss.str(std::string()); + ss.clear(); + ``] + ] +[[scanf/printf] + [`` + typename OUTTYPE::value_type buffer[500]; + sprintf( (char*)buffer, conv, _in); + _out = buffer; + ``] + ] +] +Fastest results are highlitened with "!!! *x* !!!". +Do not use this results to compare compilers, because tests were taken on different hardware. + +[endsect] + +[/ BEGIN of section, generated by performance measuring program ] + +[section clang-linux-2.8][table:id Performance Table (clang-linux-2.8) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 148 ][ 14 ][ 12 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 97 ][ 8 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *4* !!! ][ 102 ][ 19 ][ 15 ]] +[[ string->short ][ !!! *4* !!! ][ 105 ][ 20 ][ 15 ]] +[[ string->long int ][ !!! *4* !!! ][ 105 ][ 19 ][ 15 ]] +[[ string->long long ][ !!! *4* !!! ][ 115 ][ 19 ][ 14 ]] +[[ string->unsigned int ][ !!! *4* !!! ][ 102 ][ 18 ][ 14 ]] +[[ string->unsigned short ][ !!! *4* !!! ][ 101 ][ 19 ][ 15 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 107 ][ 20 ][ 14 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 103 ][ 20 ][ 14 ]] +[[ string->bool ][ !!! *<1* !!! ][ 97 ][ 16 ][ 8 ]] +[[ string->float ][ !!! *21* !!! ][ 170 ][ 61 ][ 32 ]] +[[ string->double ][ !!! *18* !!! ][ 206 ][ 93 ][ 58 ]] +[[ string->long double ][ 135 ][ 221 ][ 94 ][ !!! *57* !!! ]] +[[ char->string ][ !!! *7* !!! ][ 100 ][ 17 ][ 13 ]] +[[ unsigned char->string ][ !!! *7* !!! ][ 99 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *7* !!! ][ 101 ][ 17 ][ 12 ]] +[[ int->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 15 ]] +[[ short->string ][ !!! *13* !!! ][ 112 ][ 24 ][ 18 ]] +[[ long int->string ][ !!! *13* !!! ][ 119 ][ 23 ][ 17 ]] +[[ long long->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 18 ]] +[[ unsigned int->string ][ !!! *14* !!! ][ 113 ][ 24 ][ 17 ]] +[[ unsigned short->string ][ !!! *13* !!! ][ 108 ][ 24 ][ 17 ]] +[[ unsigned long int->string ][ !!! *13* !!! ][ 109 ][ 24 ][ 16 ]] +[[ unsigned long long->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 17 ]] +[[ bool->string ][ !!! *7* !!! ][ 105 ][ 24 ][ 12 ]] +[[ float->string ][ 70 ][ 192 ][ 94 ][ !!! *49* !!! ]] +[[ double->string ][ 106 ][ 217 ][ 122 ][ !!! *76* !!! ]] +[[ long double->string ][ 120 ][ 219 ][ 123 ][ !!! *80* !!! ]] +[[ char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 8 ]] +[[ char*->signed char ][ !!! *2* !!! ][ 87 ][ 10 ][ 7 ]] +[[ char*->unsigned char ][ !!! *3* !!! ][ 90 ][ 10 ][ 13 ]] +[[ char*->int ][ !!! *6* !!! ][ 107 ][ 21 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 110 ][ 19 ][ 14 ]] +[[ char*->long int ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ char*->long long ][ !!! *7* !!! ][ 104 ][ 20 ][ 15 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 101 ][ 20 ][ 15 ]] +[[ char*->unsigned short ][ !!! *7* !!! ][ 100 ][ 20 ][ 14 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 105 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *7* !!! ][ 106 ][ 21 ][ 14 ]] +[[ char*->bool ][ !!! *2* !!! ][ 99 ][ 18 ][ 7 ]] +[[ char*->float ][ !!! *22* !!! ][ 159 ][ 67 ][ 33 ]] +[[ char*->double ][ !!! *20* !!! ][ 205 ][ 94 ][ 58 ]] +[[ char*->long double ][ 140 ][ 214 ][ 95 ][ !!! *58* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 92 ][ 9 ][ 7 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 89 ][ 10 ][ 7 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 89 ][ 10 ][ 14 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 106 ][ 21 ][ 14 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 105 ][ 19 ][ 14 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 106 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned int ][ !!! *7* !!! ][ 105 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 106 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 21 ][ 15 ]] +[[ unsigned char*->bool ][ !!! *2* !!! ][ 102 ][ 18 ][ 7 ]] +[[ unsigned char*->float ][ !!! *23* !!! ][ 160 ][ 66 ][ 32 ]] +[[ unsigned char*->double ][ !!! *20* !!! ][ 201 ][ 95 ][ 58 ]] +[[ unsigned char*->long double ][ 144 ][ 221 ][ 95 ][ !!! *60* !!! ]] +[[ unsigned char*->string ][ !!! *12* !!! ][ 104 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 7 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 89 ][ 9 ][ 7 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 89 ][ 10 ][ 13 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 106 ][ 19 ][ 15 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 107 ][ 20 ][ 15 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 101 ][ 19 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 101 ][ 19 ][ 16 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 105 ][ 22 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 21 ][ 15 ]] +[[ signed char*->bool ][ !!! *2* !!! ][ 100 ][ 18 ][ 7 ]] +[[ signed char*->float ][ !!! *23* !!! ][ 161 ][ 62 ][ 32 ]] +[[ signed char*->double ][ !!! *20* !!! ][ 207 ][ 102 ][ 57 ]] +[[ signed char*->long double ][ 144 ][ 216 ][ 96 ][ !!! *63* !!! ]] +[[ signed char*->string ][ !!! *12* !!! ][ 104 ][ 23 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 110 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 223 ][ 113 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 227 ][ 111 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 122 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 229 ][ 121 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 91 ][ 9 ][ --- ]] +] +[endsect] +[section gcc-4.4][table:id Performance Table (gcc-4.4) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 90 ][ 7 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 88 ][ 7 ][ 8 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 88 ][ 8 ][ 14 ]] +[[ string->int ][ !!! *3* !!! ][ 103 ][ 18 ][ 15 ]] +[[ string->short ][ !!! *3* !!! ][ 105 ][ 20 ][ 15 ]] +[[ string->long int ][ !!! *3* !!! ][ 101 ][ 18 ][ 16 ]] +[[ string->long long ][ !!! *3* !!! ][ 101 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 98 ][ 23 ][ 14 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 100 ][ 17 ][ 14 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 100 ][ 21 ][ 15 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 99 ][ 19 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 95 ][ 16 ][ 8 ]] +[[ string->float ][ !!! *13* !!! ][ 160 ][ 61 ][ 33 ]] +[[ string->double ][ !!! *14* !!! ][ 206 ][ 93 ][ 59 ]] +[[ string->long double ][ 128 ][ 217 ][ 96 ][ !!! *61* !!! ]] +[[ char->string ][ !!! *7* !!! ][ 100 ][ 17 ][ 12 ]] +[[ unsigned char->string ][ !!! *7* !!! ][ 109 ][ 17 ][ 16 ]] +[[ signed char->string ][ !!! *7* !!! ][ 99 ][ 17 ][ 12 ]] +[[ int->string ][ !!! *13* !!! ][ 110 ][ 21 ][ 15 ]] +[[ short->string ][ !!! *14* !!! ][ 110 ][ 22 ][ 17 ]] +[[ long int->string ][ !!! *14* !!! ][ 109 ][ 21 ][ 16 ]] +[[ long long->string ][ !!! *13* !!! ][ 114 ][ 20 ][ 17 ]] +[[ unsigned int->string ][ !!! *13* !!! ][ 109 ][ 23 ][ 15 ]] +[[ unsigned short->string ][ !!! *14* !!! ][ 109 ][ 23 ][ 17 ]] +[[ unsigned long int->string ][ !!! *13* !!! ][ 112 ][ 23 ][ 16 ]] +[[ unsigned long long->string ][ !!! *14* !!! ][ 109 ][ 21 ][ 17 ]] +[[ bool->string ][ !!! *7* !!! ][ 108 ][ 23 ][ 11 ]] +[[ float->string ][ 63 ][ 185 ][ 92 ][ !!! *50* !!! ]] +[[ double->string ][ 106 ][ 216 ][ 116 ][ !!! *75* !!! ]] +[[ long double->string ][ 118 ][ 219 ][ 119 ][ !!! *80* !!! ]] +[[ char*->char ][ !!! *1* !!! ][ 93 ][ 9 ][ 9 ]] +[[ char*->signed char ][ !!! *1* !!! ][ 92 ][ 9 ][ 9 ]] +[[ char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 9 ][ 14 ]] +[[ char*->int ][ !!! *4* !!! ][ 107 ][ 19 ][ 15 ]] +[[ char*->short ][ !!! *5* !!! ][ 109 ][ 19 ][ 15 ]] +[[ char*->long int ][ !!! *4* !!! ][ 113 ][ 19 ][ 15 ]] +[[ char*->long long ][ !!! *4* !!! ][ 108 ][ 20 ][ 15 ]] +[[ char*->unsigned int ][ !!! *4* !!! ][ 106 ][ 19 ][ 15 ]] +[[ char*->unsigned short ][ !!! *4* !!! ][ 106 ][ 18 ][ 15 ]] +[[ char*->unsigned long int ][ !!! *4* !!! ][ 103 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *4* !!! ][ 105 ][ 20 ][ 15 ]] +[[ char*->bool ][ !!! *1* !!! ][ 104 ][ 18 ][ 8 ]] +[[ char*->float ][ !!! *15* !!! ][ 164 ][ 62 ][ 33 ]] +[[ char*->double ][ !!! *16* !!! ][ 203 ][ 97 ][ 58 ]] +[[ char*->long double ][ 132 ][ 223 ][ 98 ][ !!! *60* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 8 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 92 ][ 10 ][ 8 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 91 ][ 9 ][ 14 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 106 ][ 20 ][ 15 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 106 ][ 21 ][ 15 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 111 ][ 19 ][ 15 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 107 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 105 ][ 19 ][ 15 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 103 ][ 18 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 106 ][ 22 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 105 ][ 20 ][ 14 ]] +[[ unsigned char*->bool ][ !!! *2* !!! ][ 106 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *15* !!! ][ 167 ][ 68 ][ 33 ]] +[[ unsigned char*->double ][ !!! *17* !!! ][ 203 ][ 99 ][ 58 ]] +[[ unsigned char*->long double ][ 129 ][ 216 ][ 97 ][ !!! *61* !!! ]] +[[ unsigned char*->string ][ !!! *13* !!! ][ 111 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 92 ][ 9 ][ 8 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 91 ][ 9 ][ 8 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 91 ][ 9 ][ 14 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 107 ][ 19 ][ 15 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 109 ][ 24 ][ 14 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 112 ][ 19 ][ 15 ]] +[[ signed char*->long long ][ !!! *5* !!! ][ 107 ][ 20 ][ 15 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 108 ][ 20 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 104 ][ 18 ][ 15 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 22 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 20 ][ 15 ]] +[[ signed char*->bool ][ !!! *2* !!! ][ 104 ][ 18 ][ 8 ]] +[[ signed char*->float ][ !!! *16* !!! ][ 165 ][ 63 ][ 33 ]] +[[ signed char*->double ][ !!! *16* !!! ][ 203 ][ 98 ][ 59 ]] +[[ signed char*->long double ][ 129 ][ 215 ][ 98 ][ !!! *61* !!! ]] +[[ signed char*->string ][ !!! *13* !!! ][ 109 ][ 21 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 109 ][ 21 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 221 ][ 102 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 223 ][ 103 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 115 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 92 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 88 ][ 7 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +] +[endsect] +[section gcc-4.5][table:id Performance Table (gcc-4.5) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *3* !!! ][ 100 ][ 20 ][ 14 ]] +[[ string->short ][ !!! *3* !!! ][ 106 ][ 20 ][ 14 ]] +[[ string->long int ][ !!! *3* !!! ][ 100 ][ 18 ][ 14 ]] +[[ string->long long ][ !!! *9* !!! ][ 100 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 97 ][ 20 ][ 14 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 102 ][ 17 ][ 14 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 97 ][ 21 ][ 14 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 97 ][ 19 ][ 14 ]] +[[ string->bool ][ !!! *<1* !!! ][ 95 ][ 16 ][ 7 ]] +[[ string->float ][ !!! *15* !!! ][ 157 ][ 63 ][ 32 ]] +[[ string->double ][ !!! *17* !!! ][ 203 ][ 95 ][ 59 ]] +[[ string->long double ][ 129 ][ 216 ][ 93 ][ !!! *58* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 100 ][ 17 ][ 10 ]] +[[ unsigned char->string ][ !!! *8* !!! ][ 96 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *8* !!! ][ 96 ][ 18 ][ 10 ]] +[[ int->string ][ !!! *14* !!! ][ 105 ][ 22 ][ 15 ]] +[[ short->string ][ !!! *14* !!! ][ 107 ][ 23 ][ 17 ]] +[[ long int->string ][ !!! *14* !!! ][ 109 ][ 22 ][ 17 ]] +[[ long long->string ][ !!! *14* !!! ][ 105 ][ 22 ][ 18 ]] +[[ unsigned int->string ][ !!! *14* !!! ][ 105 ][ 25 ][ 15 ]] +[[ unsigned short->string ][ !!! *15* !!! ][ 105 ][ 23 ][ 17 ]] +[[ unsigned long int->string ][ !!! *14* !!! ][ 109 ][ 24 ][ 17 ]] +[[ unsigned long long->string ][ !!! *14* !!! ][ 102 ][ 23 ][ 17 ]] +[[ bool->string ][ !!! *8* !!! ][ 104 ][ 23 ][ 12 ]] +[[ float->string ][ 66 ][ 181 ][ 92 ][ !!! *49* !!! ]] +[[ double->string ][ 107 ][ 215 ][ 120 ][ !!! *75* !!! ]] +[[ long double->string ][ 117 ][ 221 ][ 125 ][ !!! *79* !!! ]] +[[ char*->char ][ !!! *1* !!! ][ 89 ][ 9 ][ 7 ]] +[[ char*->signed char ][ !!! *1* !!! ][ 90 ][ 9 ][ 7 ]] +[[ char*->unsigned char ][ !!! *2* !!! ][ 90 ][ 9 ][ 13 ]] +[[ char*->int ][ !!! *7* !!! ][ 103 ][ 20 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 102 ][ 29 ][ 14 ]] +[[ char*->long int ][ !!! *7* !!! ][ 101 ][ 20 ][ 15 ]] +[[ char*->long long ][ !!! *6* !!! ][ 102 ][ 20 ][ 14 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 19 ][ 14 ]] +[[ char*->unsigned short ][ !!! *6* !!! ][ 101 ][ 18 ][ 14 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 22 ][ 14 ]] +[[ char*->unsigned long long ][ !!! *6* !!! ][ 101 ][ 21 ][ 14 ]] +[[ char*->bool ][ !!! *3* !!! ][ 98 ][ 18 ][ 7 ]] +[[ char*->float ][ !!! *18* !!! ][ 162 ][ 63 ][ 31 ]] +[[ char*->double ][ !!! *17* !!! ][ 203 ][ 96 ][ 58 ]] +[[ char*->long double ][ 135 ][ 214 ][ 98 ][ !!! *58* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 87 ][ 9 ][ 7 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 87 ][ 9 ][ 7 ]] +[[ unsigned char*->unsigned char ][ !!! *3* !!! ][ 87 ][ 9 ][ 13 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 105 ][ 20 ][ 14 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 102 ][ 21 ][ 14 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 101 ][ 20 ][ 14 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 102 ][ 20 ][ 14 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 100 ][ 18 ][ 14 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 101 ][ 24 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 100 ][ 20 ][ 14 ]] +[[ unsigned char*->bool ][ !!! *3* !!! ][ 99 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *17* !!! ][ 164 ][ 64 ][ 32 ]] +[[ unsigned char*->double ][ !!! *18* !!! ][ 201 ][ 94 ][ 58 ]] +[[ unsigned char*->long double ][ 133 ][ 217 ][ 95 ][ !!! *60* !!! ]] +[[ unsigned char*->string ][ !!! *14* !!! ][ 103 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *3* !!! ][ 88 ][ 10 ][ 8 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 87 ][ 10 ][ 7 ]] +[[ signed char*->unsigned char ][ !!! *3* !!! ][ 87 ][ 9 ][ 13 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 105 ][ 21 ][ 14 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 104 ][ 20 ][ 15 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 106 ][ 20 ][ 14 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 20 ][ 14 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 100 ][ 18 ][ 14 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 23 ][ 14 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 103 ][ 20 ][ 14 ]] +[[ signed char*->bool ][ !!! *3* !!! ][ 99 ][ 18 ][ 7 ]] +[[ signed char*->float ][ !!! *18* !!! ][ 159 ][ 60 ][ 32 ]] +[[ signed char*->double ][ !!! *18* !!! ][ 203 ][ 95 ][ 57 ]] +[[ signed char*->long double ][ 129 ][ 213 ][ 97 ][ !!! *56* !!! ]] +[[ signed char*->string ][ !!! *14* !!! ][ 105 ][ 22 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 109 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 226 ][ 104 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 229 ][ 103 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 225 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 227 ][ 115 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 84 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +] +[endsect] +[section gcc-4.6][table:id Performance Table (gcc-4.6) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 96 ][ 9 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 96 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *3* !!! ][ 110 ][ 18 ][ 16 ]] +[[ string->short ][ !!! *3* !!! ][ 111 ][ 18 ][ 16 ]] +[[ string->long int ][ !!! *3* !!! ][ 109 ][ 18 ][ 15 ]] +[[ string->long long ][ !!! *3* !!! ][ 111 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 110 ][ 20 ][ 15 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 111 ][ 18 ][ 15 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 109 ][ 18 ][ 15 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 114 ][ 19 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 106 ][ 17 ][ 8 ]] +[[ string->float ][ !!! *13* !!! ][ 175 ][ 70 ][ 33 ]] +[[ string->double ][ !!! *14* !!! ][ 182 ][ 81 ][ 58 ]] +[[ string->long double ][ 118 ][ 190 ][ 87 ][ !!! *58* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 118 ][ 21 ][ 12 ]] +[[ unsigned char->string ][ !!! *8* !!! ][ 109 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *8* !!! ][ 108 ][ 18 ][ 12 ]] +[[ int->string ][ 20 ][ 121 ][ 21 ][ !!! *16* !!! ]] +[[ short->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 17 ]] +[[ long int->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 16 ]] +[[ long long->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 17 ]] +[[ unsigned int->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 16 ]] +[[ unsigned short->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 18 ]] +[[ unsigned long int->string ][ 16 ][ 118 ][ 22 ][ !!! *15* !!! ]] +[[ unsigned long long->string ][ !!! *15* !!! ][ 117 ][ 21 ][ 17 ]] +[[ bool->string ][ !!! *8* !!! ][ 117 ][ 23 ][ 10 ]] +[[ float->string ][ 77 ][ 218 ][ 105 ][ !!! *50* !!! ]] +[[ double->string ][ 108 ][ 247 ][ 129 ][ !!! *73* !!! ]] +[[ long double->string ][ 120 ][ 250 ][ 131 ][ !!! *79* !!! ]] +[[ char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 7 ]] +[[ char*->signed char ][ !!! *2* !!! ][ 98 ][ 9 ][ 8 ]] +[[ char*->unsigned char ][ !!! *2* !!! ][ 98 ][ 9 ][ 13 ]] +[[ char*->int ][ !!! *6* !!! ][ 115 ][ 22 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 114 ][ 22 ][ 15 ]] +[[ char*->long int ][ !!! *6* !!! ][ 114 ][ 22 ][ 16 ]] +[[ char*->long long ][ !!! *6* !!! ][ 119 ][ 22 ][ 15 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 20 ][ 15 ]] +[[ char*->unsigned short ][ !!! *6* !!! ][ 116 ][ 20 ][ 15 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *6* !!! ][ 118 ][ 22 ][ 15 ]] +[[ char*->bool ][ !!! *3* !!! ][ 113 ][ 18 ][ 8 ]] +[[ char*->float ][ !!! *15* !!! ][ 180 ][ 78 ][ 32 ]] +[[ char*->double ][ !!! *16* !!! ][ 185 ][ 89 ][ 58 ]] +[[ char*->long double ][ 119 ][ 193 ][ 91 ][ !!! *60* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 8 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 99 ][ 10 ][ 8 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 100 ][ 9 ][ 15 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 118 ][ 22 ][ 15 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 117 ][ 26 ][ 15 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 119 ][ 21 ][ 15 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 118 ][ 21 ][ 14 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 115 ][ 22 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 117 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 115 ][ 21 ][ 15 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ unsigned char*->bool ][ !!! *3* !!! ][ 112 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *15* !!! ][ 181 ][ 78 ][ 33 ]] +[[ unsigned char*->double ][ !!! *16* !!! ][ 185 ][ 92 ][ 59 ]] +[[ unsigned char*->long double ][ 120 ][ 190 ][ 89 ][ !!! *58* !!! ]] +[[ unsigned char*->string ][ !!! *14* !!! ][ 121 ][ 22 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 9 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 98 ][ 9 ][ 8 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 98 ][ 9 ][ 14 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 119 ][ 22 ][ 16 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 115 ][ 22 ][ 15 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 119 ][ 22 ][ 15 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 117 ][ 23 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 117 ][ 21 ][ 14 ]] +[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 119 ][ 24 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 116 ][ 22 ][ 15 ]] +[[ signed char*->bool ][ !!! *3* !!! ][ 111 ][ 18 ][ 8 ]] +[[ signed char*->float ][ !!! *16* !!! ][ 180 ][ 78 ][ 33 ]] +[[ signed char*->double ][ !!! *16* !!! ][ 185 ][ 89 ][ 59 ]] +[[ signed char*->long double ][ 120 ][ 191 ][ 91 ][ !!! *59* !!! ]] +[[ signed char*->string ][ !!! *14* !!! ][ 122 ][ 23 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 120 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 242 ][ 115 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 243 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 265 ][ 141 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 266 ][ 140 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 95 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 95 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ --- ]] +] +[endsect] + +[/ END of section, generated by performance measuring program ] +[endsect] + diff --git a/index.html b/index.html index cf8527f..133680c 100644 --- a/index.html +++ b/index.html @@ -24,7 +24,7 @@ supplied by several headers:

and polymorphic_downcast<> to perform safe casting between polymorphic types.
-
  • The boost/lexical_cast header provides lexical_cast<> +
  • The boost/lexical_cast header provides lexical_cast<> general literal text conversions, such as an int represented as a string, or vice-versa.
  • diff --git a/lexical_cast.htm b/lexical_cast.htm index 4bbdc8e..73b6ba5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -1,281 +1,16 @@ - - + + + - - lexical_cast - - - - -

    boost.png (6897 bytes)Header - boost/lexical_cast.hpp

    - -
    -

    Motivation

    - Sometimes a value must be converted to a literal text form, such as an int - represented as a string, or vice-versa, when a string - is interpreted as an int. Such examples are common when converting - between data types internal to a program and representation external to a - program, such as windows and configuration files. -

    - The standard C and C++ libraries offer a number of facilities for performing - such conversions. However, they vary with their ease of use, extensibility, and - safety. -

    - For instance, there are a number of limitations with the family of standard C - functions typified by atoi: -

      -
    • - Conversion is supported in one direction only: from text to internal data type. - Converting the other way using the C library requires either the inconvenience - and compromised safety of the sprintf function, or the loss of - portability associated with non-standard functions such as itoa. -
    • -
    • - The range of types supported is only a subset of the built-in numeric types, - namely int, long, and double. -
    • -
    • - The range of types cannot be extended in a uniform manner. For instance, - conversion from string representation to complex or rational. -
    • -
    - The standard C functions typified by strtol have the same basic - limitations, but offer finer control over the conversion process. However, for - the common case such control is often either not required or not used. The scanf - family of functions offer even greater control, but also lack safety and ease - of use. -

    - The standard C++ library offers stringstream for the kind of - in-core formatting being discussed. It offers a great deal of control over the - formatting and conversion of I/O to and from arbitrary types through text. - However, for simple conversions direct use of stringstream can be - either clumsy (with the introduction of extra local variables and the loss of - infix-expression convenience) or obscure (where stringstream - objects are created as temporary objects in an expression). Facets provide a - comprehensive concept and facility for controlling textual representation, but - their perceived complexity and high entry level requires an extreme degree of - involvement for simple conversions, and excludes all but a few programmers. -

    - The lexical_cast function template offers a convenient and - consistent form for supporting common conversions to and from arbitrary types - when they are represented as text. The simplification it offers is in - expression-level convenience for such conversions. For more involved - conversions, such as where precision or formatting need tighter control than is - offered by the default behavior of lexical_cast, the conventional - stringstream approach is recommended. Where the conversions are - numeric to numeric, numeric_cast - may offer more reasonable behavior than lexical_cast. -

    - For a good discussion of the options and issues involved in string-based - formatting, including comparison of stringstream, lexical_cast, - and others, see Herb Sutter's article, - The String Formatters of Manor Farm. -

    -


    -

    Examples

    - The following example treats command line arguments as a sequence of numeric - data:
    -
    int main(int argc, char * argv[])
    -{
    -    using boost::lexical_cast;
    -    using boost::bad_lexical_cast;
    -
    -    std::vector<short> args;
    -
    -    while(*++argv)
    -    {
    -        try
    -        {
    -            args.push_back(lexical_cast<short>(*argv));
    -        }
    -        catch(bad_lexical_cast &)
    -        {
    -            args.push_back(0);
    -        }
    -    }
    -    ...
    -}
    -
    -
    The following example uses numeric data in a string expression:
    -
    void log_message(const std::string &);
    -
    -void log_errno(int yoko)
    -{
    -    log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
    -}
    -
    -
    -
    -

    Synopsis

    - Library features defined in "boost/lexical_cast.hpp": -
    -
    namespace boost
    -{
    -    class bad_lexical_cast;
    -    template<typename Target, typename Source>
    -      Target lexical_cast(const Source& arg);
    -}
    -
    -
    Unit test defined in "lexical_cast_test.cpp". -

    -


    -

    lexical_cast

    -
    -
    template<typename Target, typename Source>
    -  Target lexical_cast(const Source& arg);
    -
    -
    Returns the result of streaming arg into a - standard library string-based stream and then out as a Target object. - Where Target is either std::string - or std::wstring, stream extraction takes the whole content - of the string, including spaces, rather than relying on the default - operator>> behavior. - If the conversion is unsuccessful, a - bad_lexical_cast exception is thrown. -

    - The requirements on the argument and result types are: -

      -
    • - Source is OutputStreamable, meaning that an operator<< - is defined that takes a std::ostream or std::wostream object on the - left hand side and an instance of the argument type on the right. -
    • -
    • - Target is InputStreamable, meaning that an operator>> - is defined that takes a std::istream or std::wistream object on the left hand side - and an instance of the result type on the right. -
    • -
    • - Target is CopyConstructible [20.1.3]. -
    • -
    • - Target is DefaultConstructible, meaning that it is possible - to default-initialize an object of that type [8.5, 20.1.4]. -
    • -
    - The character type of the underlying stream is assumed to be char unless - either the Source or the Target requires wide-character - streaming, in which case the underlying stream uses wchar_t. - Source types that require wide-character streaming are wchar_t, - wchar_t *, and std::wstring. Target types that - require wide-character streaming are wchar_t and std::wstring. -

    - Where a higher degree of control is required over conversions, std::stringstream - and std::wstringstream offer a more appropriate path. Where non-stream-based conversions are - required, lexical_cast - is the wrong tool for the job and is not special-cased for such scenarios. -

    -


    -

    bad_lexical_cast

    -
    -
    class bad_lexical_cast : public std::bad_cast
    -{
    -public:
    -    ... // same member function interface as std::exception
    -};
    -
    -
    Exception used to indicate runtime lexical_cast - failure. - -
    -

    BOOST_LEXICAL_CAST_ASSUME_C_LOCALE

    -
    #define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
    -
    -or,
    -
    -g++ -DBOOST_LEXICAL_CAST_ASSUME_C_LOCALE ...  (gcc on Linux/Unix)
    -cl.exe /DBOOST_LEXICAL_CAST_ASSUME_C_LOCALE ... (Visual C++ on Windows)
    -
    -Eliminate an overhead of std::locale if your program runs in the "C" locale. If the option is set but a program runs in other locale, lexical_cast result is unspecified. -
    - -

    Frequently Asked Questions

    -

    Q: Why does lexical_cast<int8_t>("127") throw bad_lexical_cast? -
    A: The type int8_t is a typedef to char or signed char. - Lexical conversion to these types is simply reading a byte from source but since the source has - more than one byte, the exception is thrown. -

    Please use other integer types such as int or short int. If bounds checking - is important, you can also call numeric_cast: - -

    numeric_cast<int8_t>(lexical_cast<int>("127"));
    - -

    Q: What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect? -
    A: As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: - -

    lexical_cast<std::string>(static_cast<int>(n));
    - -

    Q: The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag? -
    A: May be in a future version. There is no requirement in [N1973] to reset the flag but remember that [N1973] is not yet accepted by the committee. By the way, it's a great opportunity to make your operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver. - -

    References

    -
      -
    • [N1973] Kevlin Henney, Beman Dawes, Lexical Conversion Library Proposal for TR2, - N1973. -
    • [Tuning] Alexander Nasonov, Fine Tuning for lexical_cast, - Overload #74 (PDF), - August 2006.
    • -
    -

    Changes

    -

    August, October 2006:

    -
      -
    • Better performance for many combinations of Source and Target - types. Refer to [Tuning] for more details. -
    • -
    -

    June 2005:

    -
      -
    • Call-by-const reference for the parameters. This requires partial specialization - of class templates, so it doesn't work for MSVC 6, and it uses the original - pass by value there.
      -
    • -
    • The MSVC 6 support is deprecated, and will be removed in a future Boost - version.
    • -
    -

    Earlier:

    - -
      -
    • The previous version of lexical_cast used the default stream - precision for reading and writing floating-point numbers. For numerics that - have a corresponding specialization of std::numeric_limits, the - current version now chooses a precision to match.
      -
    • The previous version of lexical_cast did not support conversion - to or from any wide-character-based types. For compilers with full language - and library support for wide characters, lexical_cast now supports - conversions from wchar_t, wchar_t *, and std::wstring - and to wchar_t and std::wstring.
      -
    • The previous version of lexical_cast assumed that the conventional - stream extractor operators were sufficient for reading values. However, string - I/O is asymmetric, with the result that spaces play the role of I/O separators - rather than string content. The current version fixes this error for std::string - and, where supported, std::wstring: lexical_cast<std::string>("Hello, - World") succeeds instead of failing with a bad_lexical_cast - exception.
      -
    • The previous version of lexical_cast allowed unsafe and meaningless - conversions to pointers. The current version now throws a bad_lexical_cast - for conversions to pointers: lexical_cast<char *>("Goodbye, World") - now throws an exception instead of causing undefined behavior. -
    -

    -


    - -
    © Copyright Kevlin Henney, 2000–2005
    - + + + + +Automatic redirection failed, please go to +../../doc/html/boost_lexical_cast.html + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index a994d13..faeaa93 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -2,8 +2,9 @@ // // See http://www.boost.org for most recent version, including documentation. // -// Copyright Terje Slettebø and Kevlin Henney, 2005. +// Copyright Terje Sletteb and Kevlin Henney, 2005. // Copyright Alexander Nasonov, 2006. +// Copyright Antony Polukhin, 2011. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -32,7 +33,9 @@ #include #include +#include #include +#include #include #if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ @@ -40,6 +43,10 @@ #define LCAST_TEST_LONGLONG #endif +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + template struct my_traits : std::char_traits { @@ -63,6 +70,7 @@ void test_conversion_to_char(); void test_conversion_to_int(); void test_conversion_to_double(); void test_conversion_to_bool(); +void test_conversion_with_nonconst_char(); void test_conversion_to_string(); void test_conversion_from_to_wchar_t_alias(); void test_conversion_to_pointer(); @@ -90,10 +98,19 @@ void test_wtraits(); void test_allocator(); void test_wallocator(); #endif +void test_char_types_conversions(); +void operators_overload_test(); +#ifndef BOOST_NO_CHAR16_T +void test_char16_conversions(); +#endif +#ifndef BOOST_NO_CHAR32_T +void test_char32_conversions(); +#endif + unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(test_conversion_to_char)); suite->add(BOOST_TEST_CASE(test_conversion_to_int)); @@ -102,6 +119,7 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(test_conversion_from_to_wchar_t_alias)); suite->add(BOOST_TEST_CASE(test_conversion_to_pointer)); suite->add(BOOST_TEST_CASE(test_conversion_to_string)); + suite->add(BOOST_TEST_CASE(test_conversion_with_nonconst_char)); #ifndef BOOST_LCAST_NO_WCHAR_T suite->add(BOOST_TEST_CASE(test_conversion_from_wchar_t)); suite->add(BOOST_TEST_CASE(test_conversion_to_wchar_t)); @@ -129,6 +147,15 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_wallocator)); #endif + suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + suite->add(BOOST_TEST_CASE(&operators_overload_test)); +#ifndef BOOST_NO_CHAR16_T + suite->add(BOOST_TEST_CASE(&test_char16_conversions)); +#endif +#ifndef BOOST_NO_CHAR32_T + suite->add(BOOST_TEST_CASE(&test_char32_conversions)); +#endif + return suite; } @@ -190,19 +217,45 @@ void test_conversion_to_int() lexical_cast(std::string("Test")), bad_lexical_cast); } +void test_conversion_with_nonconst_char() +{ + std::vector buffer; + buffer.push_back('1'); + buffer.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer[0]), 1); + + std::vector buffer2; + buffer2.push_back('1'); + buffer2.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer2[0]), 1); + + std::vector buffer3; + buffer3.push_back('1'); + buffer3.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer3[0]), 1); + +#ifndef BOOST_LCAST_NO_WCHAR_T + std::vector buffer4; + buffer4.push_back(L'1'); + buffer4.push_back(L'\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer4[0]), 1); +#endif +} + void test_conversion_to_double() { - BOOST_CHECK_CLOSE(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast('A'), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.234567890, 1.234567890, std::numeric_limits::epsilon()); - BOOST_CHECK_CLOSE(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast(1.234567890), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast("1.234567890"), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW( lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( @@ -229,10 +282,24 @@ void test_conversion_to_bool() BOOST_CHECK_EQUAL(false, lexical_cast("0")); BOOST_CHECK_EQUAL(true, lexical_cast(std::string("1"))); BOOST_CHECK_EQUAL(false, lexical_cast(std::string("0"))); + + BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(2), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(2u), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(-1), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(-2), bad_lexical_cast); + + BOOST_CHECK_THROW( lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( lexical_cast(std::string("Test")), bad_lexical_cast); + + BOOST_CHECK(lexical_cast("+1") == true ); + BOOST_CHECK(lexical_cast("+0") == false ); + BOOST_CHECK(lexical_cast("-0") == false ); + BOOST_CHECK_THROW(lexical_cast("--0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+-0"), bad_lexical_cast); } void test_conversion_to_string() @@ -447,6 +514,24 @@ void test_conversion_from_integral_to_char(CharT zero) BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); } +template +void test_conversion_from_char_to_integral(CharT zero) +{ + BOOST_CHECK(lexical_cast( static_cast(zero + 0)) == static_cast(0) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 1)) == static_cast(1) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 2)) == static_cast(2) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 3)) == static_cast(3) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 4)) == static_cast(4) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 5)) == static_cast(5) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 6)) == static_cast(6) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 7)) == static_cast(7) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 8)) == static_cast(8) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 9)) == static_cast(9) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + template void test_conversion_from_integral_to_integral() { @@ -510,7 +595,7 @@ void test_conversion_from_integral_to_string(CharT) // Test values around zero: if(limits::is_signed) - for(t = -counter; t < static_cast(counter); ++t) + for(t = static_cast(-counter); t < static_cast(counter); ++t) BOOST_CHECK(lexical_cast(t) == to_str(t)); // Test values around 100, 1000, 10000, ... @@ -540,25 +625,46 @@ void test_conversion_from_string_to_integral(CharT) BOOST_CHECK_EQUAL(lexical_cast(s), min_val); if(limits::is_signed) { -#if defined(BOOST_MSVC) && BOOST_MSVC == 1400 - // VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp - if(sizeof(T) < sizeof(boost::intmax_t)) -#endif - { - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); - } + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); } s = to_str(max_val); BOOST_CHECK_EQUAL(lexical_cast(s), max_val); -#if defined(BOOST_MSVC) && BOOST_MSVC == 1400 - // VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp - if(sizeof(T) != sizeof(boost::intmax_t)) -#endif { BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); + + s = to_str(max_val); + for (int i =1; i <=10; ++i) { + s[s.size()-1] += 1; + BOOST_CHECK_THROW(lexical_cast( s ), bad_lexical_cast); + } + + s = to_str(max_val); + std::locale loc; + typedef std::numpunct numpunct; + if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) { + // Following tests work well for locale C + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+to_str(0)+s), max_val); + } + + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + + typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion::type promoted; + if ( !(boost::is_same::value) ) + { + promoted prom = max_val; + s = to_str(max_val); + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(prom+i) ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + } } if(limits::digits <= 16 && lcast_test_small_integral_types_completely) @@ -586,7 +692,7 @@ void test_conversion_from_string_to_integral(CharT) // Test values around zero: if(limits::is_signed) - for(t = -counter; t < static_cast(counter); ++t) + for(t = static_cast(-counter); t < static_cast(counter); ++t) BOOST_CHECK(lexical_cast(to_str(t)) == t); // Test values around 100, 1000, 10000, ... @@ -603,6 +709,21 @@ void test_conversion_from_string_to_integral(CharT) template void test_conversion_from_to_integral_for_locale() { + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); + } + test_conversion_from_integral_to_integral(); test_conversion_from_integral_to_string('0'); test_conversion_from_string_to_integral('0'); @@ -625,13 +746,54 @@ void test_conversion_from_to_integral() signed char const szero = '0'; unsigned char const uzero = '0'; test_conversion_from_integral_to_char(zero); + test_conversion_from_char_to_integral(zero); test_conversion_from_integral_to_char(szero); + test_conversion_from_char_to_integral(szero); test_conversion_from_integral_to_char(uzero); + test_conversion_from_char_to_integral(uzero); #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) wchar_t const wzero = L'0'; test_conversion_from_integral_to_char(wzero); + test_conversion_from_char_to_integral(wzero); +#endif +#ifndef BOOST_NO_CHAR16_T + char16_t const u16zero = u'0'; + test_conversion_from_integral_to_char(u16zero); + test_conversion_from_char_to_integral(u16zero); +#endif +#ifndef BOOST_NO_CHAR32_T + char32_t const u32zero = u'0'; + test_conversion_from_integral_to_char(u32zero); + test_conversion_from_char_to_integral(u32zero); #endif + BOOST_CHECK(lexical_cast("-1") == static_cast(-1)); + BOOST_CHECK(lexical_cast("-9") == static_cast(-9)); + BOOST_CHECK(lexical_cast(-1) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9) == static_cast(-9)); + + BOOST_CHECK_THROW(lexical_cast("-1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-9.0"), bad_lexical_cast); + BOOST_CHECK(lexical_cast(-1.0) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9.0) == static_cast(-9)); + + BOOST_CHECK(lexical_cast(static_cast(1)) == static_cast(1)); + BOOST_CHECK(lexical_cast(static_cast(9)) == static_cast(9)); + BOOST_CHECK_THROW(lexical_cast(1.1f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1L), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + + BOOST_CHECK(lexical_cast("+1") == static_cast(1) ); + BOOST_CHECK(lexical_cast("+9") == static_cast(9) ); + BOOST_CHECK(lexical_cast("+10") == static_cast(10) ); + BOOST_CHECK(lexical_cast("+90") == static_cast(90) ); + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); // test_conversion_from_to_integral_for_locale typedef std::numpunct numpunct; @@ -717,7 +879,7 @@ void test_conversion_from_to_ulonglong() test_conversion_from_to_integral(); } -#elif defined(LCAST_TEST_LONGLONG) +#elif defined(BOOST_HAS_MS_INT64) void test_conversion_from_to_longlong() { @@ -788,3 +950,83 @@ void test_wallocator() #endif +void test_char_types_conversions() +{ + const char c_arr[] = "Test array of chars"; + const unsigned char uc_arr[] = "Test array of chars"; + const signed char sc_arr[] = "Test array of chars"; + + BOOST_CHECK(boost::lexical_cast(c_arr) == std::string(c_arr)); + BOOST_CHECK(boost::lexical_cast(uc_arr) == std::string(c_arr)); + BOOST_CHECK(boost::lexical_cast(sc_arr) == std::string(c_arr)); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == c_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == c_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == c_arr[0]); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == uc_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == uc_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == uc_arr[0]); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == sc_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == sc_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == sc_arr[0]); + +#ifndef BOOST_LCAST_NO_WCHAR_T + const wchar_t wc_arr[]=L"Test array of chars"; + + BOOST_CHECK(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); + BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); + +#endif +} + + + +struct foo_operators_test +{ + foo_operators_test() : f(2) {} + int f; +}; + +template +OStream& operator<<(OStream& ostr, const foo_operators_test& foo) +{ + ostr << foo.f; + return ostr; +} + +template +IStream& operator>>(IStream& istr, foo_operators_test& foo) +{ + istr >> foo.f; + return istr; +} + +void operators_overload_test() +{ + foo_operators_test foo; + BOOST_CHECK_EQUAL(boost::lexical_cast(foo), "2"); + BOOST_CHECK_EQUAL((boost::lexical_cast("2")).f, 2); + + // Must compile + (void)boost::lexical_cast(foo); +} + + +#ifndef BOOST_NO_CHAR16_T +void test_char16_conversions() +{ + BOOST_CHECK(u"100" == lexical_cast(u"100")); + BOOST_CHECK(u"1" == lexical_cast(u'1')); +} +#endif + +#ifndef BOOST_NO_CHAR32_T +void test_char32_conversions() +{ + BOOST_CHECK(U"100" == lexical_cast(U"100")); + BOOST_CHECK(U"1" == lexical_cast(U'1')); +} +#endif + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1fea2fb..7e5eacf 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,10 @@ test-suite conversion [ run lexical_cast_abstract_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_noncopyable_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_containers_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_abstract_test.cpp b/test/lexical_cast_abstract_test.cpp index 4b92e49..70cdeca 100644 --- a/test/lexical_cast_abstract_test.cpp +++ b/test/lexical_cast_abstract_test.cpp @@ -28,7 +28,7 @@ void test_abstract(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_abstract)); diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp new file mode 100644 index 0000000..5f98ac8 --- /dev/null +++ b/test/lexical_cast_containers_test.cpp @@ -0,0 +1,38 @@ +// Testing boost::lexical_cast with boost::container::string. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include +#include +#include + +void testing_boost_containers_basic_string(); + +using namespace boost; + +boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("Testing boost::lexical_cast with boost::container::string"); + suite->add(BOOST_TEST_CASE(testing_boost_containers_basic_string)); + + return suite; +} + +void testing_boost_containers_basic_string() +{ + BOOST_CHECK("100" == lexical_cast("100")); + BOOST_CHECK(L"100" == lexical_cast(L"100")); + + BOOST_CHECK("100" == lexical_cast(100)); + boost::container::string str("1000"); + BOOST_CHECK(1000 == lexical_cast(str)); +} + + diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp new file mode 100755 index 0000000..808f456 --- /dev/null +++ b/test/lexical_cast_float_types_test.cpp @@ -0,0 +1,513 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +void test_conversion_from_to_float(); +void test_conversion_from_to_double(); +void test_conversion_from_to_long_double(); + +using namespace boost; + + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast float types unit test"); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long_double)); + + return suite; +} + + +// Replace "-,999" with "-999". +template +std::basic_string to_str_gcc_workaround(std::basic_string str) +{ + std::locale loc; + std::numpunct const& np = BOOST_USE_FACET(std::numpunct, loc); + std::ctype const& ct = BOOST_USE_FACET(std::ctype, loc); + + if(np.grouping().empty()) + return str; + + CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; + + if(str.find(prefix) != 0) + return str; + + prefix[1] = CharT(); + str.replace(0, 2, prefix); + return str; +} + +template +std::basic_string to_str(T t) +{ + std::basic_ostringstream o; + o << t; + return to_str_gcc_workaround(o.str()); +} + + +template +void test_conversion_from_to_float_for_locale() +{ + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + np.decimal_point() + "e10" ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1e10") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + "e10" ), bad_lexical_cast); + + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100) ), 100, (std::numeric_limits::epsilon()) ); +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100) ), 100, (std::numeric_limits::epsilon()) ); +#endif + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK_CLOSE_FRACTION( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::epsilon()) ); + } +} + + + + +/* + * Converts char* [and wchar_t] to float number type and checks, that generated + * number is in interval [base_value-epsilon, base_value+epsilon]. + */ +#ifndef BOOST_LCAST_NO_WCHAR_T +#define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \ + converted_val = lexical_cast(#VAL); \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() \ + ); \ + BOOST_CHECK_EQUAL(converted_val, lexical_cast(L## #VAL) ); + +#else +#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \ + converted_val = lexical_cast(#VAL); \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() \ + ); +#endif + +template +void test_converion_to_float_types() +{ + typedef TestType test_t; + test_t converted_val; + + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast('0')); + + unsigned char const uc_one = '1'; + unsigned char const uc_zero ='0'; + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(uc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(uc_zero)); + + signed char const sc_one = '1'; + signed char const sc_zero ='0'; + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(sc_zero)); + + BOOST_CHECK_CLOSE_FRACTION(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()) ); + +// VC failes the next test +// BOOST_CHECK_CLOSE_FRACTION(1e-35L, lexical_cast("0.00000000000000000000000000000000001"), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION( + 0.1111111111111111111111111111111111111111111111111111111111111111111111111L + , lexical_cast("0.1111111111111111111111111111111111111111111111111111111111111111111111111") + , (std::numeric_limits::epsilon()) ); + + CHECK_CLOSE_ABS_DIFF(1,test_t); + BOOST_CHECK_EQUAL(0,lexical_cast("0")); + CHECK_CLOSE_ABS_DIFF(-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0, test_t); + CHECK_CLOSE_ABS_DIFF(0.0, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0,test_t); + + CHECK_CLOSE_ABS_DIFF(1e1, test_t); + CHECK_CLOSE_ABS_DIFF(0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-1e1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0e1,test_t); + + CHECK_CLOSE_ABS_DIFF(1e-1, test_t); + CHECK_CLOSE_ABS_DIFF(0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1E1, test_t); + CHECK_CLOSE_ABS_DIFF(0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-1E1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0E1,test_t); + + CHECK_CLOSE_ABS_DIFF(1E-1, test_t); + CHECK_CLOSE_ABS_DIFF(0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1E-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0E-1, test_t); + + CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-.0E-1, test_t); + + CHECK_CLOSE_ABS_DIFF(10.0, test_t); + CHECK_CLOSE_ABS_DIFF(00.0, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0,test_t); + + CHECK_CLOSE_ABS_DIFF(10e1, test_t); + CHECK_CLOSE_ABS_DIFF(00e1, test_t); + CHECK_CLOSE_ABS_DIFF(-10e1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0e1,test_t); + + CHECK_CLOSE_ABS_DIFF(10e-1, test_t); + CHECK_CLOSE_ABS_DIFF(00e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10E1, test_t); + CHECK_CLOSE_ABS_DIFF(00E1, test_t); + CHECK_CLOSE_ABS_DIFF(-10E1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0E1,test_t); + + CHECK_CLOSE_ABS_DIFF(10E-1, test_t); + CHECK_CLOSE_ABS_DIFF(00E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10E-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0E-1, test_t); + + CHECK_CLOSE_ABS_DIFF(-10101.0E-011, test_t); + CHECK_CLOSE_ABS_DIFF(-10101093, test_t); + CHECK_CLOSE_ABS_DIFF(10101093, test_t); + + CHECK_CLOSE_ABS_DIFF(-.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34e10, test_t); + + BOOST_CHECK_THROW(lexical_cast("-1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-1.E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.E"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("1.0e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111ee"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111e-"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("-B"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0xB"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0x0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1e1e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-1e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(" 1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0 "), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('\0'), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('-'), bad_lexical_cast); +} + +template +void test_float_typess_for_overflows() +{ + typedef T test_t; + test_t minvalue = (std::numeric_limits::min)(); + std::string s_min_value = lexical_cast(minvalue); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(minvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(s_min_value), (std::numeric_limits::epsilon())); + + test_t maxvalue = (std::numeric_limits::max)(); + std::string s_max_value = lexical_cast(maxvalue); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(maxvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(s_max_value), (std::numeric_limits::epsilon())); + + BOOST_CHECK_THROW(lexical_cast(s_max_value+"1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s_max_value+"9"), bad_lexical_cast); + + // VC9 can fail the fllowing tests on floats and doubles when using stingstream... + BOOST_CHECK_THROW(lexical_cast("1"+s_max_value), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("9"+s_max_value), bad_lexical_cast); + + if ( is_same::value ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } + + if ( sizeof(test_t) < sizeof(long double) ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } +} + +#undef CHECK_CLOSE_ABS_DIFF + +#define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \ + test_value = VAL + std::numeric_limits::epsilon() * i ; \ + converted_val = lexical_cast( lexical_cast(test_value) ); \ + BOOST_CHECK_CLOSE_FRACTION( \ + test_value, \ + converted_val, \ + std::numeric_limits::epsilon() \ + ); + +/* + * For interval [ from_mult*epsilon+VAL, to_mult*epsilon+VAL ], converts float type + * numbers to string[wstring] and then back to float type, then compares initial + * values and generated. + * Step is epsilon + */ +#ifndef BOOST_LCAST_NO_WCHAR_T +# define TEST_TO_FROM_CAST_AROUND(VAL) \ + for(i=from_mult; i<=to_mult; ++i) { \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::wstring) \ + } +#else +# define TEST_TO_FROM_CAST_AROUND(VAL) \ + for(i=from_mult; i<=to_mult; ++i) { \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ + } +#endif + +template +void test_converion_from_to_float_types() +{ + typedef TestType test_t; + test_t test_value; + test_t converted_val; + + int i; + int from_mult = -50; + int to_mult = 50; + + TEST_TO_FROM_CAST_AROUND( 0.0 ); + + long double val1; + for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 ) + TEST_TO_FROM_CAST_AROUND( val1 ); + + long double val2; + for(val2 = -1.0e-10L; val2 > -1e11; val2*=10 ) + TEST_TO_FROM_CAST_AROUND( val2 ); + + from_mult = -100; + to_mult = 0; + TEST_TO_FROM_CAST_AROUND( (std::numeric_limits::max)() ); + + from_mult = 0; + to_mult = 100; + TEST_TO_FROM_CAST_AROUND( (std::numeric_limits::min)() ); +} + +#undef TEST_TO_FROM_CAST_AROUND +#undef TEST_TO_FROM_CAST_AROUND_TYPED + + +template +void test_conversion_from_float_to_char(CharT zero) +{ + BOOST_CHECK(lexical_cast(static_cast(0)) == zero + 0); + BOOST_CHECK(lexical_cast(static_cast(1)) == zero + 1); + BOOST_CHECK(lexical_cast(static_cast(2)) == zero + 2); + BOOST_CHECK(lexical_cast(static_cast(3)) == zero + 3); + BOOST_CHECK(lexical_cast(static_cast(4)) == zero + 4); + BOOST_CHECK(lexical_cast(static_cast(5)) == zero + 5); + BOOST_CHECK(lexical_cast(static_cast(6)) == zero + 6); + BOOST_CHECK(lexical_cast(static_cast(7)) == zero + 7); + BOOST_CHECK(lexical_cast(static_cast(8)) == zero + 8); + BOOST_CHECK(lexical_cast(static_cast(9)) == zero + 9); + + BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); + + T t = (std::numeric_limits::max)(); + BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); +} + +template +void test_conversion_from_char_to_float(CharT zero) +{ + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 0)), static_cast(0), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 1)), static_cast(1), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 2)), static_cast(2), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 3)), static_cast(3), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 4)), static_cast(4), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 5)), static_cast(5), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 6)), static_cast(6), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 7)), static_cast(7), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 8)), static_cast(8), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 9)), static_cast(9), (std::numeric_limits::epsilon()) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + +struct restore_oldloc +{ + std::locale oldloc; + ~restore_oldloc() { std::locale::global(oldloc); } +}; + +template +void test_conversion_from_to_float() +{ char const zero = '0'; + signed char const szero = '0'; + unsigned char const uzero = '0'; + test_conversion_from_float_to_char(zero); + test_conversion_from_char_to_float(zero); + test_conversion_from_float_to_char(szero); + test_conversion_from_char_to_float(szero); + test_conversion_from_float_to_char(uzero); + test_conversion_from_char_to_float(uzero); + #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + wchar_t const wzero = L'0'; + test_conversion_from_float_to_char(wzero); + test_conversion_from_char_to_float(wzero); + #endif + + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+1"), 1, std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+9"), 9, std::numeric_limits::epsilon()); + + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); + + test_converion_to_float_types(); + test_float_typess_for_overflows(); + test_converion_from_to_float_types(); + + + typedef std::numpunct numpunct; + + restore_oldloc guard; + std::locale const& oldloc = guard.oldloc; + + std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); + std::string grouping2(grouping1); + + test_conversion_from_to_float_for_locale(); + + try + { + std::locale newloc(""); + std::locale::global(newloc); + + grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); + } + catch(std::exception const& ex) + { + std::string msg("Failed to set system locale: "); + msg += ex.what(); + BOOST_TEST_MESSAGE(msg); + } + + if(grouping1 != grouping2) + test_conversion_from_to_float_for_locale(); + + if(grouping1.empty() && grouping2.empty()) + BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); +} + + +void test_conversion_from_to_float() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_double() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_long_double() +{ + test_conversion_from_to_float(); +} + + + + + + + diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp new file mode 100755 index 0000000..bb4331a --- /dev/null +++ b/test/lexical_cast_inf_nan_test.cpp @@ -0,0 +1,180 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + + +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +using namespace boost; + +template +bool is_pos_inf(T value) +{ + return (boost::math::isinf)(value) && !(boost::math::signbit)(value); +} + +template +bool is_neg_inf(T value) +{ + return (boost::math::isinf)(value) && (boost::math::signbit)(value); +} + +template +bool is_pos_nan(T value) +{ + return (boost::math::isnan)(value) && !(boost::math::signbit)(value); +} + +template +bool is_neg_nan(T value) +{ + /* There is some strange behaviour on Itanium platform with -nan nuber for long double. + * It is a IA64 feature, or it is a boost::math feature, not a lexical_cast bug */ +#if defined(__ia64__) || defined(_M_IA64) + return (boost::math::isnan)(value) + && ( boost::is_same::value || (boost::math::signbit)(value) ); +#else + return (boost::math::isnan)(value) && (boost::math::signbit)(value); +#endif +} + +template +void test_inf_nan_templated() +{ + typedef T test_t; + + BOOST_CHECK( is_pos_inf( lexical_cast("inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast("-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast("-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("+NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN(some string)") ) ); + BOOST_CHECK_THROW( lexical_cast("NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == "-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == "inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == "nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == "-nan" ); +#endif + +#ifndef BOOST_LCAST_NO_WCHAR_T + BOOST_CHECK( is_pos_inf( lexical_cast(L"inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast(L"-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast(L"-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"+NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN(some string)") ) ); + BOOST_CHECK_THROW( lexical_cast(L"NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == L"-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == L"inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == L"nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == L"-nan" ); +#endif + +#endif +} + +void test_inf_nan_float() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_double() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_long_double() +{ + test_inf_nan_templated(); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast inf anf nan parsing unit test"); + suite->add(BOOST_TEST_CASE(&test_inf_nan_float)); + suite->add(BOOST_TEST_CASE(&test_inf_nan_double)); + suite->add(BOOST_TEST_CASE(&test_inf_nan_long_double)); + + return suite; +} diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp index cd058fe..25b18ec 100644 --- a/test/lexical_cast_loopback_test.cpp +++ b/test/lexical_cast_loopback_test.cpp @@ -30,7 +30,7 @@ void test_round_conversion_long_double(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_round_conversion_float)); suite->add(BOOST_TEST_CASE(&test_round_conversion_double)); @@ -64,7 +64,6 @@ void test_round_conversion() } -#if defined(BOOST_MSVC) // See bug http://tinyurl.com/vhpvo template void test_msvc_magic_values() @@ -73,7 +72,6 @@ void test_msvc_magic_values() std::string magic_msvc_s = boost::lexical_cast(magic_msvc); BOOST_CHECK(magic_msvc == lexical_cast(magic_msvc_s)); } -#endif void test_round_conversion_float() { @@ -83,16 +81,12 @@ void test_round_conversion_float() void test_round_conversion_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } void test_round_conversion_long_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } diff --git a/test/lexical_cast_noncopyable_test.cpp b/test/lexical_cast_noncopyable_test.cpp index 6284b14..1f120d9 100644 --- a/test/lexical_cast_noncopyable_test.cpp +++ b/test/lexical_cast_noncopyable_test.cpp @@ -28,7 +28,7 @@ void test_noncopyable(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_noncopyable)); diff --git a/test/lexical_cast_vc8_bug_test.cpp b/test/lexical_cast_vc8_bug_test.cpp index 843bea8..9e5ef0b 100644 --- a/test/lexical_cast_vc8_bug_test.cpp +++ b/test/lexical_cast_vc8_bug_test.cpp @@ -1,3 +1,17 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Alexander Nasonov, 2007. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). +// +// This tests now must pass on vc8, because lexical_cast +// implementation has changed and it does not use stringstream for casts +// to integral types + #include #include #include @@ -46,7 +60,7 @@ void test_vc8_bug() unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast vc8 bug unit test"); suite->add(BOOST_TEST_CASE(test_vc8_bug)); return suite; diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp new file mode 100755 index 0000000..acd78b1 --- /dev/null +++ b/test/lexical_cast_wchars_test.cpp @@ -0,0 +1,56 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +using namespace boost; + +void test_char_types_conversions() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T + const char c_arr[] = "Test array of chars"; + const unsigned char uc_arr[] = "Test array of chars"; + const signed char sc_arr[] = "Test array of chars"; + const wchar_t wc_arr[] =L"Test array of chars"; + + // Following tests depend on realization of std::locale + // and pass for popular compilers and STL realizations + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); + BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(wc_arr)); + + BOOST_CHECK(boost::lexical_cast(sc_arr) == std::wstring(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(uc_arr) == std::wstring(wc_arr) ); + + BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); +#endif + BOOST_CHECK(1); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test"); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + + return suite; +}