1 // (C) Copyright Antony Polukhin, 2012-2022.
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)
6 // See http://www.boost.org/libs/config for most recent version.
9 // Testing lexical_cast<> performance
12 #define BOOST_ERROR_CODE_HEADER_ONLY
13 #define BOOST_CHRONO_HEADER_ONLY
15 #include <boost/lexical_cast.hpp>
17 #include <boost/chrono.hpp>
20 #include <boost/container/string.hpp>
22 // File to output data
26 inline std::istream
& operator>> (std::istream
& in
, boost::array
<char,50>& res
) {
32 template <class OutT
, class InT
>
33 static inline void test_lexical(const InT
& in_val
) {
34 OutT out_val
= boost::lexical_cast
<OutT
>(in_val
);
38 template <class OutT
, class InT
>
39 static inline void test_ss_constr(const InT
& in_val
) {
43 if (ss
.fail()) throw std::logic_error("descr");
45 if (ss
.fail()) throw std::logic_error("descr");
48 template <class OutT
, class CharT
, std::size_t N
>
49 static inline void test_ss_constr(const boost::array
<CharT
, N
>& in_val
) {
53 if (ss
.fail()) throw std::logic_error("descr");
55 if (ss
.fail()) throw std::logic_error("descr");
58 template <class OutT
, class StringStreamT
, class CharT
, std::size_t N
>
59 static inline void test_ss_noconstr(StringStreamT
& ss
, const boost::array
<CharT
, N
>& in_val
) {
61 ss
<< in_val
.begin(); // ss is an instance of std::stringstream
62 if (ss
.fail()) throw std::logic_error("descr");
64 if (ss
.fail()) throw std::logic_error("descr");
65 /* reseting std::stringstream to use it again */
66 ss
.str(std::string());
70 template <class OutT
, class StringStreamT
, class InT
>
71 static inline void test_ss_noconstr(StringStreamT
& ss
, const InT
& in_val
) {
73 ss
<< in_val
; // ss is an instance of std::stringstream
74 if (ss
.fail()) throw std::logic_error("descr");
76 if (ss
.fail()) throw std::logic_error("descr");
77 /* reseting std::stringstream to use it again */
78 ss
.str(std::string());
82 struct structure_sprintf
{
83 template <class OutT
, class BufferT
, class InT
>
84 static inline void test(BufferT
* buffer
, const InT
& in_val
, const char* const conv
) {
85 sprintf(buffer
, conv
, in_val
);
89 template <class OutT
, class BufferT
>
90 static inline void test(BufferT
* buffer
, const std::string
& in_val
, const char* const conv
) {
91 sprintf(buffer
, conv
, in_val
.c_str());
96 struct structure_sscanf
{
97 template <class OutT
, class BufferT
, class CharT
, std::size_t N
>
98 static inline void test(BufferT
* /*buffer*/, const boost::array
<CharT
, N
>& in_val
, const char* const conv
) {
100 sscanf(in_val
.cbegin(), conv
, &out_val
);
103 template <class OutT
, class BufferT
, class InT
>
104 static inline void test(BufferT
* /*buffer*/, const InT
& in_val
, const char* const conv
) {
106 sscanf(reinterpret_cast<const char*>(in_val
), conv
, &out_val
);
109 template <class OutT
, class BufferT
>
110 static inline void test(BufferT
* /*buffer*/, const std::string
& in_val
, const char* const conv
) {
112 sscanf(in_val
.c_str(), conv
, &out_val
);
115 template <class OutT
, class BufferT
>
116 static inline void test(BufferT
* /*buffer*/, const boost::iterator_range
<const char*>& in_val
, const char* const conv
) {
118 sscanf(in_val
.begin(), conv
, &out_val
);
122 struct structure_fake
{
123 template <class OutT
, class BufferT
, class InT
>
124 static inline void test(BufferT
* /*buffer*/, const InT
& /*in_val*/, const char* const /*conv*/) {}
127 static const int fake_test_value
= 9999;
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
[] = "";
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;
141 << (res
== 1 ? beg_mark
: no_mark
)
147 fout
<< (res
== 1 ? end_mark
: no_mark
)
149 << (res
== 2 ? beg_mark
: no_mark
)
155 fout
<< (res
== 2 ? end_mark
: no_mark
)
157 << (res
== 3 ? beg_mark
: no_mark
)
163 fout
<< (res
== 3 ? end_mark
: no_mark
)
165 << (res
== 4 ? beg_mark
: no_mark
)
168 if (!v4
) fout
<< "<1";
169 else if (v4
== fake_test_value
) fout
<< "---";
173 << (res
== 4 ? end_mark
: no_mark
)
177 template <unsigned int IetartionsCountV
, class ToT
, class SprintfT
, class FromT
>
178 static inline void perf_test_impl(const FromT
& in_val
, const char* const conv
) {
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
;
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
);
192 lexical_cast_time
= boost::chrono::duration_cast
<duration_t
>(test_clock::now() - start
);
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
);
202 ss_constr_time
= boost::chrono::duration_cast
<duration_t
>(test_clock::now() - start
);
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
);
212 ss_noconstr_time
= boost::chrono::duration_cast
<duration_t
>(test_clock::now() - start
);
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
);
223 printf_time
= boost::chrono::duration_cast
<duration_t
>(test_clock::now() - start
);
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()
233 template <class ToT
, class SprintfT
, class FromT
>
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
<< " ]";
238 perf_test_impl
<ITERATIONSCOUNT
/4, ToT
, SprintfT
>(in_val
, conv
);
244 template <class ConverterT
>
245 void string_like_test_set(const std::string
& from
) {
246 typedef structure_sscanf ssc_t
;
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");
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");
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");
263 // perf_test<bool, ssc_t>(from + "->bool", conv("1"), "%");
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");
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");
276 struct to_string_conv
{
277 std::string
operator()(const char* const c
) const {
282 struct to_char_conv
{
283 const char* operator()(const char* const c
) const {
288 struct to_uchar_conv
{
289 const unsigned char* operator()(const char* const c
) const {
290 return reinterpret_cast<const unsigned char*>(c
);
295 struct to_schar_conv
{
296 const signed char* operator()(const char* const c
) const {
297 return reinterpret_cast<const signed char*>(c
);
301 struct to_iterator_range
{
302 boost::iterator_range
<const char*> operator()(const char* const c
) const {
303 return boost::make_iterator_range(c
, c
+ std::strlen(c
));
308 boost::array
<char, 50> operator()(const char* const c
) const {
309 boost::array
<char, 50> ret
;
310 std::strcpy(ret
.begin(), c
);
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
);
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";
328 // From std::string to ...
329 string_like_test_set
<to_string_conv
>("string");
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");
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");
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");
346 // perf_test<bool, structure_sscanf>("bool->string", std::string("1"), "%");
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");
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>");
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', "");