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