• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  (C) Copyright Antony Polukhin, 2012-2020.
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  See http://www.boost.org/libs/config for most recent version.
7 
8 //
9 // Testing lexical_cast<> performance
10 //
11 
12 #define BOOST_ERROR_CODE_HEADER_ONLY
13 #define BOOST_CHRONO_HEADER_ONLY
14 
15 #include <boost/lexical_cast.hpp>
16 
17 #include <boost/chrono.hpp>
18 #include <fstream>
19 #include <cstring>
20 #include <boost/container/string.hpp>
21 
22 // File to output data
23 std::fstream fout;
24 
25 namespace boost {
operator >>(std::istream & in,boost::array<char,50> & res)26 inline std::istream& operator>> (std::istream& in, boost::array<char,50>& res) {
27     in >> res.begin();
28     return in;
29 }
30 }
31 
32 template <class OutT, class InT>
test_lexical(const InT & in_val)33 static inline void test_lexical(const InT& in_val) {
34     OutT out_val = boost::lexical_cast<OutT>(in_val);
35     (void)out_val;
36 }
37 
38 template <class OutT, class InT>
test_ss_constr(const InT & in_val)39 static inline void test_ss_constr(const InT& in_val) {
40     OutT out_val;
41     std::stringstream ss;
42     ss << in_val;
43     if (ss.fail()) throw std::logic_error("descr");
44     ss >> out_val;
45     if (ss.fail()) throw std::logic_error("descr");
46 }
47 
48 template <class OutT, class CharT, std::size_t N>
test_ss_constr(const boost::array<CharT,N> & in_val)49 static inline void test_ss_constr(const boost::array<CharT, N>& in_val) {
50     OutT out_val;
51     std::stringstream ss;
52     ss << in_val.begin();
53     if (ss.fail()) throw std::logic_error("descr");
54     ss >> out_val;
55     if (ss.fail()) throw std::logic_error("descr");
56 }
57 
58 template <class OutT, class StringStreamT, class CharT, std::size_t N>
test_ss_noconstr(StringStreamT & ss,const boost::array<CharT,N> & in_val)59 static inline void test_ss_noconstr(StringStreamT& ss, const boost::array<CharT, N>& in_val) {
60     OutT out_val;
61     ss << in_val.begin(); // ss is an instance of std::stringstream
62     if (ss.fail()) throw std::logic_error("descr");
63     ss >> out_val;
64     if (ss.fail()) throw std::logic_error("descr");
65     /* reseting std::stringstream to use it again */
66     ss.str(std::string());
67     ss.clear();
68 }
69 
70 template <class OutT, class StringStreamT, class InT>
test_ss_noconstr(StringStreamT & ss,const InT & in_val)71 static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) {
72     OutT out_val;
73     ss << in_val; // ss is an instance of std::stringstream
74     if (ss.fail()) throw std::logic_error("descr");
75     ss >> out_val;
76     if (ss.fail()) throw std::logic_error("descr");
77     /* reseting std::stringstream to use it again */
78     ss.str(std::string());
79     ss.clear();
80 }
81 
82 struct structure_sprintf {
83     template <class OutT, class BufferT, class InT>
teststructure_sprintf84     static inline void test(BufferT* buffer, const InT& in_val, const char* const conv) {
85         sprintf(buffer, conv, in_val);
86         OutT out_val(buffer);
87     }
88 
89     template <class OutT, class BufferT>
teststructure_sprintf90     static inline void test(BufferT* buffer, const std::string& in_val, const char* const conv) {
91         sprintf(buffer, conv, in_val.c_str());
92         OutT out_val(buffer);
93     }
94 };
95 
96 struct structure_sscanf {
97     template <class OutT, class BufferT, class CharT, std::size_t N>
teststructure_sscanf98     static inline void test(BufferT* /*buffer*/, const boost::array<CharT, N>& in_val, const char* const conv) {
99         OutT out_val;
100         sscanf(in_val.cbegin(), conv, &out_val);
101     }
102 
103     template <class OutT, class BufferT, class InT>
teststructure_sscanf104     static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) {
105         OutT out_val;
106         sscanf(reinterpret_cast<const char*>(in_val), conv, &out_val);
107     }
108 
109     template <class OutT, class BufferT>
teststructure_sscanf110     static inline void test(BufferT* /*buffer*/, const std::string& in_val, const char* const conv) {
111         OutT out_val;
112         sscanf(in_val.c_str(), conv, &out_val);
113     }
114 
115     template <class OutT, class BufferT>
teststructure_sscanf116     static inline void test(BufferT* /*buffer*/, const boost::iterator_range<const char*>& in_val, const char* const conv) {
117         OutT out_val;
118         sscanf(in_val.begin(), conv, &out_val);
119     }
120 };
121 
122 struct structure_fake {
123     template <class OutT, class BufferT, class InT>
teststructure_fake124     static inline void test(BufferT* /*buffer*/, const InT& /*in_val*/, const char* const /*conv*/) {}
125 };
126 
127 static const int fake_test_value = 9999;
128 
129 template <class T>
min_fancy_output(T v1,T v2,T v3,T v4)130 static inline void min_fancy_output(T v1, T v2, T v3, T v4) {
131     const char beg_mark[] = "!!! *";
132     const char end_mark[] = "* !!!";
133     const char no_mark[] = "";
134 
135     unsigned int res = 4;
136     if (v1 < v2 && v1 < v3 && v1 < v4) res = 1;
137     if (v2 < v1 && v2 < v3 && v2 < v4) res = 2;
138     if (v3 < v1 && v3 < v2 && v3 < v4) res = 3;
139 
140     fout << "[ "
141          << (res == 1 ? beg_mark : no_mark)
142          ;
143 
144     if (v1) fout << v1;
145     else fout << "<1";
146 
147     fout << (res == 1 ? end_mark : no_mark)
148          << " ][ "
149          << (res == 2 ? beg_mark : no_mark)
150          ;
151 
152        if (v2) fout << v2;
153        else fout << "<1";
154 
155        fout << (res == 2 ? end_mark : no_mark)
156          << " ][ "
157          << (res == 3 ? beg_mark : no_mark)
158          ;
159 
160        if (v3) fout << v3;
161        else fout << "<1";
162 
163        fout << (res == 3 ? end_mark : no_mark)
164          << " ][ "
165          << (res == 4 ? beg_mark : no_mark)
166          ;
167 
168        if (!v4) fout << "<1";
169        else if (v4 == fake_test_value) fout << "---";
170        else fout << v4;
171 
172        fout
173          << (res == 4 ? end_mark : no_mark)
174          << " ]";
175 }
176 
177 template <unsigned int IetartionsCountV, class ToT, class SprintfT, class FromT>
perf_test_impl(const FromT & in_val,const char * const conv)178 static inline void perf_test_impl(const FromT& in_val, const char* const conv) {
179 
180     typedef boost::chrono::steady_clock test_clock;
181     test_clock::time_point start;
182     typedef boost::chrono::milliseconds duration_t;
183     duration_t lexical_cast_time, ss_constr_time, ss_noconstr_time, printf_time;
184 
185     start = test_clock::now();
186     for (unsigned int i = 0; i < IetartionsCountV; ++i) {
187         test_lexical<ToT>(in_val);
188         test_lexical<ToT>(in_val);
189         test_lexical<ToT>(in_val);
190         test_lexical<ToT>(in_val);
191     }
192     lexical_cast_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
193 
194 
195     start = test_clock::now();
196     for (unsigned int i = 0; i < IetartionsCountV; ++i) {
197         test_ss_constr<ToT>(in_val);
198         test_ss_constr<ToT>(in_val);
199         test_ss_constr<ToT>(in_val);
200         test_ss_constr<ToT>(in_val);
201     }
202     ss_constr_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
203 
204     std::stringstream ss;
205     start = test_clock::now();
206     for (unsigned int i = 0; i < IetartionsCountV; ++i) {
207         test_ss_noconstr<ToT>(ss, in_val);
208         test_ss_noconstr<ToT>(ss, in_val);
209         test_ss_noconstr<ToT>(ss, in_val);
210         test_ss_noconstr<ToT>(ss, in_val);
211     }
212     ss_noconstr_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
213 
214 
215     char buffer[128];
216     start = test_clock::now();
217     for (unsigned int i = 0; i < IetartionsCountV; ++i) {
218         SprintfT::template test<ToT>(buffer, in_val, conv);
219         SprintfT::template test<ToT>(buffer, in_val, conv);
220         SprintfT::template test<ToT>(buffer, in_val, conv);
221         SprintfT::template test<ToT>(buffer, in_val, conv);
222     }
223     printf_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
224 
225     min_fancy_output(
226                 lexical_cast_time.count(),
227                 ss_constr_time.count(),
228                 ss_noconstr_time.count(),
229                 boost::is_same<SprintfT, structure_fake>::value ? fake_test_value : printf_time.count()
230     );
231 }
232 
233 template <class ToT, class SprintfT, class FromT>
perf_test(const std::string & test_name,const FromT & in_val,const char * const conv)234 static inline void perf_test(const std::string& test_name, const FromT& in_val, const char* const conv) {
235     const unsigned int ITERATIONSCOUNT = 100000;
236     fout << "  [[ " << test_name << " ]";
237 
238     perf_test_impl<ITERATIONSCOUNT/4, ToT, SprintfT>(in_val, conv);
239 
240     fout << "]\n";
241 }
242 
243 
244 template <class ConverterT>
string_like_test_set(const std::string & from)245 void string_like_test_set(const std::string& from) {
246     typedef structure_sscanf ssc_t;
247     ConverterT conv;
248 
249     perf_test<char, ssc_t>(from + "->char",               conv("c"), "%c");
250     perf_test<signed char, ssc_t>(from + "->signed char", conv("c"), "%hhd");
251     perf_test<unsigned char, ssc_t>(from + "->unsigned char", conv("c"), "%hhu");
252 
253     perf_test<int, ssc_t>(from + "->int",             conv("100"), "%d");
254     perf_test<short, ssc_t>(from + "->short",         conv("100"), "%hd");
255     perf_test<long int, ssc_t>(from + "->long int",   conv("100"), "%ld");
256     perf_test<boost::long_long_type, ssc_t>(from + "->long long", conv("100"), "%lld");
257 
258     perf_test<unsigned int, ssc_t>(from + "->unsigned int",             conv("100"), "%u");
259     perf_test<unsigned short, ssc_t>(from + "->unsigned short",         conv("100"), "%hu");
260     perf_test<unsigned long int, ssc_t>(from + "->unsigned long int",   conv("100"), "%lu");
261     perf_test<boost::ulong_long_type, ssc_t>(from + "->unsigned long long", conv("100"), "%llu");
262 
263     // perf_test<bool, ssc_t>(from + "->bool", conv("1"), "%");
264 
265     perf_test<float, ssc_t>(from + "->float",             conv("1.123"), "%f");
266     perf_test<double, ssc_t>(from + "->double",           conv("1.123"), "%lf");
267     perf_test<long double, ssc_t>(from + "->long double", conv("1.123"), "%Lf");
268     perf_test<boost::array<char, 50>, ssc_t>(from + "->array<char, 50>", conv("1.123"), "%s");
269 
270     perf_test<std::string, structure_fake>(from + "->string", conv("string"), "%Lf");
271     perf_test<boost::container::string, structure_fake>(from + "->container::string"
272                                                         , conv("string"), "%Lf");
273 
274 }
275 
276 struct to_string_conv {
operator ()to_string_conv277     std::string operator()(const char* const c) const {
278         return c;
279     }
280 };
281 
282 struct to_char_conv {
operator ()to_char_conv283     const char*  operator()(const char* const c) const {
284         return c;
285     }
286 };
287 
288 struct to_uchar_conv {
operator ()to_uchar_conv289     const unsigned char*  operator()(const char* const c) const {
290         return reinterpret_cast<const unsigned char*>(c);
291     }
292 };
293 
294 
295 struct to_schar_conv {
operator ()to_schar_conv296     const signed char*  operator()(const char* const c) const {
297         return reinterpret_cast<const signed char*>(c);
298     }
299 };
300 
301 struct to_iterator_range {
operator ()to_iterator_range302     boost::iterator_range<const char*>  operator()(const char* const c) const {
303         return boost::make_iterator_range(c, c + std::strlen(c));
304     }
305 };
306 
307 struct to_array_50 {
operator ()to_array_50308     boost::array<char, 50> operator()(const char* const c) const {
309         boost::array<char, 50> ret;
310         std::strcpy(ret.begin(), c);
311         return ret;
312     }
313 };
314 
main(int argc,char ** argv)315 int main(int argc, char** argv) {
316     BOOST_ASSERT(argc >= 2);
317     std::string output_path(argv[1]);
318     output_path += "/results.txt";
319     fout.open(output_path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
320     BOOST_ASSERT(fout);
321 
322     fout << "[section " << BOOST_COMPILER << "]\n"
323         << "[table:id Performance Table ( "<< BOOST_COMPILER << ")\n"
324         << "[[From->To] [lexical_cast] [std::stringstream with construction] "
325         << "[std::stringstream without construction][scanf/printf]]\n";
326 
327 
328     // From std::string to ...
329     string_like_test_set<to_string_conv>("string");
330 
331     // From ... to std::string
332     perf_test<std::string, structure_sprintf>("string->char",                'c', "%c");
333     perf_test<std::string, structure_sprintf>("string->signed char",     static_cast<signed char>('c'), "%hhd");
334     perf_test<std::string, structure_sprintf>("string->unsigned char", static_cast<unsigned char>('c'), "%hhu");
335 
336     perf_test<std::string, structure_sprintf>("int->string",                 100, "%d");
337     perf_test<std::string, structure_sprintf>("short->string",               static_cast<short>(100), "%hd");
338     perf_test<std::string, structure_sprintf>("long int->string",            100l, "%ld");
339     perf_test<std::string, structure_sprintf>("long long->string",           100ll, "%lld");
340 
341     perf_test<std::string, structure_sprintf>("unsigned int->string",        static_cast<unsigned short>(100u), "%u");
342     perf_test<std::string, structure_sprintf>("unsigned short->string",      100u, "%hu");
343     perf_test<std::string, structure_sprintf>("unsigned long int->string",   100ul, "%lu");
344     perf_test<std::string, structure_sprintf>("unsigned long long->string",  static_cast<boost::ulong_long_type>(100), "%llu");
345 
346     // perf_test<bool, structure_sscanf>("bool->string", std::string("1"), "%");
347 
348     perf_test<std::string, structure_sprintf>("float->string",       1.123f, "%f");
349     perf_test<std::string, structure_sprintf>("double->string",      1.123, "%lf");
350     perf_test<std::string, structure_sprintf>("long double->string", 1.123L, "%Lf");
351 
352 
353     string_like_test_set<to_char_conv>("char*");
354     string_like_test_set<to_uchar_conv>("unsigned char*");
355     string_like_test_set<to_schar_conv>("signed char*");
356     string_like_test_set<to_iterator_range>("iterator_range<char*>");
357     string_like_test_set<to_array_50>("array<char, 50>");
358 
359     perf_test<int, structure_fake>("int->int", 100, "");
360     perf_test<double, structure_fake>("float->double", 100.0f, "");
361     perf_test<signed char, structure_fake>("char->signed char", 'c', "");
362 
363 
364     fout << "]\n"
365         << "[endsect]\n\n";
366     return 0;
367 }
368 
369 
370