From fe752d84234d603e7d1a90803284cb20faa8affc Mon Sep 17 00:00:00 2001 From: VB Date: Thu, 5 Jun 2014 14:04:06 +1000 Subject: [PATCH] addressing review comments --- doc/converters.qbk | 8 +- example/algorithms.cpp | 1 - example/example.hpp | 2 + example/getting_serious.cpp | 1 - example/getting_started.cpp | 1 - include/boost/convert.hpp | 27 ++-- .../boost/convert/detail/algorithm_helper.hpp | 17 +-- include/boost/convert/{ => detail}/base.hpp | 12 +- .../boost/convert/{ => detail}/forward.hpp | 8 ++ include/boost/convert/detail/optional.hpp | 96 +++++++++++++ include/boost/convert/lexical_cast.hpp | 8 +- include/boost/convert/printf.hpp | 51 ++++--- include/boost/convert/result.hpp | 56 -------- include/boost/convert/spirit.hpp | 12 +- include/boost/convert/sstream.hpp | 29 ++-- include/boost/convert/strtol.hpp | 30 ++-- makefile | 3 +- test/algorithms.cpp | 2 +- test/callable.cpp | 8 +- test/encryption.cpp | 4 +- test/int_to_str.cpp | 2 +- test/invalid.hpp | 26 ++++ test/lcast_converter.cpp | 2 +- test/performance.cpp | 100 ++++++++++--- test/scratchpad.cpp | 2 +- test/sfinae.cpp | 2 +- test/spirit.cpp | 38 +---- test/sstream.cpp | 135 ++++++++++++++++++ test/sstream_converter.cpp | 26 ---- test/sstream_locale.cpp | 56 -------- test/sstream_manipulators.cpp | 59 -------- test/str_to_bool.cpp | 2 +- test/str_to_int.cpp | 126 ---------------- test/str_to_int.hpp | 76 ++++------ test/test.hpp | 40 ++---- test/test_convert.cpp | 43 ++++-- test/user_type.cpp | 2 +- 37 files changed, 526 insertions(+), 587 deletions(-) rename include/boost/convert/{ => detail}/base.hpp (94%) rename include/boost/convert/{ => detail}/forward.hpp (77%) create mode 100644 include/boost/convert/detail/optional.hpp delete mode 100644 include/boost/convert/result.hpp create mode 100644 test/invalid.hpp create mode 100644 test/sstream.cpp delete mode 100644 test/sstream_converter.cpp delete mode 100644 test/sstream_locale.cpp delete mode 100644 test/sstream_manipulators.cpp delete mode 100644 test/str_to_int.cpp diff --git a/doc/converters.qbk b/doc/converters.qbk index e7c4844..2cd715a 100644 --- a/doc/converters.qbk +++ b/doc/converters.qbk @@ -5,15 +5,15 @@ For a converter to be plugged in to the ['Boost.Convert] framework it needs to be a ['callable] with the following signature: template - bool operator()(TypeIn const& value_in, TypeOut& result_out) const; + bool operator()(TypeIn const& value_in, boost::optional& result_out) const; if that is a general-purpose converter capable of handling many types (like string-to-type and type-to-string conversions). Alternatively, a purpose-built custom converter might only care to provide - bool operator()(TypeIn const& value_in, TypeOut& result_out) const; + bool operator()(TypeIn const& value_in, boost::optional& result_out) const; if its sole purpose is to handle one particular conversion\/transformation of ['TypeIn] to ['TypeOut]. For example, a converter from the operating-system-specific MBCS string format to the UCS-2 or UCS-4 (depending on `wchar_t` size) does not seem like such an unreasonable idea: - bool operator()(std::string const& value_in, std::wstring& result_out) const; + bool operator()(std::string const& value_in, boost::optional& result_out) const; Alternatively again, an ad-hoc in-place ['callable] might be provided as a converter. For example, @@ -21,7 +21,7 @@ Alternatively again, an ad-hoc in-place ['callable] might be provided as a conve or an old-fashioned function: - extern bool my_converter(std::string const&, int&); + extern bool my_converter(std::string const&, boost::optional&); int v = boost::convert(str, my_converter).value_or(-1); diff --git a/example/algorithms.cpp b/example/algorithms.cpp index b473372..9e3dcf0 100644 --- a/example/algorithms.cpp +++ b/example/algorithms.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include diff --git a/example/example.hpp b/example/example.hpp index 45afd18..1e703f9 100644 --- a/example/example.hpp +++ b/example/example.hpp @@ -1,6 +1,8 @@ #ifndef BOOST_CONVERT_EXAMPLE_HPP #define BOOST_CONVERT_EXAMPLE_HPP +#include + struct example { static void getting_started (); diff --git a/example/getting_serious.cpp b/example/getting_serious.cpp index fcf4581..589b690 100644 --- a/example/getting_serious.cpp +++ b/example/getting_serious.cpp @@ -1,5 +1,4 @@ #include "./example.hpp" -#include #include #include diff --git a/example/getting_started.cpp b/example/getting_started.cpp index 67a2f3d..fec00f3 100644 --- a/example/getting_started.cpp +++ b/example/getting_started.cpp @@ -1,5 +1,4 @@ #include "./example.hpp" -#include //[getting_started_headers1 #include #include diff --git a/include/boost/convert.hpp b/include/boost/convert.hpp index 7b9f2ee..232824b 100644 --- a/include/boost/convert.hpp +++ b/include/boost/convert.hpp @@ -1,9 +1,9 @@ -// Boost.Convert library +// Boost.Convert // Copyright (c) 2009-2014 Vladimir Batov. // // Many thanks to // *) Andrzej Krzemienski for helping great deal to partition responsibilities and to ultimately pave -// the way for the tr1::optional deployment; +// the way for the std::tr2::optional deployment; // *) Edward Diener the Boost Review Manager for helping with the converters' design, his continuous // involvement, technical and administrative help, guidance and advice; // *) Kevlin Henney and Dave Abrahams for their ['lexical_cast]-related insights and explanations; @@ -15,29 +15,30 @@ #ifndef BOOST_CONVERT_HPP #define BOOST_CONVERT_HPP -#include +#include #include #include -#include +#include namespace boost { // C2. TypeIn is passed in to the Converter as-is. // That way the converter will be able to optimize the conversion based on that TypeIn type. - // C3. convert() allocates storage for the conversion result. - // The Pascal-style passing of the out_type& to the converter is ugly. However, it - // a) ensures the consistent requirement with regard to "out_type" - // (rather than every converter imposing their own); - // b) relieves the converter of that responsibility and makes writing converters easier. template boost::cnv::optional convert(TypeIn const& value_in, Converter const& converter) { - cnv::optional result (boost::make_default()); //C3 - bool success = converter(value_in, result.value_); //C2,C3 - - return success ? result : result(false); + try + { + boost::cnv::optional result; + + return converter(value_in, result) ? result : boost::cnv::optional(); + } + catch (...) + { + return boost::cnv::optional(); + } } template diff --git a/include/boost/convert/detail/algorithm_helper.hpp b/include/boost/convert/detail/algorithm_helper.hpp index fd8d3a6..7f137af 100644 --- a/include/boost/convert/detail/algorithm_helper.hpp +++ b/include/boost/convert/detail/algorithm_helper.hpp @@ -5,10 +5,8 @@ #ifndef BOOST_CONVERT_DETAIL_ALGORITHM_HELPER_HPP #define BOOST_CONVERT_DETAIL_ALGORITHM_HELPER_HPP -#include +#include #include -#include -#include namespace boost { namespace cnv { @@ -23,13 +21,12 @@ namespace boost { namespace cnv template TypeOut operator()(TypeIn const& value_in) { - TypeOut result = boost::make_default(); - bool good = (*converter_)(value_in, result); + boost::cnv::optional result; - if (!good) - BOOST_THROW_EXCEPTION(std::invalid_argument("boost::convert failed")); + if (!(*converter_)(value_in, result)) + boost::cnv::dothrow(); - return result; + return result.value(); } protected: @@ -53,10 +50,10 @@ namespace boost { namespace cnv template TypeOut operator()(TypeIn const& value_in) { - TypeOut result = boost::make_default(); + boost::cnv::optional result; bool good = (*base_type::converter_)(value_in, result); - return good ? result : fallback_; + return good ? result.value() : fallback_; } TypeOut fallback_; diff --git a/include/boost/convert/base.hpp b/include/boost/convert/detail/base.hpp similarity index 94% rename from include/boost/convert/base.hpp rename to include/boost/convert/detail/base.hpp index c28eabe..d16344a 100644 --- a/include/boost/convert/base.hpp +++ b/include/boost/convert/detail/base.hpp @@ -7,16 +7,16 @@ #include -namespace boost +namespace boost { namespace cnv { namespace detail { - struct converter_base; -} + struct cnvbase; +}}} -struct boost::converter_base +struct boost::cnv::detail::cnvbase { - typedef boost::converter_base this_type; + typedef boost::cnv::detail::cnvbase this_type; - converter_base() + cnvbase() : base_(10), precision_(0), uppercase_(false) {} diff --git a/include/boost/convert/forward.hpp b/include/boost/convert/detail/forward.hpp similarity index 77% rename from include/boost/convert/forward.hpp rename to include/boost/convert/detail/forward.hpp index 3e61cae..8876bf3 100644 --- a/include/boost/convert/forward.hpp +++ b/include/boost/convert/detail/forward.hpp @@ -5,6 +5,9 @@ #ifndef BOOST_CONVERT_FORWARD_HPP #define BOOST_CONVERT_FORWARD_HPP +#include +#include + namespace boost { namespace cnv @@ -12,6 +15,11 @@ namespace boost template struct algorithm_helper; template struct algorithm_helper_with_fallback; template struct optional; + + static void dothrow() + { + BOOST_THROW_EXCEPTION(std::invalid_argument("boost::convert failed")); + } } template diff --git a/include/boost/convert/detail/optional.hpp b/include/boost/convert/detail/optional.hpp new file mode 100644 index 0000000..f6af04f --- /dev/null +++ b/include/boost/convert/detail/optional.hpp @@ -0,0 +1,96 @@ +// Copyright (c) 2009-2014 Vladimir Batov. +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. + +#ifndef BOOST_CONVERT_RESULT_HPP +#define BOOST_CONVERT_RESULT_HPP + +#include +#include + +//#define USE_MINE +#ifdef USE_MINE + +#include + +namespace boost { namespace cnv +{ + // Used temporarily. To be replaced with std::tr2::optional or improved boost::optional. + template + struct optional + { + typedef optional this_type; + typedef boost::safebool safebool; + + optional () : value_(boost::make_default()), good_(false) {} + + bool operator! () const { return !good_; } + operator typename safebool::type () const { return safebool(!operator!()); } + + template + this_type& operator=(OtherTypeOut const& v) { value_ = TypeOut(v), good_ = true; return *this; } + + TypeOut& operator*() { return value_; } + TypeOut* operator->() { return &value_; } + + TypeOut const& value() const + { + if (!good_) + boost::cnv::dothrow(); + + return value_; + } + + template + TypeOut value_or(FallbackType const& fallback) const + { + return good_ ? value_ : TypeOut(fallback); + } + + private: + + TypeOut value_; + bool good_; + }; +}} + +#else + +// Somehow the below introduces performance overhead: +// str-to-int spirit: raw/cnv=0.13/0.16 seconds. +// when our own (above) does not: +// str-to-int spirit: raw/cnv=0.13/0.13 seconds. + +namespace boost { namespace cnv +{ + // Used temporarily. To be replaced with std::tr2::optional or improved boost::optional. + template + struct optional : public boost::optional + { + typedef optional this_type; + typedef boost::optional base_type; + + optional () {} + + template + this_type& operator=(OtherTypeOut const& v) { base_type::operator=(TypeOut(v)); return *this; } + + TypeOut const& value() const + { + if (!*this) + boost::cnv::dothrow(); + + return base_type::get(); + } + + template + TypeOut value_or(FallbackType const& fallback) const + { + return !*this ? TypeOut(fallback) : base_type::get(); + } + }; +}} + +#endif + +#endif // BOOST_CONVERT_RESULT_HPP diff --git a/include/boost/convert/lexical_cast.hpp b/include/boost/convert/lexical_cast.hpp index 597bddc..dc3cf65 100644 --- a/include/boost/convert/lexical_cast.hpp +++ b/include/boost/convert/lexical_cast.hpp @@ -2,8 +2,8 @@ // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. -#ifndef BOOST_CONVERT_LEXICAL_CAST_BASED_CONVERTER_HPP -#define BOOST_CONVERT_LEXICAL_CAST_BASED_CONVERTER_HPP +#ifndef BOOST_CONVERT_LEXICAL_CAST_HPP +#define BOOST_CONVERT_LEXICAL_CAST_HPP #include @@ -16,7 +16,7 @@ struct boost::cnv::lexical_cast { template bool - operator()(TypeIn const& value_in, TypeOut& result_out) const + operator()(TypeIn const& value_in, boost::cnv::optional& result_out) const { try { @@ -30,4 +30,4 @@ struct boost::cnv::lexical_cast } }; -#endif // BOOST_CONVERT_LEXICAL_CAST_BASED_CONVERTER_HPP +#endif // BOOST_CONVERT_LEXICAL_CAST_HPP diff --git a/include/boost/convert/printf.hpp b/include/boost/convert/printf.hpp index 8a13e26..af6c299 100644 --- a/include/boost/convert/printf.hpp +++ b/include/boost/convert/printf.hpp @@ -2,21 +2,21 @@ // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. -#ifndef BOOST_CONVERT_PRINTF_CONVERTER_HPP -#define BOOST_CONVERT_PRINTF_CONVERTER_HPP +#ifndef BOOST_CONVERT_PRINTF_HPP +#define BOOST_CONVERT_PRINTF_HPP -#include +#include #include -namespace boost +namespace boost { namespace cnv { - struct printf_converter; -} + struct printf; +}} -struct boost::printf_converter : public boost::converter_base +struct boost::cnv::printf : public boost::cnv::detail::cnvbase { - typedef boost::printf_converter this_type; - typedef boost::converter_base base_type; + typedef boost::cnv::printf this_type; + typedef boost::cnv::detail::cnvbase base_type; CONVERT_FUNC_SET_BASE; CONVERT_FUNC_SET_PRECISION; @@ -24,28 +24,28 @@ struct boost::printf_converter : public boost::converter_base template typename boost::disable_if, bool>::type - operator()(TypeIn const& value_in, std::string& result_out) const + operator()(TypeIn const& value_in, boost::cnv::optional& result_out) const { - int const bufsz = 256; + int const bufsz = 256; char buf[bufsz]; - int num_chars = snprintf(buf, bufsz, format(pos()), value_in); - bool success = num_chars < bufsz; + int const num_chars = ::snprintf(buf, bufsz, format(pos()), value_in); + bool const success = num_chars < bufsz; - if (success) result_out = buf; + if (success) result_out = std::string(buf); return success; } template typename boost::disable_if, bool>::type - operator()(std::string const& value_in, TypeOut& result_out) const + operator()(std::string const& value_in, boost::cnv::optional& result_out) const { return this_type::operator()(value_in.c_str(), result_out); } template typename boost::disable_if, bool>::type - operator()(char const* value_in, TypeOut& result_out) const + operator()(char const* value_in, boost::cnv::optional& result_out) const { - int num_read = sscanf(value_in, format(pos()), &result_out); + int num_read = ::sscanf(value_in, format(pos()), &*(result_out = boost::make_default())); return num_read == 1; } @@ -68,16 +68,15 @@ struct boost::printf_converter : public boost::converter_base char const* format(int pos) const { - char const* d_format[] = { "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types - char const* x_format[] = { "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types - char const* o_format[] = { "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types - char const* format = base_ == 10 ? d_format[pos] - : base_ == 16 ? x_format[pos] - : base_ == 8 ? o_format[pos] - : (BOOST_ASSERT(0), (char const*) 0); - + static char const* d_format[] = { "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types + static char const* x_format[] = { "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types + static char const* o_format[] = { "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types + char const* format = base_ == 10 ? d_format[pos] + : base_ == 16 ? x_format[pos] + : base_ == 8 ? o_format[pos] + : (BOOST_ASSERT(0), (char const*) 0); return format; } }; -#endif // BOOST_CONVERT_PRINTF_CONVERTER_HPP +#endif // BOOST_CONVERT_PRINTF_HPP diff --git a/include/boost/convert/result.hpp b/include/boost/convert/result.hpp deleted file mode 100644 index fad62a1..0000000 --- a/include/boost/convert/result.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2009-2014 Vladimir Batov. -// Use, modification and distribution are subject to the Boost Software License, -// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. - -#ifndef BOOST_CONVERT_RESULT_HPP -#define BOOST_CONVERT_RESULT_HPP - -#include -#include -#include -#include - -namespace boost { namespace cnv -{ - // Used temporarily. To be replaced with std::tr2::optional or improved boost::optional. - template - struct optional - { - typedef optional this_type; - typedef boost::safebool safebool; - - optional (TypeOut const& v) : value_(v), good_(true) {} - - bool operator! () const { return !good_; } - operator typename safebool::type () const { return safebool(!operator!()); } - // operator TypeOut const& () const { return this_type::value(); } - - TypeOut const& value() const - { - if (!good_) - BOOST_THROW_EXCEPTION(std::invalid_argument("boost::convert failed")); - - return value_; - } - - template - TypeOut value_or(FallbackType const& fallback) const - { - return good_ ? value_ : fallback; - } - - private: - - template - friend - boost::cnv::optional - boost::convert(TypeIn const& value_in, Converter const& converter); - - this_type& operator()(bool good) { return (good_ = good, *this); } - - TypeOut value_; - bool good_; - }; -}} - -#endif // BOOST_CONVERT_RESULT_HPP diff --git a/include/boost/convert/spirit.hpp b/include/boost/convert/spirit.hpp index 759e849..4672f87 100644 --- a/include/boost/convert/spirit.hpp +++ b/include/boost/convert/spirit.hpp @@ -5,18 +5,18 @@ #include #include -namespace boost +namespace boost { namespace cnv { - struct spirit_converter; -} + struct spirit; +}} -struct boost::spirit_converter +struct boost::cnv::spirit { - bool operator()(std::string const& str, int& result) const + bool operator()(std::string const& str, boost::cnv::optional& result) const { std::string::const_iterator i = str.begin(); - if (!boost::spirit::qi::parse(i, str.end(), boost::spirit::int_, result)) + if (!boost::spirit::qi::parse(i, str.end(), boost::spirit::int_, *(result = int()))) return false; return i == str.end(); // ensure the whole string was parsed diff --git a/include/boost/convert/sstream.hpp b/include/boost/convert/sstream.hpp index bbf5336..105dd3c 100644 --- a/include/boost/convert/sstream.hpp +++ b/include/boost/convert/sstream.hpp @@ -5,7 +5,7 @@ #ifndef BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP #define BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP -#include +#include #include #include #include @@ -21,13 +21,13 @@ namespace boost { namespace cnv template struct boost::cnv::basic_stringstream { - typedef Char char_type; - typedef boost::cnv::basic_stringstream this_type; - typedef std::basic_stringstream stream_type; - typedef std::basic_istream istream_type; - typedef std::basic_streambuf buffer_type; - typedef detail::parser_buf parser_type; - typedef std::basic_string string_type; + typedef Char char_type; + typedef boost::cnv::basic_stringstream this_type; + typedef std::basic_stringstream stream_type; + typedef std::basic_istream istream_type; + typedef std::basic_streambuf buffer_type; + typedef boost::detail::parser_buf parser_type; + typedef std::basic_string string_type; typedef std::ios_base& (*manipulator_type)(std::ios_base&); basic_stringstream() @@ -37,7 +37,7 @@ struct boost::cnv::basic_stringstream template typename boost::enable_if_c::value, bool>::type - operator()(TypeIn const& value_in, string_type& string_out) const + operator()(TypeIn const& value_in, boost::cnv::optional& string_out) const { stream_.clear(); // Clear the flags stream_.str(string_type()); // Clear/empty the content of the stream @@ -48,7 +48,7 @@ struct boost::cnv::basic_stringstream typename boost::enable_if_c< cnv::is_any_string::value && !cnv::is_any_string::value, bool>::type - operator()(StringIn const& string_in, TypeOut& result_out) const + operator()(StringIn const& string_in, boost::cnv::optional& result_out) const { typedef cnv::string_range str_range; @@ -58,9 +58,7 @@ struct boost::cnv::basic_stringstream char_type const* beg = str_range::begin(string_in); std::streamsize sz = str_range::size(string_in); - stream_.clear(); // Clear the flags -// stream_.str(string_in); // Copy the content to the internal buffer -// stream_ >> result_out; + stream_.clear(); // Clear the flags // The code below (pretty much stolen from shr_using_base_class(InputStreamable& output) in lexical_cast.hpp // uses the provided string_in as the buffer and, consequently, avoids the overhead associated with @@ -68,7 +66,7 @@ struct boost::cnv::basic_stringstream strbuf.setbuf(const_cast(beg), sz); istream.rdbuf(&strbuf); - istream >> result_out; + istream >> *(result_out = boost::make_default()); bool result = !istream.fail() && istream.eof(); istream.rdbuf(oldbuf); @@ -78,9 +76,6 @@ struct boost::cnv::basic_stringstream this_type& operator() (std::locale const& locale) { return (stream_.imbue(locale), *this); } this_type& operator() (manipulator_type m) { return (m(stream_), *this); } - template - this_type& operator()(Manipulator m) { return (stream_ >> m, *this); } - CONVERTER_PARAM_FUNC(locale, std::locale) { std::locale const& locale = arg[cnv::parameter::locale]; diff --git a/include/boost/convert/strtol.hpp b/include/boost/convert/strtol.hpp index ffb3a73..f7de08d 100644 --- a/include/boost/convert/strtol.hpp +++ b/include/boost/convert/strtol.hpp @@ -5,7 +5,7 @@ #ifndef BOOST_CONVERT_STRTOL_CONVERTER_HPP #define BOOST_CONVERT_STRTOL_CONVERTER_HPP -#include +#include #include namespace boost { namespace cnv @@ -13,21 +13,21 @@ namespace boost { namespace cnv struct strtol; }} -struct boost::cnv::strtol : public boost::converter_base +struct boost::cnv::strtol : public boost::cnv::detail::cnvbase { typedef boost::cnv::strtol this_type; - typedef boost::converter_base base_type; + typedef boost::cnv::detail::cnvbase base_type; CONVERT_FUNC_SET_BASE; CONVERT_FUNC_SET_PRECISION; CONVERT_FUNC_SET_UPPERCASE; - bool operator()(std::string const& v, int& r) const { return operator()(v.c_str(), r); } - bool operator()(std::string const& v, long int& r) const { return operator()(v.c_str(), r); } - bool operator()(std::string const& v, unsigned long int& r) const { return operator()(v.c_str(), r); } - bool operator()(std::string const& v, double& r) const { return operator()(v.c_str(), r); } + bool operator()(std::string const& v, boost::cnv::optional& r) const { return operator()(v.c_str(), r); } + bool operator()(std::string const& v, boost::cnv::optional& r) const { return operator()(v.c_str(), r); } + bool operator()(std::string const& v, boost::cnv::optional& r) const { return operator()(v.c_str(), r); } + bool operator()(std::string const& v, boost::cnv::optional& r) const { return operator()(v.c_str(), r); } - bool operator()(char const* value_in, double& result_out) const + bool operator()(char const* value_in, boost::cnv::optional& result_out) const { char const* str_end = value_in + strlen(value_in); char* cnv_end = 0; @@ -36,7 +36,7 @@ struct boost::cnv::strtol : public boost::converter_base return cnv_end == str_end; } - bool operator()(char const* value_in, int& result_out) const + bool operator()(char const* value_in, boost::cnv::optional& result_out) const { char const* str_end = value_in + strlen(value_in); char* cnv_end = 0; @@ -45,28 +45,28 @@ struct boost::cnv::strtol : public boost::converter_base return success ? (result_out = int(result), success) : success; } - bool operator()(char const* value_in, long int& result_out) const + bool operator()(char const* value_in, boost::cnv::optional& result_out) const { char const* str_end = value_in + strlen(value_in); char* cnv_end = 0; result_out = ::strtol(value_in, &cnv_end, base_); - return result_out != LONG_MIN && result_out != LONG_MAX && cnv_end == str_end; + return *result_out != LONG_MIN && *result_out != LONG_MAX && cnv_end == str_end; } - bool operator()(char const* value_in, unsigned long int& result_out) const + bool operator()(char const* value_in, boost::cnv::optional& result_out) const { char const* str_end = value_in + strlen(value_in); char* cnv_end = 0; result_out = ::strtoul(value_in, &cnv_end, base_); - return result_out != ULONG_MAX && cnv_end == str_end; + return *result_out != ULONG_MAX && cnv_end == str_end; } - bool operator()(int value_in, std::string& result_out) const + bool operator()(int value_in, boost::cnv::optional& result_out) const { - this_type::ltostr(value_in, base_).swap(result_out); + result_out = this_type::ltostr(value_in, base_); return true; } diff --git a/makefile b/makefile index 3110beb..e2db6df 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,7 @@ ifneq ($(DEVMAKE),) -cflags = -Iinclude -I../boost_1_55_0 -Wno-unused-local-typedefs -Wno-unused-variable +cflags = -O3 -Iinclude -I../boost_1_55_0 -Wno-unused-local-typedefs -Wno-unused-variable -Wno-uninitialized +#cflags = -Iinclude -I../boost_1_55_0 -Wno-unused-local-typedefs -Wno-unused-variable -Wno-uninitialized target = test-convert.exe sources = $(wildcard test/*.cpp) $(wildcard example/*.cpp) diff --git a/test/algorithms.cpp b/test/algorithms.cpp index a7dfbcb..ed388b3 100644 --- a/test/algorithms.cpp +++ b/test/algorithms.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/callable.cpp b/test/callable.cpp index 1aa94d3..7f5989a 100644 --- a/test/callable.cpp +++ b/test/callable.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. @@ -8,7 +8,7 @@ static bool -plain_old_func(std::string const& value_in, int& value_out) +plain_old_func(std::string const& value_in, boost::cnv::optional& value_out) { try { @@ -23,7 +23,7 @@ plain_old_func(std::string const& value_in, int& value_out) template bool -assign(Type& value_out, Type const& value_in) +assign(boost::cnv::optional& value_out, Type const& value_in) { value_out = value_in; return true; @@ -32,7 +32,7 @@ assign(Type& value_out, Type const& value_in) void test::callables() { - typedef boost::function boost_func; + typedef boost::function&)> boost_func; char const* const str = "-12"; diff --git a/test/encryption.cpp b/test/encryption.cpp index 8924d24..3439b0a 100644 --- a/test/encryption.cpp +++ b/test/encryption.cpp @@ -5,13 +5,13 @@ using std::wstring; static bool -my_cypher(std::string const& value_in, std::string& value_out) +my_cypher(std::string const& value_in, boost::cnv::optional& value_out) { size_t const cypher = 'A' - '1'; value_out = value_in; - for (string::iterator it = value_out.begin(); it != value_out.end(); ++it) + for (string::iterator it = value_out->begin(); it != value_out->end(); ++it) (*it < 'A') ? (*it += cypher) : (*it -= cypher); return true; diff --git a/test/int_to_str.cpp b/test/int_to_str.cpp index 54b1bf7..3b920f4 100644 --- a/test/int_to_str.cpp +++ b/test/int_to_str.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/invalid.hpp b/test/invalid.hpp new file mode 100644 index 0000000..cf44d45 --- /dev/null +++ b/test/invalid.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_CONVERT_TEST_INVALID_HPP +#define BOOST_CONVERT_TEST_INVALID_HPP + +#include "./test.hpp" + +template +void +test::invalid(Converter const& cnv) +{ + char const* str[] = { "not", "1 2", " 33", "44 ", "0x11", "7 + 5" }; + int const size = sizeof(str) / sizeof(str[0]); + + for (int k = 0; k < size; ++k) + { + boost::cnv::optional const res = boost::convert(str[k], cnv); + bool const failed = !res; + + if (!failed) + { + printf("test::invalid() failed for: <%s><%d>\n", str[k], res.value()); + } + BOOST_TEST(failed); + } +} + +#endif // BOOST_CONVERT_TEST_INVALID_HPP diff --git a/test/lcast_converter.cpp b/test/lcast_converter.cpp index d62a4db..28e4295 100644 --- a/test/lcast_converter.cpp +++ b/test/lcast_converter.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/performance.cpp b/test/performance.cpp index fa3637b..7856373 100644 --- a/test/performance.cpp +++ b/test/performance.cpp @@ -1,12 +1,68 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. #include "./test.hpp" +#include using std::string; +struct performance +{ + template static double str_to_int (test::strings const&, Converter const&); + template static double int_to_str (test::ints const&, Converter const&); +}; + +static +int +str_to_int_spirit(std::string const& str) +{ + std::string::const_iterator i = str.begin(); + int result; + + if (!boost::spirit::qi::parse(i, str.end(), boost::spirit::int_, result)) + BOOST_ASSERT(0); + + BOOST_ASSERT(i == str.end()); // ensure the whole string was parsed + + return result; +} + +static +double +performance_string_to_int_spirit(test::strings const& strings) +{ + int sum = 0; + int const size = strings.size(); + double const p1 = clock(); + + for (int k = 0; k < size; ++k) + sum += str_to_int_spirit(strings[k]); + + double const p2 = clock(); + int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0); + + return (p2 - p1) / CLOCKS_PER_SEC + use_sum; +} + +template +double +performance::str_to_int(test::strings const& strings, Converter const& try_converter) +{ + int sum = 0; + int const size = strings.size(); + double const p1 = clock(); + + for (int k = 0; k < size; ++k) + sum += boost::convert(strings[k], try_converter).value(); + + double const p2 = clock(); + int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0); + + return (p2 - p1) / CLOCKS_PER_SEC + use_sum; +} + template double performance_string_to_type(Converter const& try_converter) @@ -55,41 +111,47 @@ performance_type_to_string(Converter const& try_converter) template double -performance_int_to_string(Converter const& try_converter) +performance::int_to_str(test::ints const& ints, Converter const& try_converter) { - std::vector res; res.reserve(test::num_cycles); - double const p1 = clock(); + int const size = ints.size(); + std::vector strings; strings.reserve(size); + double const p1 = clock(); - for (int k = 0; k < test::num_cycles; ++k) - res.push_back(boost::convert(k, try_converter).value()); + for (int k = 0; k < size; ++k) + strings.push_back(boost::convert(ints[k], try_converter).value()); double const p2 = clock(); - for (int k = 0; k < test::num_cycles; ++k) - BOOST_TEST(k == boost::convert(res[k], try_converter).value()); + for (int k = 0; k < size; ++k) + BOOST_TEST(ints[k] == boost::convert(strings[k], try_converter).value()); return (p2 - p1) / CLOCKS_PER_SEC; } void -test::performance() +test::performance(test::strings const& strings, test::ints const& ints) { + for (int k = 0; k < 3; ++k) + printf("str-to-int spirit: raw/cnv=%.2f/%.2f seconds.\n", + performance_string_to_int_spirit(strings), + performance::str_to_int(strings, boost::cnv::spirit())); + printf("str-to-int: strtol/scanf/lcast/sstream=%.2f/%.2f/%.2f/%.2f seconds.\n", - performance_string_to_int(boost:: cnv::strtol()), - performance_string_to_int(boost:: printf_converter()), - performance_string_to_int(boost:: cnv::lexical_cast()), - performance_string_to_int(boost::cnv::cstringstream())); + performance::str_to_int(strings, boost::cnv::strtol()), + performance::str_to_int(strings, boost::cnv::printf()), + performance::str_to_int(strings, boost::cnv::lexical_cast()), + performance::str_to_int(strings, boost::cnv::cstringstream())); printf("int-to-str: ltostr/prntf/lcast/sstream=%.2f/%.2f/%.2f/%.2f seconds.\n", - performance_int_to_string(boost:: cnv::strtol()), - performance_int_to_string(boost:: printf_converter()), - performance_int_to_string(boost:: cnv::lexical_cast()), - performance_int_to_string(boost::cnv::cstringstream())); + performance::int_to_str(ints, boost::cnv::strtol()), + performance::int_to_str(ints, boost::cnv::printf()), + performance::int_to_str(ints, boost::cnv::lexical_cast()), + performance::int_to_str(ints, boost::cnv::cstringstream())); printf("str-to-user-type: lcast/sstream=%.2f/%.2f seconds.\n", - performance_string_to_type(boost:: cnv::lexical_cast()), + performance_string_to_type(boost::cnv::lexical_cast()), performance_string_to_type(boost::cnv::cstringstream())); printf("user-type-to-str: lcast/sstream=%.2f/%.2f seconds.\n", - performance_type_to_string(boost:: cnv::lexical_cast()), + performance_type_to_string(boost::cnv::lexical_cast()), performance_type_to_string(boost::cnv::cstringstream())); } diff --git a/test/scratchpad.cpp b/test/scratchpad.cpp index b717dfb..fff8574 100644 --- a/test/scratchpad.cpp +++ b/test/scratchpad.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/sfinae.cpp b/test/sfinae.cpp index 98b13ef..92df24e 100644 --- a/test/sfinae.cpp +++ b/test/sfinae.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/spirit.cpp b/test/spirit.cpp index 25d7ea4..f50e49d 100644 --- a/test/spirit.cpp +++ b/test/spirit.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. @@ -6,41 +6,7 @@ #include "./test.hpp" #include -static -int -str_to_int_spirit(std::string const& str) -{ - std::string::const_iterator i = str.begin(); - int result; - - if (!boost::spirit::qi::parse(i, str.end(), boost::spirit::int_, result)) - BOOST_ASSERT(0); - - BOOST_ASSERT(i == str.end()); // ensure the whole string was parsed - - return result; -} - -double -performance_string_to_int_spirit() -{ - std::string str = "12345"; - int sum = 0; - double const p1 = clock(); - - for (int k = 0; k < test::num_cycles; ++k) - sum += str_to_int_spirit((str[4 - k % 5] = 49 + k % 9, str)); - - double const p2 = clock(); - int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0); - - return (p2 - p1) / CLOCKS_PER_SEC + use_sum; -} - void -test::spirit() +test::spirit(test::strings const& strings) { - printf("str-to-int spirit: raw/cnv=%.2f/%.2f seconds.\n", - performance_string_to_int_spirit(), - performance_string_to_int(boost::spirit_converter())); } diff --git a/test/sstream.cpp b/test/sstream.cpp new file mode 100644 index 0000000..fa97d03 --- /dev/null +++ b/test/sstream.cpp @@ -0,0 +1,135 @@ +// Boost.Convert test and usage example +// Copyright (c) 2009-2014 Vladimir Batov. +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. + +#include "./test.hpp" + +using std::string; + +static +void +test_skipws() +{ + boost::cnv::cstringstream ccnv; + boost::cnv::wstringstream wcnv; + char const* const cstr_good = " 123"; + wchar_t const* const wstr_good = L" 123"; + char const* const cstr_bad = " 123 "; // std::skipws only affects leading spaces. + wchar_t const* const wstr_bad = L" 123 "; + + ccnv(std::skipws); + wcnv(std::skipws); + + BOOST_TEST( boost::convert(cstr_good, ccnv).value() == 123); + BOOST_TEST( boost::convert(wstr_good, wcnv).value() == 123); + BOOST_TEST(!boost::convert( cstr_bad, ccnv)); + BOOST_TEST(!boost::convert( wstr_bad, wcnv)); + + ccnv(std::noskipws); + wcnv(std::noskipws); + + BOOST_TEST(!boost::convert(cstr_good, ccnv)); + BOOST_TEST(!boost::convert(wstr_good, wcnv)); + BOOST_TEST(!boost::convert( cstr_bad, ccnv)); + BOOST_TEST(!boost::convert( wstr_bad, wcnv)); +} + +static +void +test_manipulators() +{ + boost::cnv::cstringstream ccnv; + boost::cnv::wstringstream wcnv; + + int const hex_v01 = boost::convert("FF", ccnv(std::hex)).value_or(0); + int const hex_v02 = boost::convert(L"F", wcnv(std::hex)).value_or(0); + int const hex_v03 = boost::convert("FF", ccnv(std::dec)).value_or(-5); + int const hex_v04 = boost::convert(L"F", wcnv(std::dec)).value_or(-6); + + BOOST_TEST(hex_v01 == 255); // "FF" + BOOST_TEST(hex_v02 == 15); // L"F" + BOOST_TEST(hex_v03 == -5); // Failed conversion + BOOST_TEST(hex_v04 == -6); // Failed conversion + + ccnv(std::noshowbase)(std::nouppercase)(std::oct); + + BOOST_TEST(boost::convert(255, ccnv).value() == "377"); + BOOST_TEST(boost::convert( 15, ccnv).value() == "17"); + + ccnv(std::showbase); + + BOOST_TEST(boost::convert(255, ccnv).value() == "0377"); + BOOST_TEST(boost::convert( 15, ccnv).value() == "017"); + + ccnv(std::uppercase)(std::hex); + + BOOST_TEST(boost::convert(255, ccnv).value() == "0XFF"); + BOOST_TEST(boost::convert( 15, ccnv).value() == "0XF"); + + ccnv(std::noshowbase)(std::nouppercase)(std::oct); + + BOOST_TEST(boost::convert(255, ccnv).value() == "377"); + BOOST_TEST(boost::convert( 15, ccnv).value() == "17"); + + ccnv(std::showbase)(arg::uppercase = true)(arg::base = boost::cnv::base::hex); + + BOOST_TEST(boost::convert(255, ccnv).value() == "0XFF"); + BOOST_TEST(boost::convert( 15, ccnv).value() == "0XF"); +} + +static +void +test_locale() +{ + boost::cnv::cstringstream cnv; + + char const* eng_locale_name = test::is_msc ? "" // I do not know MS presentation of US locale + : test::is_gcc ? "en_US.UTF-8" + : ""; + char const* rus_locale_name = test::is_msc ? "Russian_Russia.1251" + : test::is_gcc ? "ru_RU.UTF-8" + : ""; + char const* rus_expected = test::is_msc ? "1,235e-002" : test::is_gcc ? "1,235e-02" : ""; + char const* eng_expected = test::is_msc ? "1.235e-002" : test::is_gcc ? "1.235e-02" : ""; + std::locale rus_locale; + std::locale eng_locale; + + char const* double_s01 = test::is_msc ? "1.2345E-002" + : test::is_gcc ? "1.2345E-02" + : ""; +// cnv(std::setprecision(4))(std::uppercase)(std::scientific); + cnv(arg::precision = 4) + (arg::uppercase = true) + (arg::notation = boost::cnv::notation::scientific); + + double double_v01 = boost::convert(double_s01, cnv).value(); + string double_s02 = boost::convert(double_v01, cnv).value(); + + BOOST_TEST(double_s01 == double_s02); + + try { rus_locale = std::locale(rus_locale_name); } + catch (...) { printf("Test failed: bad locale %s.\n", rus_locale_name); exit(1); } + + try { eng_locale = std::locale(eng_locale_name); } + catch (...) { printf("Test failed: bad locale %s.\n", eng_locale_name); exit(1); } + +// cnv(std::setprecision(3))(std::nouppercase); + cnv(arg::precision = 3)(arg::uppercase = false); + + string double_rus = boost::convert(double_v01, cnv(rus_locale)).value(); + string double_eng = boost::convert(double_v01, cnv(eng_locale)).value(); + printf("rus locale=%s, presentation=%s.\n", rus_locale.name().c_str(), double_rus.c_str()); + printf("eng locale=%s, presentation=%s.\n", eng_locale.name().c_str(), double_eng.c_str()); + + BOOST_TEST(double_rus == rus_expected); + BOOST_TEST(double_eng == eng_expected); +} + +void +test::sstream() +{ + test_skipws(); + test_manipulators(); + test_locale(); +} diff --git a/test/sstream_converter.cpp b/test/sstream_converter.cpp deleted file mode 100644 index 22d30a1..0000000 --- a/test/sstream_converter.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Boost.Convert library test and usage example -// Copyright (c) 2009-2014 Vladimir Batov. -// Use, modification and distribution are subject to the Boost Software License, -// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. - -#include "./test.hpp" - -using std::string; - -void -test::sstream_converter() -{ - char const* const invalid_input = "7 + 5"; - - try - { - boost::lexical_cast(invalid_input); - BOOST_TEST(!"We should not be here"); - } - catch (...) - { - } - boost::cnv::cstringstream cnv; // std::stringstream-based char converter - - BOOST_TEST(!boost::convert(invalid_input, cnv)); -} diff --git a/test/sstream_locale.cpp b/test/sstream_locale.cpp deleted file mode 100644 index 10d5449..0000000 --- a/test/sstream_locale.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Boost.Convert library test and usage example -// Copyright (c) 2009-2014 Vladimir Batov. -// Use, modification and distribution are subject to the Boost Software License, -// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. - -#include "./test.hpp" - -using std::string; - -void -test::sstream_locale() -{ - boost::cnv::cstringstream cnv; - - char const* eng_locale_name = test::is_msc ? "" // I do not know MS presentation of US locale - : test::is_gcc ? "en_US.UTF-8" - : ""; - char const* rus_locale_name = test::is_msc ? "Russian_Russia.1251" - : test::is_gcc ? "ru_RU.UTF-8" - : ""; - char const* rus_expected = test::is_msc ? "1,235e-002" : test::is_gcc ? "1,235e-02" : ""; - char const* eng_expected = test::is_msc ? "1.235e-002" : test::is_gcc ? "1.235e-02" : ""; - std::locale rus_locale; - std::locale eng_locale; - - char const* double_s01 = test::is_msc ? "1.2345E-002" - : test::is_gcc ? "1.2345E-02" - : ""; -// cnv(std::setprecision(4))(std::uppercase)(std::scientific); - cnv(arg::precision = 4) - (arg::uppercase = true) - (arg::notation = boost::cnv::notation::scientific); - - double double_v01 = boost::convert(double_s01, cnv).value(); - string double_s02 = boost::convert(double_v01, cnv).value(); - - BOOST_TEST(double_s01 == double_s02); - - try { rus_locale = std::locale(rus_locale_name); } - catch (...) { printf("Test failed: bad locale %s.\n", rus_locale_name); exit(1); } - - try { eng_locale = std::locale(eng_locale_name); } - catch (...) { printf("Test failed: bad locale %s.\n", eng_locale_name); exit(1); } - -// cnv(std::setprecision(3))(std::nouppercase); - cnv(arg::precision = 3)(arg::uppercase = false); - - string double_rus = boost::convert(double_v01, cnv(rus_locale)).value(); - string double_eng = boost::convert(double_v01, cnv(eng_locale)).value(); - printf("rus locale=%s, presentation=%s.\n", rus_locale.name().c_str(), double_rus.c_str()); - printf("eng locale=%s, presentation=%s.\n", eng_locale.name().c_str(), double_eng.c_str()); - - BOOST_TEST(double_rus == rus_expected); - BOOST_TEST(double_eng == eng_expected); - -} diff --git a/test/sstream_manipulators.cpp b/test/sstream_manipulators.cpp deleted file mode 100644 index 228d36f..0000000 --- a/test/sstream_manipulators.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Boost.Convert library test and usage example -// Copyright (c) 2009-2014 Vladimir Batov. -// Use, modification and distribution are subject to the Boost Software License, -// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. - -#include "./test.hpp" - -using std::string; - -void -test::sstream_manipulators() -{ - try - { - boost::lexical_cast("FF"); - BOOST_TEST(!"We should not be here"); - } - catch (...) - { - } - - boost::cnv::cstringstream ccnv; // std::stringstream-based char converter - boost::cnv::wstringstream wcnv; // std::stringstream-based wchar_t converter - - int const hex_v01 = boost::convert("FF", ccnv(std::hex)).value_or(0); - int const hex_v02 = boost::convert(L"F", wcnv(std::hex)).value_or(0); - int const hex_v03 = boost::convert("FF", ccnv(std::dec)).value_or(-5); - int const hex_v04 = boost::convert(L"F", wcnv(std::dec)).value_or(-6); - - BOOST_TEST(hex_v01 == 255); // "FF" - BOOST_TEST(hex_v02 == 15); // L"F" - BOOST_TEST(hex_v03 == -5); // Failed conversion - BOOST_TEST(hex_v04 == -6); // Failed conversion - - ccnv(std::noshowbase)(std::nouppercase)(std::oct); - - BOOST_TEST(boost::convert(255, ccnv).value() == "377"); - BOOST_TEST(boost::convert( 15, ccnv).value() == "17"); - - ccnv(std::showbase); - - BOOST_TEST(boost::convert(255, ccnv).value() == "0377"); - BOOST_TEST(boost::convert( 15, ccnv).value() == "017"); - - ccnv(std::uppercase)(std::hex); - - BOOST_TEST(boost::convert(255, ccnv).value() == "0XFF"); - BOOST_TEST(boost::convert( 15, ccnv).value() == "0XF"); - - ccnv(std::noshowbase)(std::nouppercase)(std::oct); - - BOOST_TEST(boost::convert(255, ccnv).value() == "377"); - BOOST_TEST(boost::convert( 15, ccnv).value() == "17"); - - ccnv(std::showbase)(arg::uppercase = true)(arg::base = boost::cnv::base::hex); - - BOOST_TEST(boost::convert(255, ccnv).value() == "0XFF"); - BOOST_TEST(boost::convert( 15, ccnv).value() == "0XF"); -} diff --git a/test/str_to_bool.cpp b/test/str_to_bool.cpp index 444e2ae..cfa1ecb 100644 --- a/test/str_to_bool.cpp +++ b/test/str_to_bool.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. diff --git a/test/str_to_int.cpp b/test/str_to_int.cpp deleted file mode 100644 index 8ed25ad..0000000 --- a/test/str_to_int.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Boost.Convert library test and usage example -// Copyright (c) 2009-2014 Vladimir Batov. -// Use, modification and distribution are subject to the Boost Software License, -// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. - -#include "./test.hpp" - -using std::string; -using std::wstring; - -void -test::string_to_int() -{ - string const not_int_str = "not an int"; - string const std_str = "-11"; - char const* const c_str = "-12"; - wstring const wstd_str = L"-13"; - wchar_t const* const wc_str = L"-14"; - char const array_str[] = "-15"; - char const* const container_str = "-16"; - std::vector const vector_str (container_str, container_str + strlen(container_str)); - std::list const list_str (container_str, container_str + strlen(container_str)); - - boost::cnv::cstringstream ccnv; // std::stringstream-based char converter - boost::cnv::wstringstream wcnv; // std::stringstream-based wchar_t converter - - //////////////////////////////////////////////////////////////////////////// - // Testing various kinds of string containers. - // Testing implicit conversion directly to TypeOut (int). - // Testing with the fallback value value provided. - // On failure returns the provided fallback value and DOES NOT THROW. - //////////////////////////////////////////////////////////////////////////// - - int const a00 = boost::convert(not_int_str, ccnv).value_or(-1); - int const a01 = boost::convert(std_str, ccnv).value_or(-1); - int const a02 = boost::convert(c_str, ccnv).value_or(-1); - int const a03 = boost::convert(wstd_str, wcnv).value_or(-1); - int const a04 = boost::convert(wc_str, wcnv).value_or(-1); - int const a05 = boost::convert(array_str, ccnv).value_or(-1); - - BOOST_TEST(a00 == -1); // Failed conversion - BOOST_TEST(a01 == -11); - BOOST_TEST(a02 == -12); - BOOST_TEST(a03 == -13); - BOOST_TEST(a04 == -14); - BOOST_TEST(a05 == -15); - - //////////////////////////////////////////////////////////////////////////// - // Testing with the fallback value value provided. - // Testing implicit conversion to cnv::optional. - // cnv::optional<> exhibits the SAME behavior, i.e. - // on failure it returns the provided fallback value and DOES NOT THROW. - //////////////////////////////////////////////////////////////////////////// - - boost::cnv::optional r000 = boost::convert(not_int_str, ccnv); - boost::cnv::optional r001 = boost::convert(std_str, ccnv); - boost::cnv::optional r002 = boost::convert(c_str, ccnv); - boost::cnv::optional r003 = boost::convert(wstd_str, wcnv); - boost::cnv::optional r004 = boost::convert(wc_str, wcnv); - boost::cnv::optional r005 = boost::convert(array_str, ccnv); - - BOOST_TEST(!r000); // Failed conversion - BOOST_TEST( r001 && r001.value() == -11); - BOOST_TEST( r002 && r002.value() == -12); - BOOST_TEST( r003 && r003.value() == -13); - BOOST_TEST( r004 && r004.value() == -14); - BOOST_TEST( r005 && r005.value() == -15); - - //////////////////////////////////////////////////////////////////////////// - // Testing without a fallback value provided. - // On failure it throws as there is nothing to return. - // Requires TypeOut to be DefaultConstructible. - //////////////////////////////////////////////////////////////////////////// - - try - { - boost::convert(not_int_str, ccnv).value(); - BOOST_TEST(!"failed to throw"); - } - catch (std::exception&) - { - // Expected behavior: received 'boost::convert failed' exception. All well. - } - int a021 = boost::convert(std_str, ccnv).value(); - int a022 = boost::convert(c_str, ccnv).value(); - int a023 = boost::convert(wstd_str, wcnv).value(); - int a024 = boost::convert(wc_str, wcnv).value(); - int a025 = boost::convert(array_str, ccnv).value(); - - BOOST_TEST(a021 == -11); - BOOST_TEST(a022 == -12); - BOOST_TEST(a023 == -13); - BOOST_TEST(a024 == -14); - BOOST_TEST(a025 == -15); - - //////////////////////////////////////////////////////////////////////////// - // Testing cnv::optional<> interface. - // cnv::optional exhibits the SAME (but delayed) behavior, i.e. - // for failed conversion it throws on an attempt to retrieve the value - // as there is nothing to return. - //////////////////////////////////////////////////////////////////////////// - - cnv::optional const r010 = boost::convert(not_int_str, ccnv); - cnv::optional const r011 = boost::convert(std_str, ccnv); - cnv::optional const r012 = boost::convert(c_str, ccnv); - cnv::optional const r013 = boost::convert(wstd_str, wcnv); - cnv::optional const r014 = boost::convert(wc_str, wcnv); - cnv::optional const r015 = boost::convert(array_str, ccnv); - - BOOST_TEST(!r010); // Failed conversion - BOOST_TEST( r011 && r011.value() == -11); - BOOST_TEST( r012 && r012.value() == -12); - BOOST_TEST( r013 && r013.value() == -13); - BOOST_TEST( r014 && r014.value() == -14); - BOOST_TEST( r015 && r015.value() == -15); - - try - { - r010.value(); // Throws on an attempt to retrieve the value. - BOOST_TEST(!"failed to throw"); - } - catch (std::exception&) - { - // Expected behavior: received 'boost::convert failed' exception. All well. - } -} diff --git a/test/str_to_int.hpp b/test/str_to_int.hpp index 8e7c51e..7043c42 100644 --- a/test/str_to_int.hpp +++ b/test/str_to_int.hpp @@ -10,10 +10,9 @@ void test::str_to_int(Converter const& cnv) { string const not_int_str = "not an int"; - string const std_str = "-11"; - char const* const c_str = "-12"; - char const array_str[] = "-15"; - char const* const container_str = "-16"; + string const std_str = "-11"; + char const* const c_str = "-123"; + char const array_str[] = "3456"; //////////////////////////////////////////////////////////////////////////// // Testing various kinds of string containers. @@ -27,32 +26,27 @@ test::str_to_int(Converter const& cnv) int const a02 = boost::convert(c_str, cnv).value_or(-1); int const a05 = boost::convert(array_str, cnv).value_or(-1); - BOOST_TEST(a00 == -1); // Failed conversion - BOOST_TEST(a01 == -11); - BOOST_TEST(a02 == -12); - BOOST_TEST(a05 == -15); + BOOST_TEST(a00 == -1); // Failed conversion + BOOST_TEST(a01 == -11); + BOOST_TEST(a02 == -123); + BOOST_TEST(a05 == 3456); //////////////////////////////////////////////////////////////////////////// - // Testing with the fallback value value provided. - // Testing implicit conversion to cnv::optional. - // cnv::optional<> exhibits the SAME behavior, i.e. - // on failure it returns the provided fallback value and DOES NOT THROW. + // Testing "optional" //////////////////////////////////////////////////////////////////////////// - boost::cnv::optional r000 = boost::convert(not_int_str, cnv); - boost::cnv::optional r001 = boost::convert(std_str, cnv); - boost::cnv::optional r002 = boost::convert(c_str, cnv); - boost::cnv::optional r005 = boost::convert(array_str, cnv); + boost::cnv::optional const r00 = boost::convert(not_int_str, cnv); + boost::cnv::optional const r01 = boost::convert(std_str, cnv); + boost::cnv::optional const r02 = boost::convert(c_str, cnv); + boost::cnv::optional const r05 = boost::convert(array_str, cnv); - BOOST_TEST(!r000); // Failed conversion - BOOST_TEST( r001 && r001.value() == -11); - BOOST_TEST( r002 && r002.value() == -12); - BOOST_TEST( r005 && r005.value() == -15); + BOOST_TEST(!r00); // Failed conversion + BOOST_TEST( r01 && r01.value() == -11); + BOOST_TEST( r02 && r02.value() == -123); + BOOST_TEST( r05 && r05.value() == 3456); //////////////////////////////////////////////////////////////////////////// - // Testing without a fallback value provided. - // On failure it throws as there is nothing to return. - // Requires TypeOut to be DefaultConstructible. + // Testing value() on invalid result. //////////////////////////////////////////////////////////////////////////// try @@ -64,40 +58,18 @@ test::str_to_int(Converter const& cnv) { // Expected behavior: received 'boost::convert failed' exception. All well. } + //////////////////////////////////////////////////////////////////////////// + // Testing value() on valid result. + //////////////////////////////////////////////////////////////////////////// + int a021 = boost::convert(std_str, cnv).value(); int a022 = boost::convert(c_str, cnv).value(); int a025 = boost::convert(array_str, cnv).value(); - BOOST_TEST(a021 == -11); - BOOST_TEST(a022 == -12); - BOOST_TEST(a025 == -15); + BOOST_TEST(a021 == -11); + BOOST_TEST(a022 == -123); + BOOST_TEST(a025 == 3456); - //////////////////////////////////////////////////////////////////////////// - // Testing cnv::optional<> interface. - // cnv::optional exhibits the SAME (but delayed) behavior, i.e. - // for failed conversion it throws on an attempt to retrieve the value - // as there is nothing to return. - //////////////////////////////////////////////////////////////////////////// - - cnv::optional const r010 = boost::convert(not_int_str, cnv); - cnv::optional const r011 = boost::convert(std_str, cnv); - cnv::optional const r012 = boost::convert(c_str, cnv); - cnv::optional const r015 = boost::convert(array_str, cnv); - - BOOST_TEST(!r010); // Failed conversion - BOOST_TEST( r011 && r011.value() == -11); - BOOST_TEST( r012 && r012.value() == -12); - BOOST_TEST( r015 && r015.value() == -15); - - try - { - r010.value(); // Throws on an attempt to retrieve the value. - BOOST_TEST(!"failed to throw"); - } - catch (std::exception&) - { - // Expected behavior: received 'boost::convert failed' exception. All well. - } // for (int k = INT_MIN; k <= INT_MAX; ++k) // { // string str = boost::convert(k, boost::cnv::strtol()).value(); diff --git a/test/test.hpp b/test/test.hpp index 65fb5aa..858802c 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -16,6 +16,9 @@ #include #include +#undef BOOST_TEST +#define BOOST_TEST BOOST_ASSERT + struct change { typedef change this_type; @@ -63,47 +66,30 @@ struct test #error "Add here." #endif + typedef std::vector ints; + typedef std::vector strings; + static void scratchpad (); static void sfinae (); static void algorithms (); - static void performance (); static void encryption (); static void callables (); static void lcast_converter (); - static void sstream_converter (); - static void sstream_locale (); - static void sstream_manipulators (); + static void sstream (); static void int_to_string (); - static void string_to_int (); static void string_to_bool (); static void user_type (); static void force_in_type (); - static void spirit (); + static void performance (test::strings const&, test::ints const&); + static void spirit (test::strings const&); - template static void str_to_int (Converter const&); - template static void type_to_string (Converter const&); - template static void string_to_type (Converter const&); - template static double performance_string_to_int (Converter const&); + template static void str_to_int (Converter const&); + template static void type_to_string (Converter const&); + template static void string_to_type (Converter const&); + template static void invalid (Converter const&); }; namespace cnv = boost::cnv; namespace arg = boost::cnv::parameter; -template -double -test::performance_string_to_int(Converter const& try_converter) -{ - std::string str = "12345"; - int sum = 0; - double const p1 = clock(); - - for (int k = 0; k < test::num_cycles; ++k) - sum += boost::convert((str[4 - k % 5] = 49 + k % 9, str), try_converter).value(); - - double const p2 = clock(); - int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0); - - return (p2 - p1) / CLOCKS_PER_SEC + use_sum; -} - #endif // BOOST_CONVERT_TEST_HPP diff --git a/test/test_convert.cpp b/test/test_convert.cpp index 479725a..10931e2 100644 --- a/test/test_convert.cpp +++ b/test/test_convert.cpp @@ -1,10 +1,13 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. #include "./test.hpp" #include "./str_to_int.hpp" +#include "./invalid.hpp" +#include +#include using std::string; using std::wstring; @@ -48,33 +51,49 @@ test::force_in_type() int main(int argc, char const* argv[]) { + test::ints ints; + test::strings strings; + boost::random::mt19937 gen; + boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); + + ints .reserve(test::num_cycles); + strings.reserve(test::num_cycles); + + for (int k = 0; k < test::num_cycles; ++k) + { + int v = dist(gen); + + ints .push_back(v); + strings.push_back(boost::lexical_cast(v)); + } example::getting_started(); example::getting_serious(); + test::invalid(boost::cnv::lexical_cast()); +// test::invalid(boost::cnv::cstringstream()); +// test::invalid(boost::cnv::strtol()); +// test::invalid(boost::cnv::printf()); test::scratchpad(); test::sfinae(); test::int_to_string(); - test::string_to_int(); test::string_to_bool(); - test::str_to_int(boost::cnv::cstringstream()); test::str_to_int(boost::cnv::lexical_cast()); + test::str_to_int(boost::cnv::cstringstream()); test::str_to_int(boost::cnv::strtol()); - test::str_to_int(boost::printf_converter()); - test::type_to_string(boost::printf_converter()); + test::str_to_int(boost::cnv::printf()); + test::type_to_string(boost::cnv::printf()); test::string_to_type(boost::cnv::strtol()); - test::string_to_type(boost::printf_converter()); - test::type_to_string(boost::printf_converter()); + test::string_to_type(boost::cnv::printf()); + test::type_to_string(boost::cnv::printf()); test::user_type(); test::force_in_type(); test::lcast_converter(); - test::sstream_converter(); - test::sstream_manipulators(); - test::sstream_locale(); + test::sstream(); test::algorithms(); test::callables(); test::encryption(); - test::performance(); - test::spirit(); + test::performance(strings, ints); + test::spirit(strings); return boost::report_errors(); } diff --git a/test/user_type.cpp b/test/user_type.cpp index b1d0eab..479d554 100644 --- a/test/user_type.cpp +++ b/test/user_type.cpp @@ -1,4 +1,4 @@ -// Boost.Convert library test and usage example +// Boost.Convert test and usage example // Copyright (c) 2009-2014 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.