• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
7 
8 #if defined(BOOST_CONVERT_IS_NOT_SUPPORTED)
main(int,char const * [])9 int main(int, char const* []) { return 0; }
10 #else
11 
12 #include "./prepare.hpp"
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 
value__anon31a5096a0111::local::timer50         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&
get()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&
get()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&
get()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 {
operator ()raw_str_to_int_spirit122     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 {
operator ()raw_str_to_int_lxcast138     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
raw_str_to(Converter const & cnv)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
str_to(Converter const & try_converter)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
to_str(Converter const & try_converter)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
performance_str_to_type(Converter const & try_converter)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
performance_type_to_str(Converter const & try_converter)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
performance_comparative(Raw const & raw,Cnv const & cnv,char const * txt)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
main(int,char const * [])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 }
316 
317 #endif
318