// Boost.Convert test and usage example // Copyright (c) 2009-2016 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" #if defined(BOOST_CONVERT_IS_NOT_SUPPORTED) int main(int, char const* []) { return 0; } #else #include "./prepare.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using boost::convert; namespace cnv = boost::cnv; namespace arg = boost::cnv::parameter; namespace { namespace local { template struct array { typedef boost::array type; }; template static typename array::type const& get(); static int const num_cycles = 1000000; int sum = 0; struct timer : public boost::timer::cpu_timer { typedef timer this_type; typedef boost::timer::cpu_timer base_type; double value() const { boost::timer::cpu_times times = base_type::elapsed(); int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0); return double(times.user + times.system) / 1000000000 + use_sum; } }; template< typename Type, typename Cnv> static double str_to (Cnv const&); template static double to_str (Cnv const&); template<> local::array::type const& get() { static array::type ints; static bool filled; if (!filled) { boost::random::mt19937 gen (::time(0)); boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2,147,483,647 for (size_t k = 0; k < ints.size(); ++k) ints[k] = dist(gen); filled = true; } return ints; } template<> array::type const& get() { static array::type ints; static bool filled; if (!filled) { boost::random::mt19937 gen (::time(0)); boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647 for (size_t k = 0; k < ints.size(); ++k) ints[k] = dist(gen); filled = true; } return ints; } template<> array::type const& get() { static array::type dbls; static bool filled; if (!filled) { boost::random::mt19937 gen (::time(0)); boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647 for (size_t k = 0; k < dbls.size(); ++k) dbls[k] = double(dist(gen)) + 0.7654321; filled = true; } return dbls; } }} struct raw_str_to_int_spirit { int operator()(char const* str) const { char const* beg = str; char const* end = beg + strlen(str); int result; if (boost::spirit::qi::parse(beg, end, boost::spirit::int_, result)) if (beg == end) // ensure the whole string was parsed return result; return (BOOST_ASSERT(0), result); } }; struct raw_str_to_int_lxcast { int operator()(char const* str) const { return boost::lexical_cast(str); } }; template double raw_str_to(Converter const& cnv) { local::strings strings = local::get_strs(); // Create strings on the stack int const size = strings.size(); local::timer timer; for (int t = 0; t < local::num_cycles; ++t) for (int k = 0; k < size; ++k) local::sum += cnv(strings[k].c_str()); return timer.value(); } template double local::str_to(Converter const& try_converter) { local::strings strings = local::get_strs(); // Create strings on the stack int const size = strings.size(); local::timer timer; for (int t = 0; t < local::num_cycles; ++t) for (int k = 0; k < size; ++k) local::sum += boost::convert(strings[k].c_str(), try_converter).value(); return timer.value(); } template double local::to_str(Converter const& try_converter) { typedef typename local::array::type collection; collection values = local::get(); int const size = values.size(); local::timer timer; for (int t = 0; t < local::num_cycles; ++t) for (int k = 0; k < size; ++k) local::sum += *boost::convert(Type(values[k]), try_converter).value().begin(); return timer.value(); } template double performance_str_to_type(Converter const& try_converter) { char const* input[] = { "no", "up", "dn" }; local::timer timer; for (int k = 0; k < local::num_cycles; ++k) { change chg = boost::convert(input[k % 3], try_converter).value(); int res = chg.value(); BOOST_TEST(res == k % 3); local::sum += res; // Make sure chg is not optimized out } return timer.value(); } template double performance_type_to_str(Converter const& try_converter) { boost::array input = {{ change::no, change::up, change::dn }}; boost::array results = {{ "no", "up", "dn" }}; local::timer timer; for (int k = 0; k < local::num_cycles; ++k) { string res = boost::convert(input[k % 3], try_converter).value(); BOOST_TEST(res == results[k % 3]); local::sum += res[0]; // Make sure res is not optimized out } return timer.value(); } template void performance_comparative(Raw const& raw, Cnv const& cnv, char const* txt) { int const num_tries = 5; double cnv_time = 0; double raw_time = 0; for (int k = 0; k < num_tries; ++k) cnv_time += local::str_to(cnv); for (int k = 0; k < num_tries; ++k) raw_time += raw_str_to(raw); cnv_time /= num_tries; raw_time /= num_tries; double change = 100 * (1 - cnv_time / raw_time); printf("str-to-int: %s raw/cnv=%.2f/%.2f seconds (%.2f%%).\n", txt, raw_time, cnv_time, change); } int main(int, char const* []) { printf("Started performance tests...\n"); printf("str-to-int: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::str_to(boost::cnv::spirit()), local::str_to(boost::cnv::strtol()), local::str_to(boost::cnv::lexical_cast()), local::str_to(boost::cnv::printf()), local::str_to(boost::cnv::cstream())); printf("str-to-lng: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::str_to(boost::cnv::spirit()), local::str_to(boost::cnv::strtol()), local::str_to(boost::cnv::lexical_cast()), local::str_to(boost::cnv::printf()), local::str_to(boost::cnv::cstream())); printf("str-to-dbl: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::str_to(boost::cnv::spirit()), local::str_to(boost::cnv::strtol()), local::str_to(boost::cnv::lexical_cast()), local::str_to(boost::cnv::printf()), local::str_to(boost::cnv::cstream())); printf("int-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::to_str(boost::cnv::spirit()), local::to_str(boost::cnv::strtol()), local::to_str(boost::cnv::lexical_cast()), local::to_str(boost::cnv::printf()), local::to_str(boost::cnv::cstream())); printf("lng-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::to_str(boost::cnv::spirit()), local::to_str(boost::cnv::strtol()), local::to_str(boost::cnv::lexical_cast()), local::to_str(boost::cnv::printf()), local::to_str(boost::cnv::cstream())); printf("dbl-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n", local::to_str(boost::cnv::spirit()), local::to_str(boost::cnv::strtol()(arg::precision = 6)), local::to_str(boost::cnv::lexical_cast()), local::to_str(boost::cnv::printf()(arg::precision = 6)), local::to_str(boost::cnv::cstream()(arg::precision = 6))); printf("str-to-user-type: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n", performance_str_to_type(boost::cnv::lexical_cast()), performance_str_to_type(boost::cnv::cstream()), performance_str_to_type(boost::cnv::strtol())); printf("user-type-to-str: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n", performance_type_to_str(boost::cnv::lexical_cast()), performance_type_to_str(boost::cnv::cstream()), performance_type_to_str(boost::cnv::strtol())); //[small_string_results printf("strtol int-to std::string/small-string: %.2f/%.2f seconds.\n", local::to_str(boost::cnv::strtol()), local::to_str< my_string, int>(boost::cnv::strtol())); printf("spirit int-to std::string/small-string: %.2f/%.2f seconds.\n", local::to_str(boost::cnv::spirit()), local::to_str< my_string, int>(boost::cnv::spirit())); printf("stream int-to std::string/small-string: %.2f/%.2f seconds.\n", local::to_str(boost::cnv::cstream()), local::to_str< my_string, int>(boost::cnv::cstream())); //] performance_comparative(raw_str_to_int_spirit(), boost::cnv::spirit(), "spirit"); performance_comparative(raw_str_to_int_lxcast(), boost::cnv::lexical_cast(), "lxcast"); return boost::report_errors(); } #endif