From c2c4b884fea699f95f3cdf8484d84d05719e02ea Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 22 Sep 2013 12:23:26 +0000 Subject: [PATCH] Make a separate folder for lexical_casts examples, use those examples in documenation and assure that they successfully build and run (refs #9046) [SVN r85828] --- doc/lexical_cast.qbk | 113 +++++------------------------ example/args_to_numbers.cpp | 35 +++++++++ example/generic_stringize.cpp | 59 +++++++++++++++ example/small_examples.cpp | 52 +++++++++++++ example/variant_to_long_double.cpp | 39 ++++++++++ test/Jamfile.v2 | 7 ++ 6 files changed, 210 insertions(+), 95 deletions(-) create mode 100644 example/args_to_numbers.cpp create mode 100644 example/generic_stringize.cpp create mode 100644 example/small_examples.cpp create mode 100644 example/variant_to_long_double.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 78137ce..2006405 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -38,54 +38,22 @@ For a good discussion of the options and issues involved in string-based formatt [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; +[import ../example/args_to_numbers.cpp] - 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 &); +[section Strings to numbers conversion] [lexical_cast_args_example] [endsect] + +[import ../example/small_examples.cpp] +[section Numbers to strings conversion] [lexical_cast_log_errno] [endsect] +[section Converting to string without dynamic memory allocation] [lexical_cast_fixed_buffer] [endsect] +[section Converting part of the string] [lexical_cast_substring_conversion] [endsect] + +[import ../example/generic_stringize.cpp] +[section Generic programming (Boost.Fusion)] [lexical_cast_stringize] [endsect] + +[import ../example/variant_to_long_double.cpp] +[section Generic programming (Boost.Variant)] [lexical_cast_variant_to_long_double] [endsect] - void log_errno(int yoko) - { - log_message("Error " + boost::lexical_cast(yoko) + ": " + strerror(yoko)); - } -`` -Following example converts some number and puts it to file: -`` - int i; - FILE* file; - ... - typedef boost::array buf_t; // You can use std::array if your compiler supports it - buf_t buffer = boost::lexical_cast(i); // No dynamic memory allocation - puts(buffer.begin(), file); -`` -Following example takes part of the string and converts it to `int`: -`` -int convert_strings_part(const std::string& s, std::size_t pos, std::size_t n) -{ - return boost::lexical_cast(s.data() + pos, n); -} -`` [endsect] [section Synopsis] @@ -156,56 +124,6 @@ Exception used to indicate runtime lexical_cast failure. [endsect] -[/ Commenting out bad advise (this will break the ability to get correct function pointers via &lexical_cast) -[section Tuning classes for fast lexical conversions] -Because of `boost::lexical_cast` optimizations for `boost::iterator_range`, it is possibile to make very fast lexical conversions for non zero terminated strings, substrings and user-defined classes. - -Consider the following example: -`` - class example_class { - char non_zero_terminated_data[10]; - std::size_t data_length; - - public: - example_class(); - void fill_data(); - - const char* data() const { - return non_zero_terminated_data; - } - - std::size_t size() const { - return data_length; - } - }; - - inline std::ostream& operator << (std::ostream& ostr, const example_class& rhs) { - return ostr << boost::make_iterator_range(rhs.data(), rhs.data() + rhs.size()); - } -`` - -This is a good generic solution for most use cases. -But we can make it even faster for some performance critical applications. During conversion, we loose speed at: - - * `std::ostream` construction (it makes some heap allocations) - * `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) - * `std::ostream` destruction (it makes some heap deallocations) - -We can avoid all of this, by specifieng an overload for `boost::lexical_cast`: -`` -namespace boost { - template - OutT lexical_cast(const example_class& rhs) { - return boost::lexical_cast( - boost::make_iterator_range(rhs.data(), rhs.data() + rhs.size()) - ); - } -} -`` -Now `boost::lexical_cast(example_class_instance)` conversions won't copy data and construct heavy STL stream objects. See [link boost_lexical_cast.performance Performance] section for info on `boost::iterator_range` conversion performance. -[endsect] -] - [section Frequently Asked Questions] * [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? @@ -276,6 +194,11 @@ limitation of compiler options that you use. [section Changes] +* [*boost 1.54.0 :] + + * Fix some issues with `boost::int128_type` and `boost::uint128_type` conversions. Notify user at compile time + if the `std::numeric_limits` are not specialized for 128bit types and `boost::lexical_cast` can not make conversions. + * [*boost 1.54.0 :] * Added code to convert `boost::int128_type` and `boost::uint128_type` types (requires GCC 4.7 or higher). diff --git a/example/args_to_numbers.cpp b/example/args_to_numbers.cpp new file mode 100644 index 0000000..edcc779 --- /dev/null +++ b/example/args_to_numbers.cpp @@ -0,0 +1,35 @@ +// Copyright 2013 Antony Polukhin + +// Distributed under the Boost Software License, Version 1.0. +// (See the accompanying file LICENSE_1_0.txt +// or a copy at .) + +//[lexical_cast_args_example +//`The following example treats command line arguments as a sequence of numeric data + +#include +#include + +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(const bad_lexical_cast &) + { + args.push_back(0); + } + } + + // ... +} + +//] [/lexical_cast_args_example] diff --git a/example/generic_stringize.cpp b/example/generic_stringize.cpp new file mode 100644 index 0000000..4944532 --- /dev/null +++ b/example/generic_stringize.cpp @@ -0,0 +1,59 @@ +// Copyright 2013 Antony Polukhin + +// Distributed under the Boost Software License, Version 1.0. +// (See the accompanying file LICENSE_1_0.txt +// or a copy at .) + + +//[lexical_cast_stringize +/*` + In this example we'll make a `stringize` method that accepts a sequence, converts + each element of the sequence into string and appends that string to the result. + + Example is based on the example from the [@http://www.packtpub.com/boost-cplusplus-application-development-cookbook/book Boost C++ Application Development Cookbook] + by Antony Polukhin, ISBN 9781849514880. + + Step 1: Making a functor that converts any type to a string and remembers result: +*/ + +#include +#include + +struct stringize_functor: boost::noncopyable { +private: + std::string& result; + +public: + explicit stringize_functor(std::string& res) + : result(res) + {} + + template + void operator()(const T& v) const { + result += boost::lexical_cast(v); + } +}; + +//` Step 2: Applying `stringize_functor` to each element in sequence: +#include +template +std::string stringize(const Sequence& seq) { + std::string result; + boost::fusion::for_each(seq, stringize_functor(result)); + return result; +} + +//` Step 3: Using the `stringize` with different types: +#include +#include +#include + +int main() { + boost::tuple decim('-', 10, 'e', 5); + std::pair value_and_type(270, "Kelvin"); + + std::cout << stringize(decim) << '\n' // outputs '-10e5' + << stringize(value_and_type); // outputs '270Kelvin' +} + +//] [/lexical_cast_stringize] diff --git a/example/small_examples.cpp b/example/small_examples.cpp new file mode 100644 index 0000000..31f3981 --- /dev/null +++ b/example/small_examples.cpp @@ -0,0 +1,52 @@ +// Copyright 2013 Antony Polukhin + +// Distributed under the Boost Software License, Version 1.0. +// (See the accompanying file LICENSE_1_0.txt +// or a copy at .) + +#include +#include +#include + +//[lexical_cast_log_errno +//`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)); +} + +//] [/lexical_cast_log_errno] + + +//[lexical_cast_fixed_buffer +//`The following example converts some number and puts it to file: + +void number_to_file(int number, FILE* file) +{ + typedef boost::array buf_t; // You can use std::array if your compiler supports it + buf_t buffer = boost::lexical_cast(number); // No dynamic memory allocation + fputs(buffer.begin(), file); +} + +//] [/lexical_cast_fixed_buffer] + +//[lexical_cast_substring_conversion +//`The following example takes part of the string and converts it to `int`: + +int convert_strings_part(const std::string& s, std::size_t pos, std::size_t n) +{ + return boost::lexical_cast(s.data() + pos, n); +} + +//] [/lexical_cast_substring_conversion] + +void log_message(const std::string &) {} + +int main() +{ + return 0; +} + diff --git a/example/variant_to_long_double.cpp b/example/variant_to_long_double.cpp new file mode 100644 index 0000000..2ed95a8 --- /dev/null +++ b/example/variant_to_long_double.cpp @@ -0,0 +1,39 @@ +// Copyright 2013 Antony Polukhin + +// Distributed under the Boost Software License, Version 1.0. +// (See the accompanying file LICENSE_1_0.txt +// or a copy at .) + + +//[lexical_cast_variant_to_long_double +/*` + In this example we'll make a `to_long_double` method that converts value of the Boost.Variant to `long double`. +*/ + +#include +#include +#include + +struct to_long_double_functor: boost::static_visitor { + template + long double operator()(const T& v) const { + // Lexical cast has many optimizations including optimizations for situations that usually + // occur in generic programming, like std::string to std::string or arithmetic type to arithmetic type conversion. + return boost::lexical_cast(v); + } +}; + +// Throws `boost::bad_lexical_cast` if value of the variant is not convertible to `long double` +template +long double to_long_double(const Variant& v) { + return boost::apply_visitor(to_long_double_functor(), v); +} + +int main() { + boost::variant v1('0'), v2("10.0001"), v3(1); + + long double sum = to_long_double(v1) + to_long_double(v2) + to_long_double(v3); + assert(sum > 11 && sum < 11.1); +} + +//] [/lexical_cast_variant_to_long_double] diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b1ffb57..bd17204 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -64,3 +64,10 @@ test-suite conversion [ run lexical_cast_filesystem_test.cpp ../../filesystem/build//boost_filesystem/static ] ; +# Assuring that examples compile and run. Adding sources from `example` directory to the `conversion` test suite. +for local p in [ glob ../example/*.cpp ] +{ + conversion += [ run $(p) ] ; +} + +