1 | /* |
---|
2 | * |
---|
3 | * Copyright (c) 2002-2003 |
---|
4 | * John Maddock |
---|
5 | * |
---|
6 | * Use, modification and distribution are subject to the |
---|
7 | * Boost Software License, Version 1.0. (See accompanying file |
---|
8 | * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
9 | * |
---|
10 | */ |
---|
11 | |
---|
12 | #include <iostream> |
---|
13 | #include <iomanip> |
---|
14 | #include <fstream> |
---|
15 | #include <deque> |
---|
16 | #include <sstream> |
---|
17 | #include <stdexcept> |
---|
18 | #include <iterator> |
---|
19 | #include <boost/regex.hpp> |
---|
20 | #include <boost/version.hpp> |
---|
21 | #include "regex_comparison.hpp" |
---|
22 | |
---|
23 | #ifdef BOOST_HAS_PCRE |
---|
24 | #include "pcre.h" // for pcre version number |
---|
25 | #endif |
---|
26 | |
---|
27 | // |
---|
28 | // globals: |
---|
29 | // |
---|
30 | bool time_boost = false; |
---|
31 | bool time_localised_boost = false; |
---|
32 | bool time_greta = false; |
---|
33 | bool time_safe_greta = false; |
---|
34 | bool time_posix = false; |
---|
35 | bool time_pcre = false; |
---|
36 | bool time_xpressive = false; |
---|
37 | |
---|
38 | bool test_matches = false; |
---|
39 | bool test_code = false; |
---|
40 | bool test_html = false; |
---|
41 | bool test_short_twain = false; |
---|
42 | bool test_long_twain = false; |
---|
43 | |
---|
44 | |
---|
45 | std::string html_template_file; |
---|
46 | std::string html_out_file; |
---|
47 | std::string html_contents; |
---|
48 | std::list<results> result_list; |
---|
49 | |
---|
50 | // the following let us compute averages: |
---|
51 | double greta_total = 0; |
---|
52 | double safe_greta_total = 0; |
---|
53 | double boost_total = 0; |
---|
54 | double locale_boost_total = 0; |
---|
55 | double posix_total = 0; |
---|
56 | double pcre_total = 0; |
---|
57 | unsigned greta_test_count = 0; |
---|
58 | unsigned safe_greta_test_count = 0; |
---|
59 | unsigned boost_test_count = 0; |
---|
60 | unsigned locale_boost_test_count = 0; |
---|
61 | unsigned posix_test_count = 0; |
---|
62 | unsigned pcre_test_count = 0; |
---|
63 | |
---|
64 | int handle_argument(const std::string& what) |
---|
65 | { |
---|
66 | if(what == "-b") |
---|
67 | time_boost = true; |
---|
68 | else if(what == "-bl") |
---|
69 | time_localised_boost = true; |
---|
70 | #ifdef BOOST_HAS_GRETA |
---|
71 | else if(what == "-g") |
---|
72 | time_greta = true; |
---|
73 | else if(what == "-gs") |
---|
74 | time_safe_greta = true; |
---|
75 | #endif |
---|
76 | #ifdef BOOST_HAS_POSIX |
---|
77 | else if(what == "-posix") |
---|
78 | time_posix = true; |
---|
79 | #endif |
---|
80 | #ifdef BOOST_HAS_PCRE |
---|
81 | else if(what == "-pcre") |
---|
82 | time_pcre = true; |
---|
83 | #endif |
---|
84 | #ifdef BOOST_HAS_XPRESSIVE |
---|
85 | else if(what == "-xpressive") |
---|
86 | time_xpressive = true; |
---|
87 | #endif |
---|
88 | else if(what == "-all") |
---|
89 | { |
---|
90 | time_boost = true; |
---|
91 | time_localised_boost = true; |
---|
92 | #ifdef BOOST_HAS_GRETA |
---|
93 | time_greta = true; |
---|
94 | time_safe_greta = true; |
---|
95 | #endif |
---|
96 | #ifdef BOOST_HAS_POSIX |
---|
97 | time_posix = true; |
---|
98 | #endif |
---|
99 | #ifdef BOOST_HAS_PCRE |
---|
100 | time_pcre = true; |
---|
101 | #endif |
---|
102 | } |
---|
103 | else if(what == "-test-matches") |
---|
104 | test_matches = true; |
---|
105 | else if(what == "-test-code") |
---|
106 | test_code = true; |
---|
107 | else if(what == "-test-html") |
---|
108 | test_html = true; |
---|
109 | else if(what == "-test-short-twain") |
---|
110 | test_short_twain = true; |
---|
111 | else if(what == "-test-long-twain") |
---|
112 | test_long_twain = true; |
---|
113 | else if(what == "-test-all") |
---|
114 | { |
---|
115 | test_matches = true; |
---|
116 | test_code = true; |
---|
117 | test_html = true; |
---|
118 | test_short_twain = true; |
---|
119 | test_long_twain = true; |
---|
120 | } |
---|
121 | else if((what == "-h") || (what == "--help")) |
---|
122 | return show_usage(); |
---|
123 | else if((what[0] == '-') || (what[0] == '/')) |
---|
124 | { |
---|
125 | std::cerr << "Unknown argument: \"" << what << "\"" << std::endl; |
---|
126 | return 1; |
---|
127 | } |
---|
128 | else if(html_template_file.size() == 0) |
---|
129 | { |
---|
130 | html_template_file = what; |
---|
131 | load_file(html_contents, what.c_str()); |
---|
132 | } |
---|
133 | else if(html_out_file.size() == 0) |
---|
134 | html_out_file = what; |
---|
135 | else |
---|
136 | { |
---|
137 | std::cerr << "Unexpected argument: \"" << what << "\"" << std::endl; |
---|
138 | return 1; |
---|
139 | } |
---|
140 | return 0; |
---|
141 | } |
---|
142 | |
---|
143 | int show_usage() |
---|
144 | { |
---|
145 | std::cout << |
---|
146 | "Usage\n" |
---|
147 | "regex_comparison [-h] [library options] [test options] [html_template html_output_file]\n" |
---|
148 | " -h Show help\n\n" |
---|
149 | " library options:\n" |
---|
150 | " -b Apply tests to boost library\n" |
---|
151 | " -bl Apply tests to boost library with C++ locale\n" |
---|
152 | #ifdef BOOST_HAS_GRETA |
---|
153 | " -g Apply tests to GRETA library\n" |
---|
154 | " -gs Apply tests to GRETA library (in non-recursive mode)\n" |
---|
155 | #endif |
---|
156 | #ifdef BOOST_HAS_POSIX |
---|
157 | " -posix Apply tests to POSIX library\n" |
---|
158 | #endif |
---|
159 | #ifdef BOOST_HAS_PCRE |
---|
160 | " -pcre Apply tests to PCRE library\n" |
---|
161 | #endif |
---|
162 | " -all Apply tests to all libraries\n\n" |
---|
163 | " test options:\n" |
---|
164 | " -test-matches Test short matches\n" |
---|
165 | " -test-code Test c++ code examples\n" |
---|
166 | " -test-html Test c++ code examples\n" |
---|
167 | " -test-short-twain Test short searches\n" |
---|
168 | " -test-long-twain Test long searches\n" |
---|
169 | " -test-all Test everthing\n"; |
---|
170 | return 1; |
---|
171 | } |
---|
172 | |
---|
173 | void load_file(std::string& text, const char* file) |
---|
174 | { |
---|
175 | std::deque<char> temp_copy; |
---|
176 | std::ifstream is(file); |
---|
177 | if(!is.good()) |
---|
178 | { |
---|
179 | std::string msg("Unable to open file: \""); |
---|
180 | msg.append(file); |
---|
181 | msg.append("\""); |
---|
182 | throw std::runtime_error(msg); |
---|
183 | } |
---|
184 | is.seekg(0, std::ios_base::end); |
---|
185 | std::istream::pos_type pos = is.tellg(); |
---|
186 | is.seekg(0, std::ios_base::beg); |
---|
187 | text.erase(); |
---|
188 | text.reserve(pos); |
---|
189 | std::istreambuf_iterator<char> it(is); |
---|
190 | std::copy(it, std::istreambuf_iterator<char>(), std::back_inserter(text)); |
---|
191 | } |
---|
192 | |
---|
193 | void print_result(std::ostream& os, double time, double best) |
---|
194 | { |
---|
195 | static const char* suffixes[] = {"s", "ms", "us", "ns", "ps", }; |
---|
196 | |
---|
197 | if(time < 0) |
---|
198 | { |
---|
199 | os << "<td>NA</td>"; |
---|
200 | return; |
---|
201 | } |
---|
202 | double rel = time / best; |
---|
203 | bool highlight = ((rel > 0) && (rel < 1.1)); |
---|
204 | unsigned suffix = 0; |
---|
205 | while(time < 0) |
---|
206 | { |
---|
207 | time *= 1000; |
---|
208 | ++suffix; |
---|
209 | } |
---|
210 | os << "<td>"; |
---|
211 | if(highlight) |
---|
212 | os << "<font color=\"#008000\">"; |
---|
213 | if(rel <= 1000) |
---|
214 | os << std::setprecision(3) << rel; |
---|
215 | else |
---|
216 | os << (int)rel; |
---|
217 | os << "<BR>("; |
---|
218 | if(time <= 1000) |
---|
219 | os << std::setprecision(3) << time; |
---|
220 | else |
---|
221 | os << (int)time; |
---|
222 | os << suffixes[suffix] << ")"; |
---|
223 | if(highlight) |
---|
224 | os << "</font>"; |
---|
225 | os << "</td>"; |
---|
226 | } |
---|
227 | |
---|
228 | std::string html_quote(const std::string& in) |
---|
229 | { |
---|
230 | static const boost::regex e("(<)|(>)|(&)|(\")"); |
---|
231 | static const std::string format("(?1<)(?2>)(?3&)(?4")"); |
---|
232 | return regex_replace(in, e, format, boost::match_default | boost::format_all); |
---|
233 | } |
---|
234 | |
---|
235 | void output_html_results(bool show_description, const std::string& tagname) |
---|
236 | { |
---|
237 | std::stringstream os; |
---|
238 | if(result_list.size()) |
---|
239 | { |
---|
240 | // |
---|
241 | // start by outputting the table header: |
---|
242 | // |
---|
243 | os << "<table border=\"1\" cellspacing=\"1\">\n"; |
---|
244 | os << "<tr><td><strong>Expression</strong></td>"; |
---|
245 | if(show_description) |
---|
246 | os << "<td><strong>Text</strong></td>"; |
---|
247 | #if defined(BOOST_HAS_GRETA) |
---|
248 | if(time_greta == true) |
---|
249 | os << "<td><strong>GRETA</strong></td>"; |
---|
250 | if(time_safe_greta == true) |
---|
251 | os << "<td><strong>GRETA<BR>(non-recursive mode)</strong></td>"; |
---|
252 | #endif |
---|
253 | if(time_boost == true) |
---|
254 | os << "<td><strong>Boost</strong></td>"; |
---|
255 | if(time_localised_boost == true) |
---|
256 | os << "<td><strong>Boost + C++ locale</strong></td>"; |
---|
257 | #if defined(BOOST_HAS_POSIX) |
---|
258 | if(time_posix == true) |
---|
259 | os << "<td><strong>POSIX</strong></td>"; |
---|
260 | #endif |
---|
261 | #ifdef BOOST_HAS_PCRE |
---|
262 | if(time_pcre == true) |
---|
263 | os << "<td><strong>PCRE</strong></td>"; |
---|
264 | #endif |
---|
265 | os << "</tr>\n"; |
---|
266 | |
---|
267 | // |
---|
268 | // Now enumerate through all the test results: |
---|
269 | // |
---|
270 | std::list<results>::const_iterator first, last; |
---|
271 | first = result_list.begin(); |
---|
272 | last = result_list.end(); |
---|
273 | while(first != last) |
---|
274 | { |
---|
275 | os << "<tr><td><code>" << html_quote(first->expression) << "</code></td>"; |
---|
276 | if(show_description) |
---|
277 | os << "<td>" << html_quote(first->description) << "</td>"; |
---|
278 | #if defined(BOOST_HAS_GRETA) |
---|
279 | if(time_greta == true) |
---|
280 | { |
---|
281 | print_result(os, first->greta_time, first->factor); |
---|
282 | if(first->greta_time > 0) |
---|
283 | { |
---|
284 | greta_total += first->greta_time / first->factor; |
---|
285 | ++greta_test_count; |
---|
286 | } |
---|
287 | } |
---|
288 | if(time_safe_greta == true) |
---|
289 | { |
---|
290 | print_result(os, first->safe_greta_time, first->factor); |
---|
291 | if(first->safe_greta_time > 0) |
---|
292 | { |
---|
293 | safe_greta_total += first->safe_greta_time / first->factor; |
---|
294 | ++safe_greta_test_count; |
---|
295 | } |
---|
296 | } |
---|
297 | #endif |
---|
298 | #if defined(BOOST_HAS_POSIX) |
---|
299 | if(time_boost == true) |
---|
300 | { |
---|
301 | print_result(os, first->boost_time, first->factor); |
---|
302 | if(first->boost_time > 0) |
---|
303 | { |
---|
304 | boost_total += first->boost_time / first->factor; |
---|
305 | ++boost_test_count; |
---|
306 | } |
---|
307 | } |
---|
308 | if(time_localised_boost == true) |
---|
309 | { |
---|
310 | print_result(os, first->localised_boost_time, first->factor); |
---|
311 | if(first->localised_boost_time > 0) |
---|
312 | { |
---|
313 | locale_boost_total += first->localised_boost_time / first->factor; |
---|
314 | ++locale_boost_test_count; |
---|
315 | } |
---|
316 | } |
---|
317 | #endif |
---|
318 | if(time_posix == true) |
---|
319 | { |
---|
320 | print_result(os, first->posix_time, first->factor); |
---|
321 | if(first->posix_time > 0) |
---|
322 | { |
---|
323 | posix_total += first->posix_time / first->factor; |
---|
324 | ++posix_test_count; |
---|
325 | } |
---|
326 | } |
---|
327 | #if defined(BOOST_HAS_PCRE) |
---|
328 | if(time_pcre == true) |
---|
329 | { |
---|
330 | print_result(os, first->pcre_time, first->factor); |
---|
331 | if(first->pcre_time > 0) |
---|
332 | { |
---|
333 | pcre_total += first->pcre_time / first->factor; |
---|
334 | ++pcre_test_count; |
---|
335 | } |
---|
336 | } |
---|
337 | #endif |
---|
338 | os << "</tr>\n"; |
---|
339 | ++first; |
---|
340 | } |
---|
341 | os << "</table>\n"; |
---|
342 | result_list.clear(); |
---|
343 | } |
---|
344 | else |
---|
345 | { |
---|
346 | os << "<P><I>Results not available...</I></P>\n"; |
---|
347 | } |
---|
348 | |
---|
349 | std::string result = os.str(); |
---|
350 | |
---|
351 | std::string::size_type pos = html_contents.find(tagname); |
---|
352 | if(pos != std::string::npos) |
---|
353 | { |
---|
354 | html_contents.replace(pos, tagname.size(), result); |
---|
355 | } |
---|
356 | } |
---|
357 | |
---|
358 | std::string get_boost_version() |
---|
359 | { |
---|
360 | std::stringstream os; |
---|
361 | os << (BOOST_VERSION / 100000) << '.' << ((BOOST_VERSION / 100) % 1000) << '.' << (BOOST_VERSION % 100); |
---|
362 | return os.str(); |
---|
363 | } |
---|
364 | |
---|
365 | std::string get_averages_table() |
---|
366 | { |
---|
367 | std::stringstream os; |
---|
368 | // |
---|
369 | // start by outputting the table header: |
---|
370 | // |
---|
371 | os << "<table border=\"1\" cellspacing=\"1\">\n"; |
---|
372 | os << "<tr>"; |
---|
373 | #if defined(BOOST_HAS_GRETA) |
---|
374 | if(time_greta == true) |
---|
375 | { |
---|
376 | os << "<td><strong>GRETA</strong></td>"; |
---|
377 | } |
---|
378 | if(time_safe_greta == true) |
---|
379 | { |
---|
380 | os << "<td><strong>GRETA<BR>(non-recursive mode)</strong></td>"; |
---|
381 | } |
---|
382 | |
---|
383 | #endif |
---|
384 | if(time_boost == true) |
---|
385 | { |
---|
386 | os << "<td><strong>Boost</strong></td>"; |
---|
387 | } |
---|
388 | if(time_localised_boost == true) |
---|
389 | { |
---|
390 | os << "<td><strong>Boost + C++ locale</strong></td>"; |
---|
391 | } |
---|
392 | #if defined(BOOST_HAS_POSIX) |
---|
393 | if(time_posix == true) |
---|
394 | { |
---|
395 | os << "<td><strong>POSIX</strong></td>"; |
---|
396 | } |
---|
397 | #endif |
---|
398 | #ifdef BOOST_HAS_PCRE |
---|
399 | if(time_pcre == true) |
---|
400 | { |
---|
401 | os << "<td><strong>PCRE</strong></td>"; |
---|
402 | } |
---|
403 | #endif |
---|
404 | os << "</tr>\n"; |
---|
405 | |
---|
406 | // |
---|
407 | // Now enumerate through all averages: |
---|
408 | // |
---|
409 | os << "<tr>"; |
---|
410 | #if defined(BOOST_HAS_GRETA) |
---|
411 | if(time_greta == true) |
---|
412 | os << "<td>" << (greta_total / greta_test_count) << "</td>\n"; |
---|
413 | if(time_safe_greta == true) |
---|
414 | os << "<td>" << (safe_greta_total / safe_greta_test_count) << "</td>\n"; |
---|
415 | #endif |
---|
416 | #if defined(BOOST_HAS_POSIX) |
---|
417 | if(time_boost == true) |
---|
418 | os << "<td>" << (boost_total / boost_test_count) << "</td>\n"; |
---|
419 | if(time_localised_boost == true) |
---|
420 | os << "<td>" << (locale_boost_total / locale_boost_test_count) << "</td>\n"; |
---|
421 | #endif |
---|
422 | if(time_posix == true) |
---|
423 | os << "<td>" << (posix_total / posix_test_count) << "</td>\n"; |
---|
424 | #if defined(BOOST_HAS_PCRE) |
---|
425 | if(time_pcre == true) |
---|
426 | os << "<td>" << (pcre_total / pcre_test_count) << "</td>\n"; |
---|
427 | #endif |
---|
428 | os << "</tr>\n"; |
---|
429 | os << "</table>\n"; |
---|
430 | return os.str(); |
---|
431 | } |
---|
432 | |
---|
433 | void output_final_html() |
---|
434 | { |
---|
435 | if(html_out_file.size()) |
---|
436 | { |
---|
437 | // |
---|
438 | // start with search and replace ops: |
---|
439 | // |
---|
440 | std::string::size_type pos; |
---|
441 | pos = html_contents.find("%compiler%"); |
---|
442 | if(pos != std::string::npos) |
---|
443 | { |
---|
444 | html_contents.replace(pos, 10, BOOST_COMPILER); |
---|
445 | } |
---|
446 | pos = html_contents.find("%library%"); |
---|
447 | if(pos != std::string::npos) |
---|
448 | { |
---|
449 | html_contents.replace(pos, 9, BOOST_STDLIB); |
---|
450 | } |
---|
451 | pos = html_contents.find("%os%"); |
---|
452 | if(pos != std::string::npos) |
---|
453 | { |
---|
454 | html_contents.replace(pos, 4, BOOST_PLATFORM); |
---|
455 | } |
---|
456 | pos = html_contents.find("%boost%"); |
---|
457 | if(pos != std::string::npos) |
---|
458 | { |
---|
459 | html_contents.replace(pos, 7, get_boost_version()); |
---|
460 | } |
---|
461 | pos = html_contents.find("%pcre%"); |
---|
462 | if(pos != std::string::npos) |
---|
463 | { |
---|
464 | #ifdef PCRE_MINOR |
---|
465 | html_contents.replace(pos, 6, BOOST_STRINGIZE(PCRE_MAJOR.PCRE_MINOR)); |
---|
466 | #else |
---|
467 | html_contents.replace(pos, 6, "N/A"); |
---|
468 | #endif |
---|
469 | } |
---|
470 | pos = html_contents.find("%averages%"); |
---|
471 | if(pos != std::string::npos) |
---|
472 | { |
---|
473 | html_contents.replace(pos, 10, get_averages_table()); |
---|
474 | } |
---|
475 | // |
---|
476 | // now right the output to file: |
---|
477 | // |
---|
478 | std::ofstream os(html_out_file.c_str()); |
---|
479 | os << html_contents; |
---|
480 | } |
---|
481 | else |
---|
482 | { |
---|
483 | std::cout << html_contents; |
---|
484 | } |
---|
485 | } |
---|