// 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 "./timer.hpp" #include #include #include #include #include #include #include using std::string; using boost::convert; namespace cnv = boost::cnv; namespace arg = boost::cnv::parameter; struct 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 str_to_int_lxcast { int operator()(char const* str) const { return boost::lexical_cast(str); } }; template double performance_str_to_int(Converter const& cnv) { test::cnv::strings strings = test::cnv::get_strs(); // Create strings on the stack int const size = strings.size(); int sum = 0; test::cnv::timer timer (sum); for (int t = 0; t < test::cnv::num_cycles; ++t) for (int k = 0; k < size; ++k) sum += cnv(strings[k].c_str()); return timer.value(); } template double test::performance::str_to(Converter const& try_converter) { test::cnv::strings strings = test::cnv::get_strs(); // Create strings on the stack int const size = strings.size(); int sum = 0; test::cnv::timer timer (sum); for (int t = 0; t < test::cnv::num_cycles; ++t) for (int k = 0; k < size; ++k) sum += boost::convert(strings[k].c_str(), try_converter).value(); return timer.value(); } template double test::performance::to_str(Converter const& try_converter) { typedef typename test::cnv::array::type collection; collection values = test::cnv::get(); int const size = values.size(); int sum = 0; test::cnv::timer timer (sum); for (int t = 0; t < test::cnv::num_cycles; ++t) for (int k = 0; k < size; ++k) sum += boost::convert(Type(values[k]), try_converter).value()[0]; return timer.value(); } template double performance_str_to_type(Converter const& try_converter) { char const* input[] = { "no", "up", "dn" }; int sum = 0; test::cnv::timer timer (sum); for (int k = 0; k < test::cnv::num_cycles; ++k) { change chg = boost::convert(input[k % 3], try_converter).value(); int res = chg.value(); BOOST_TEST(res == k % 3); 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" }}; int sum = 0; test::cnv::timer timer (sum); for (int k = 0; k < test::cnv::num_cycles; ++k) { string res = boost::convert(input[k % 3], try_converter).value(); BOOST_TEST(res == results[k % 3]); 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; double change = 0; for (int k = 0; k < num_tries; ++k) { raw_time += performance_str_to_int(raw); cnv_time += test::performance::str_to(cnv); change += 100 * (1 - cnv_time / raw_time); } cnv_time /= num_tries; raw_time /= num_tries; change /= num_tries; printf("str-to-int: %s raw/cnv=%.2f/%.2f seconds (%.2f%%).\n", txt, raw_time, cnv_time, change); } static void performance_comparative() { performance_comparative(str_to_int_spirit(), boost::cnv::spirit(), "spirit"); performance_comparative(str_to_int_lxcast(), boost::cnv::lexical_cast(), "lxcast"); } void test::cnv::performance() { printf("Started performance tests...\n"); printf("str-to-int: spirit/strtoi/lcast/scanf/stream=%8.2f/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", performance::str_to(boost::cnv::spirit()), performance::str_to(boost::cnv::strtol()), performance::str_to(boost::cnv::lexical_cast()), performance::str_to(boost::cnv::printf()), performance::str_to(boost::cnv::cstream())); printf("str-to-lng: spirit/strtol/lcast/scanf/stream=%8.2f/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", performance::str_to(boost::cnv::spirit()), performance::str_to(boost::cnv::strtol()), performance::str_to(boost::cnv::lexical_cast()), performance::str_to(boost::cnv::printf()), performance::str_to(boost::cnv::cstream())); printf("str-to-dbl: spirit/strtod/lcast/scanf/stream= NA/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", // performance::str_to(boost::cnv::spirit()), performance::str_to(boost::cnv::strtol()), performance::str_to(boost::cnv::lexical_cast()), performance::str_to(boost::cnv::printf()), performance::str_to(boost::cnv::cstream())); printf("int-to-str: spirit/itostr/lcast/prntf/stream=%8.2f/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", performance::to_str(boost::cnv::spirit()), performance::to_str(boost::cnv::strtol()), performance::to_str(boost::cnv::lexical_cast()), performance::to_str(boost::cnv::printf()), performance::to_str(boost::cnv::cstream())); printf("lng-to-str: spirit/ltostr/lcast/prntf/stream=%8.2f/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", performance::to_str(boost::cnv::spirit()), performance::to_str(boost::cnv::strtol()), performance::to_str(boost::cnv::lexical_cast()), performance::to_str(boost::cnv::printf()), performance::to_str(boost::cnv::cstream())); printf("dbl-to-str: spirit/dtostr/lcast/prntf/stream= NA/%8.2f/%8.2f/%8.2f/%8.2f seconds.\n", // performance::to_str(boost::cnv::spirit()), performance::to_str(boost::cnv::strtol()(arg::precision = 6)), performance::to_str(boost::cnv::lexical_cast()), performance::to_str(boost::cnv::printf()(arg::precision = 6)), performance::to_str(boost::cnv::cstream()(arg::precision = 6))); printf("str-to-user-type: lcast/stream=%.2f/%.2f seconds.\n", performance_str_to_type(boost::cnv::lexical_cast()), performance_str_to_type(boost::cnv::cstream())); printf("user-type-to-str: lcast/stream=%.2f/%.2f seconds.\n", performance_type_to_str(boost::cnv::lexical_cast()), performance_type_to_str(boost::cnv::cstream())); if (0) { performance_comparative(); } }