1// Boost.Convert test and usage example
2// Copyright (c) 2009-2014 Vladimir Batov.
3// Use, modification and distribution are subject to the Boost Software License,
4// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
5
6#include "./test.hpp"
7#include "./prepare.hpp"
8
9#include <boost/convert.hpp>
10#include <boost/convert/stream.hpp>
11#include <boost/convert/printf.hpp>
12#include <boost/convert/strtol.hpp>
13#include <boost/convert/spirit.hpp>
14#include <boost/convert/lexical_cast.hpp>
15#include <boost/detail/lightweight_test.hpp>
16#include <boost/timer/timer.hpp>
17#include <boost/array.hpp>
18#include <boost/random/mersenne_twister.hpp>
19#include <boost/random/uniform_int_distribution.hpp>
20#include <cstdlib>
21#include <cstdio>
22
23using std::string;
24using boost::convert;
25
26namespace cnv = boost::cnv;
27namespace arg = boost::cnv::parameter;
28
29namespace { namespace local
30{
31 template<typename Type>
32 struct array
33 {
34 typedef boost::array<Type, 20> type;
35 };
36 template<typename T> static typename array<T>::type const& get();
37
38 static int const num_cycles = 1000000;
39 int sum = 0;
40
41 struct timer : public boost::timer::cpu_timer
42 {
43 typedef timer this_type;
44 typedef boost::timer::cpu_timer base_type;
45
46 double value() const
47 {
48 boost::timer::cpu_times times = base_type::elapsed();
49 int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0);
50
51 return double(times.user + times.system) / 1000000000 + use_sum;
52 }
53 };
54 template< typename Type, typename Cnv> static double str_to (Cnv const&);
55 template<typename S, typename Type, typename Cnv> static double to_str (Cnv const&);
56
57 template<>
58 local::array<int>::type const&
59 get<int>()
60 {
61 static array<int>::type ints;
62 static bool filled;
63
64 if (!filled)
65 {
66 boost::random::mt19937 gen (::time(timer: 0));
67 boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2,147,483,647
68
69 for (size_t k = 0; k < ints.size(); ++k)
70 ints[k] = dist(gen);
71
72 filled = true;
73 }
74 return ints;
75 }
76 template<>
77 array<long int>::type const&
78 get<long int>()
79 {
80 static array<long int>::type ints;
81 static bool filled;
82
83 if (!filled)
84 {
85 boost::random::mt19937 gen (::time(timer: 0));
86 boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647
87
88 for (size_t k = 0; k < ints.size(); ++k)
89 ints[k] = dist(gen);
90
91 filled = true;
92 }
93 return ints;
94 }
95 template<>
96 array<double>::type const&
97 get<double>()
98 {
99 static array<double>::type dbls;
100 static bool filled;
101
102 if (!filled)
103 {
104 boost::random::mt19937 gen (::time(timer: 0));
105 boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647
106
107 for (size_t k = 0; k < dbls.size(); ++k)
108 dbls[k] = double(dist(gen)) + 0.7654321;
109
110 filled = true;
111 }
112 return dbls;
113 }
114}}
115
116struct raw_str_to_int_spirit
117{
118 int operator()(char const* str) const
119 {
120 char const* beg = str;
121 char const* end = beg + strlen(s: str);
122 int result;
123
124 if (boost::spirit::qi::parse(first&: beg, last: end, expr: boost::spirit::int_, attr&: result))
125 if (beg == end) // ensure the whole string was parsed
126 return result;
127
128 return (BOOST_ASSERT(0), result);
129 }
130};
131
132struct raw_str_to_int_lxcast
133{
134 int operator()(char const* str) const
135 {
136 return boost::lexical_cast<int>(arg: str);
137 }
138};
139
140template<typename Type, typename Converter>
141double
142raw_str_to(Converter const& cnv)
143{
144 local::strings strings = local::get_strs(); // Create strings on the stack
145 int const size = strings.size();
146 local::timer timer;
147
148 for (int t = 0; t < local::num_cycles; ++t)
149 for (int k = 0; k < size; ++k)
150 local::sum += cnv(strings[k].c_str());
151
152 return timer.value();
153}
154
155template<typename Type, typename Converter>
156double
157local::str_to(Converter const& try_converter)
158{
159 local::strings strings = local::get_strs(); // Create strings on the stack
160 int const size = strings.size();
161 local::timer timer;
162
163 for (int t = 0; t < local::num_cycles; ++t)
164 for (int k = 0; k < size; ++k)
165 local::sum += boost::convert<Type>(strings[k].c_str(), try_converter).value();
166
167 return timer.value();
168}
169
170template<typename string_type, typename Type, typename Converter>
171double
172local::to_str(Converter const& try_converter)
173{
174 typedef typename local::array<Type>::type collection;
175
176 collection values = local::get<Type>();
177 int const size = values.size();
178 local::timer timer;
179
180 for (int t = 0; t < local::num_cycles; ++t)
181 for (int k = 0; k < size; ++k)
182 local::sum += *boost::convert<string_type>(Type(values[k]), try_converter).value().begin();
183
184 return timer.value();
185}
186
187template<typename Converter>
188double
189performance_str_to_type(Converter const& try_converter)
190{
191 char const* input[] = { "no", "up", "dn" };
192 local::timer timer;
193
194 for (int k = 0; k < local::num_cycles; ++k)
195 {
196 change chg = boost::convert<change>(input[k % 3], try_converter).value();
197 int res = chg.value();
198
199 BOOST_TEST(res == k % 3);
200
201 local::sum += res; // Make sure chg is not optimized out
202 }
203 return timer.value();
204}
205
206template<typename Converter>
207double
208performance_type_to_str(Converter const& try_converter)
209{
210 boost::array<change, 3> input = {.elems: { change::no, change::up, change::dn }};
211 boost::array<string, 3> results = {.elems: { "no", "up", "dn" }};
212 local::timer timer;
213
214 for (int k = 0; k < local::num_cycles; ++k)
215 {
216 string res = boost::convert<string>(input[k % 3], try_converter).value();
217
218 BOOST_TEST(res == results[k % 3]);
219
220 local::sum += res[0]; // Make sure res is not optimized out
221 }
222 return timer.value();
223}
224
225template<typename Raw, typename Cnv>
226void
227performance_comparative(Raw const& raw, Cnv const& cnv, char const* txt)
228{
229 int const num_tries = 5;
230 double cnv_time = 0;
231 double raw_time = 0;
232
233 for (int k = 0; k < num_tries; ++k) cnv_time += local::str_to<int>(cnv);
234 for (int k = 0; k < num_tries; ++k) raw_time += raw_str_to<int>(raw);
235
236 cnv_time /= num_tries;
237 raw_time /= num_tries;
238
239 double change = 100 * (1 - cnv_time / raw_time);
240
241 printf(format: "str-to-int: %s raw/cnv=%.2f/%.2f seconds (%.2f%%).\n", txt, raw_time, cnv_time, change);
242}
243
244int
245main(int, char const* [])
246{
247 printf(format: "Started performance tests...\n");
248
249 printf(format: "str-to-int: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
250 local::str_to<int>(try_converter: boost::cnv::spirit()),
251 local::str_to<int>(try_converter: boost::cnv::strtol()),
252 local::str_to<int>(try_converter: boost::cnv::lexical_cast()),
253 local::str_to<int>(try_converter: boost::cnv::printf()),
254 local::str_to<int>(try_converter: boost::cnv::cstream()));
255 printf(format: "str-to-lng: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
256 local::str_to<long int>(try_converter: boost::cnv::spirit()),
257 local::str_to<long int>(try_converter: boost::cnv::strtol()),
258 local::str_to<long int>(try_converter: boost::cnv::lexical_cast()),
259 local::str_to<long int>(try_converter: boost::cnv::printf()),
260 local::str_to<long int>(try_converter: boost::cnv::cstream()));
261 printf(format: "str-to-dbl: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
262 local::str_to<double>(try_converter: boost::cnv::spirit()),
263 local::str_to<double>(try_converter: boost::cnv::strtol()),
264 local::str_to<double>(try_converter: boost::cnv::lexical_cast()),
265 local::str_to<double>(try_converter: boost::cnv::printf()),
266 local::str_to<double>(try_converter: boost::cnv::cstream()));
267
268 printf(format: "int-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
269 local::to_str<std::string, int>(try_converter: boost::cnv::spirit()),
270 local::to_str<std::string, int>(try_converter: boost::cnv::strtol()),
271 local::to_str<std::string, int>(try_converter: boost::cnv::lexical_cast()),
272 local::to_str<std::string, int>(try_converter: boost::cnv::printf()),
273 local::to_str<std::string, int>(try_converter: boost::cnv::cstream()));
274 printf(format: "lng-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
275 local::to_str<std::string, long int>(try_converter: boost::cnv::spirit()),
276 local::to_str<std::string, long int>(try_converter: boost::cnv::strtol()),
277 local::to_str<std::string, long int>(try_converter: boost::cnv::lexical_cast()),
278 local::to_str<std::string, long int>(try_converter: boost::cnv::printf()),
279 local::to_str<std::string, long int>(try_converter: boost::cnv::cstream()));
280 printf(format: "dbl-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
281 local::to_str<std::string, double>(try_converter: boost::cnv::spirit()),
282 local::to_str<std::string, double>(try_converter: boost::cnv::strtol()(arg::precision = 6)),
283 local::to_str<std::string, double>(try_converter: boost::cnv::lexical_cast()),
284 local::to_str<std::string, double>(try_converter: boost::cnv::printf()(arg::precision = 6)),
285 local::to_str<std::string, double>(try_converter: boost::cnv::cstream()(arg::precision = 6)));
286
287 printf(format: "str-to-user-type: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n",
288 performance_str_to_type(try_converter: boost::cnv::lexical_cast()),
289 performance_str_to_type(try_converter: boost::cnv::cstream()),
290 performance_str_to_type(try_converter: boost::cnv::strtol()));
291 printf(format: "user-type-to-str: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n",
292 performance_type_to_str(try_converter: boost::cnv::lexical_cast()),
293 performance_type_to_str(try_converter: boost::cnv::cstream()),
294 performance_type_to_str(try_converter: boost::cnv::strtol()));
295
296 //[small_string_results
297 printf(format: "strtol int-to std::string/small-string: %.2f/%.2f seconds.\n",
298 local::to_str<std::string, int>(try_converter: boost::cnv::strtol()),
299 local::to_str< my_string, int>(try_converter: boost::cnv::strtol()));
300 printf(format: "spirit int-to std::string/small-string: %.2f/%.2f seconds.\n",
301 local::to_str<std::string, int>(try_converter: boost::cnv::spirit()),
302 local::to_str< my_string, int>(try_converter: boost::cnv::spirit()));
303 printf(format: "stream int-to std::string/small-string: %.2f/%.2f seconds.\n",
304 local::to_str<std::string, int>(try_converter: boost::cnv::cstream()),
305 local::to_str< my_string, int>(try_converter: boost::cnv::cstream()));
306 //]
307 performance_comparative(raw: raw_str_to_int_spirit(), cnv: boost::cnv::spirit(), txt: "spirit");
308 performance_comparative(raw: raw_str_to_int_lxcast(), cnv: boost::cnv::lexical_cast(), txt: "lxcast");
309
310 return boost::report_errors();
311}
312

source code of boost/libs/convert/test/performance.cpp