// (C) Copyright Antony Polukhin, 2012-2019. // 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) // See http://www.boost.org/libs/config for most recent version. // // Testing lexical_cast<> performance // #define BOOST_ERROR_CODE_HEADER_ONLY #define BOOST_CHRONO_HEADER_ONLY #include #include #include #include #include // File to output data std::fstream fout; namespace boost { inline std::istream& operator>> (std::istream& in, boost::array& res) { in >> res.begin(); return in; } } template static inline void test_lexical(const InT& in_val) { OutT out_val = boost::lexical_cast(in_val); (void)out_val; } template static inline void test_ss_constr(const InT& in_val) { OutT out_val; std::stringstream ss; ss << in_val; if (ss.fail()) throw std::logic_error("descr"); ss >> out_val; if (ss.fail()) throw std::logic_error("descr"); } template static inline void test_ss_constr(const boost::array& in_val) { OutT out_val; std::stringstream ss; ss << in_val.begin(); if (ss.fail()) throw std::logic_error("descr"); ss >> out_val; if (ss.fail()) throw std::logic_error("descr"); } template static inline void test_ss_noconstr(StringStreamT& ss, const boost::array& in_val) { OutT out_val; ss << in_val.begin(); // ss is an instance of std::stringstream if (ss.fail()) throw std::logic_error("descr"); ss >> out_val; if (ss.fail()) throw std::logic_error("descr"); /* reseting std::stringstream to use it again */ ss.str(std::string()); ss.clear(); } template static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) { OutT out_val; ss << in_val; // ss is an instance of std::stringstream if (ss.fail()) throw std::logic_error("descr"); ss >> out_val; if (ss.fail()) throw std::logic_error("descr"); /* reseting std::stringstream to use it again */ ss.str(std::string()); ss.clear(); } struct structure_sprintf { template static inline void test(BufferT* buffer, const InT& in_val, const char* const conv) { sprintf(buffer, conv, in_val); OutT out_val(buffer); } template static inline void test(BufferT* buffer, const std::string& in_val, const char* const conv) { sprintf(buffer, conv, in_val.c_str()); OutT out_val(buffer); } }; struct structure_sscanf { template static inline void test(BufferT* /*buffer*/, const boost::array& in_val, const char* const conv) { OutT out_val; sscanf(in_val.cbegin(), conv, &out_val); } template static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) { OutT out_val; sscanf(reinterpret_cast(in_val), conv, &out_val); } template static inline void test(BufferT* /*buffer*/, const std::string& in_val, const char* const conv) { OutT out_val; sscanf(in_val.c_str(), conv, &out_val); } template static inline void test(BufferT* /*buffer*/, const boost::iterator_range& in_val, const char* const conv) { OutT out_val; sscanf(in_val.begin(), conv, &out_val); } }; struct structure_fake { template static inline void test(BufferT* /*buffer*/, const InT& /*in_val*/, const char* const /*conv*/) {} }; static const int fake_test_value = 9999; template static inline void min_fancy_output(T v1, T v2, T v3, T v4) { const char beg_mark[] = "!!! *"; const char end_mark[] = "* !!!"; const char no_mark[] = ""; unsigned int res = 4; if (v1 < v2 && v1 < v3 && v1 < v4) res = 1; if (v2 < v1 && v2 < v3 && v2 < v4) res = 2; if (v3 < v1 && v3 < v2 && v3 < v4) res = 3; fout << "[ " << (res == 1 ? beg_mark : no_mark) ; if (v1) fout << v1; else fout << "<1"; fout << (res == 1 ? end_mark : no_mark) << " ][ " << (res == 2 ? beg_mark : no_mark) ; if (v2) fout << v2; else fout << "<1"; fout << (res == 2 ? end_mark : no_mark) << " ][ " << (res == 3 ? beg_mark : no_mark) ; if (v3) fout << v3; else fout << "<1"; fout << (res == 3 ? end_mark : no_mark) << " ][ " << (res == 4 ? beg_mark : no_mark) ; if (!v4) fout << "<1"; else if (v4 == fake_test_value) fout << "---"; else fout << v4; fout << (res == 4 ? end_mark : no_mark) << " ]"; } template static inline void perf_test_impl(const FromT& in_val, const char* const conv) { typedef boost::chrono::steady_clock test_clock; test_clock::time_point start; typedef boost::chrono::milliseconds duration_t; duration_t lexical_cast_time, ss_constr_time, ss_noconstr_time, printf_time; start = test_clock::now(); for (unsigned int i = 0; i < IetartionsCountV; ++i) { test_lexical(in_val); test_lexical(in_val); test_lexical(in_val); test_lexical(in_val); } lexical_cast_time = boost::chrono::duration_cast(test_clock::now() - start); start = test_clock::now(); for (unsigned int i = 0; i < IetartionsCountV; ++i) { test_ss_constr(in_val); test_ss_constr(in_val); test_ss_constr(in_val); test_ss_constr(in_val); } ss_constr_time = boost::chrono::duration_cast(test_clock::now() - start); std::stringstream ss; start = test_clock::now(); for (unsigned int i = 0; i < IetartionsCountV; ++i) { test_ss_noconstr(ss, in_val); test_ss_noconstr(ss, in_val); test_ss_noconstr(ss, in_val); test_ss_noconstr(ss, in_val); } ss_noconstr_time = boost::chrono::duration_cast(test_clock::now() - start); char buffer[128]; start = test_clock::now(); for (unsigned int i = 0; i < IetartionsCountV; ++i) { SprintfT::template test(buffer, in_val, conv); SprintfT::template test(buffer, in_val, conv); SprintfT::template test(buffer, in_val, conv); SprintfT::template test(buffer, in_val, conv); } printf_time = boost::chrono::duration_cast(test_clock::now() - start); min_fancy_output( lexical_cast_time.count(), ss_constr_time.count(), ss_noconstr_time.count(), boost::is_same::value ? fake_test_value : printf_time.count() ); } template static inline void perf_test(const std::string& test_name, const FromT& in_val, const char* const conv) { const unsigned int ITERATIONSCOUNT = 100000; fout << " [[ " << test_name << " ]"; perf_test_impl(in_val, conv); fout << "]\n"; } template void string_like_test_set(const std::string& from) { typedef structure_sscanf ssc_t; ConverterT conv; perf_test(from + "->char", conv("c"), "%c"); perf_test(from + "->signed char", conv("c"), "%hhd"); perf_test(from + "->unsigned char", conv("c"), "%hhu"); perf_test(from + "->int", conv("100"), "%d"); perf_test(from + "->short", conv("100"), "%hd"); perf_test(from + "->long int", conv("100"), "%ld"); perf_test(from + "->long long", conv("100"), "%lld"); perf_test(from + "->unsigned int", conv("100"), "%u"); perf_test(from + "->unsigned short", conv("100"), "%hu"); perf_test(from + "->unsigned long int", conv("100"), "%lu"); perf_test(from + "->unsigned long long", conv("100"), "%llu"); // perf_test(from + "->bool", conv("1"), "%"); perf_test(from + "->float", conv("1.123"), "%f"); perf_test(from + "->double", conv("1.123"), "%lf"); perf_test(from + "->long double", conv("1.123"), "%Lf"); perf_test, ssc_t>(from + "->array", conv("1.123"), "%s"); perf_test(from + "->string", conv("string"), "%Lf"); perf_test(from + "->container::string" , conv("string"), "%Lf"); } struct to_string_conv { std::string operator()(const char* const c) const { return c; } }; struct to_char_conv { const char* operator()(const char* const c) const { return c; } }; struct to_uchar_conv { const unsigned char* operator()(const char* const c) const { return reinterpret_cast(c); } }; struct to_schar_conv { const signed char* operator()(const char* const c) const { return reinterpret_cast(c); } }; struct to_iterator_range { boost::iterator_range operator()(const char* const c) const { return boost::make_iterator_range(c, c + std::strlen(c)); } }; struct to_array_50 { boost::array operator()(const char* const c) const { boost::array ret; std::strcpy(ret.begin(), c); return ret; } }; int main(int argc, char** argv) { BOOST_ASSERT(argc >= 2); std::string output_path(argv[1]); output_path += "/results.txt"; fout.open(output_path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app); BOOST_ASSERT(fout); fout << "[section " << BOOST_COMPILER << "]\n" << "[table:id Performance Table ( "<< BOOST_COMPILER << ")\n" << "[[From->To] [lexical_cast] [std::stringstream with construction] " << "[std::stringstream without construction][scanf/printf]]\n"; // From std::string to ... string_like_test_set("string"); // From ... to std::string perf_test("string->char", 'c', "%c"); perf_test("string->signed char", static_cast('c'), "%hhd"); perf_test("string->unsigned char", static_cast('c'), "%hhu"); perf_test("int->string", 100, "%d"); perf_test("short->string", static_cast(100), "%hd"); perf_test("long int->string", 100l, "%ld"); perf_test("long long->string", 100ll, "%lld"); perf_test("unsigned int->string", static_cast(100u), "%u"); perf_test("unsigned short->string", 100u, "%hu"); perf_test("unsigned long int->string", 100ul, "%lu"); perf_test("unsigned long long->string", static_cast(100), "%llu"); // perf_test("bool->string", std::string("1"), "%"); perf_test("float->string", 1.123f, "%f"); perf_test("double->string", 1.123, "%lf"); perf_test("long double->string", 1.123L, "%Lf"); string_like_test_set("char*"); string_like_test_set("unsigned char*"); string_like_test_set("signed char*"); string_like_test_set("iterator_range"); string_like_test_set("array"); perf_test("int->int", 100, ""); perf_test("float->double", 100.0f, ""); perf_test("char->signed char", 'c', ""); fout << "]\n" << "[endsect]\n\n"; return 0; }