1 // (C) Copyright Eric Niebler 2006.
2 // Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <iostream>
7 #include <iomanip>
8 #include <fstream>
9 #include <deque>
10 #include <sstream>
11 #include <stdexcept>
12 #include <iterator>
13 #include "./regex_comparison.hpp"
14
15 //
16 // globals:
17 //
18 bool time_boost = false;
19 bool time_greta = false;
20 bool time_safe_greta = false;
21 bool time_dynamic_xpressive = false;
22 bool time_static_xpressive = false;
23 //bool time_posix = false;
24 //bool time_pcre = false;
25
26 bool test_matches = false;
27 bool test_short_twain = false;
28 bool test_long_twain = false;
29
30 std::string xml_out_file;
31 std::string xml_contents;
32 std::list<results> result_list;
33
handle_argument(const std::string & what)34 int handle_argument(const std::string& what)
35 {
36 if(what == "-b")
37 time_boost = true;
38 else if(what == "-g")
39 time_greta = true;
40 else if(what == "-gs")
41 time_safe_greta = true;
42 else if(what == "-dx")
43 time_dynamic_xpressive = true;
44 else if(what == "-sx")
45 time_static_xpressive = true;
46 //else if(what == "-posix")
47 // time_posix = true;
48 //else if(what == "-pcre")
49 // time_pcre = true;
50 else if(what == "-all")
51 {
52 time_boost = true;
53 time_greta = true;
54 time_safe_greta = true;
55 time_dynamic_xpressive = true;
56 time_static_xpressive = true;
57 //time_posix = true;
58 //time_pcre = true;
59 }
60 else if(what == "-test-matches")
61 test_matches = true;
62 else if(what == "-test-short-twain")
63 test_short_twain = true;
64 else if(what == "-test-long-twain")
65 test_long_twain = true;
66 else if(what == "-test-all")
67 {
68 test_matches = true;
69 test_short_twain = true;
70 test_long_twain = true;
71 }
72 else if((what == "-h") || (what == "--help"))
73 return show_usage();
74 else if((what[0] == '-') || (what[0] == '/'))
75 {
76 std::cerr << "Unknown argument: \"" << what << "\"" << std::endl;
77 return 1;
78 }
79 else if(xml_out_file.size() == 0)
80 {
81 xml_out_file = what;
82 }
83 else
84 {
85 std::cerr << "Unexpected argument: \"" << what << "\"" << std::endl;
86 return 1;
87 }
88 return 0;
89 }
90
show_usage()91 int show_usage()
92 {
93 std::cout <<
94 "Usage\n"
95 "xprperf [-h] [library options] [test options] [xml_output_file]\n"
96 " -h Show help\n\n"
97 " library options:\n"
98 " -b Apply tests to boost library\n"
99 //" -ba Apply tests to boost library with a custom allocator\n"
100 //" -be Apply tests to experimental boost library\n"
101 //" -g Apply tests to GRETA library\n"
102 //" -gs Apply tests to GRETA library (in non-recursive mode)\n"
103 " -dx Apply tests to dynamic xpressive library\n"
104 " -sx Apply tests to static xpressive library\n"
105 //" -posix Apply tests to POSIX library\n"
106 //" -pcre Apply tests to PCRE library\n"
107 " -all Apply tests to all libraries\n\n"
108 " test options:\n"
109 " -test-matches Test short matches\n"
110 " -test-short-twain Test short searches\n"
111 " -test-long-twain Test long searches\n"
112 " -test-all Test everthing\n";
113 return 1;
114 }
115
load_file(std::string & text,const char * file)116 void load_file(std::string& text, const char* file)
117 {
118 std::deque<char> temp_copy;
119 std::ifstream is(file);
120 if(!is.good())
121 {
122 std::string msg("Unable to open file: \"");
123 msg.append(file);
124 msg.append("\"");
125 throw std::runtime_error(msg);
126 }
127 std::istreambuf_iterator<char> it(is);
128 std::copy(it, std::istreambuf_iterator<char>(), std::back_inserter(temp_copy));
129 text.erase();
130 text.reserve(temp_copy.size());
131 text.append(temp_copy.begin(), temp_copy.end());
132 }
133
134 struct xml_double
135 {
136 double d_;
xml_doublexml_double137 xml_double( double d ) : d_(d) {}
operator <<(std::ostream & out,xml_double const & xd)138 friend std::ostream & operator<<( std::ostream & out, xml_double const & xd )
139 {
140 std::ostringstream tmp;
141 tmp << std::setprecision(out.precision()) << xd.d_;
142 std::string str = tmp.str();
143 std::string::size_type i = str.find( '-' );
144 if( i != std::string::npos )
145 str.replace( i, 1, "‑" );
146 return out << str;
147 }
148 };
149
print_result(std::ostream & os,double time,double best)150 void print_result(std::ostream& os, double time, double best)
151 {
152 static const char* suffixes[] = {"s", "ms", "us", "ns", "ps", };
153
154 if(time < 0)
155 {
156 os << "<entry>NA</entry>";
157 return;
158 }
159 double rel = time / best;
160 bool highlight = ((rel > 0) && (rel < 1.1));
161 unsigned suffix = 0;
162 while(time < 0)
163 {
164 time *= 1000;
165 ++suffix;
166 }
167 os << "<entry>";
168 if(highlight)
169 os << "<phrase role=\"highlight\">";
170 if(rel <= 1000)
171 os << std::setprecision(3) << xml_double(rel);
172 else
173 os << (int)rel;
174 os << "<para/>(";
175 if(time <= 1000)
176 os << std::setprecision(3) << xml_double(time);
177 else
178 os << (int)time;
179 os << suffixes[suffix] << ")";
180 if(highlight)
181 os << "</phrase>";
182 os << "</entry>";
183 }
184
output_xml_results(bool show_description,const std::string & title,const std::string & filename)185 void output_xml_results(bool show_description, const std::string& title, const std::string& filename)
186 {
187 std::stringstream os;
188 // Generate the copyright and license on the output file
189 os << "<!--\n"
190 " Copyright 2004 Eric Niebler.\n"
191 "\n"
192 " Distributed under the Boost Software License, Version 1.0.\n"
193 " (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n"
194 "-->\n";
195
196 if(result_list.size())
197 {
198 // calculate the number of columns in this table
199 int num_cols = 1 + show_description + time_greta + time_safe_greta
200 + time_dynamic_xpressive + time_static_xpressive + time_boost;
201
202 //
203 // start by outputting the table header:
204 //
205 os << "<informaltable frame=\"all\">\n";
206 os << "<bridgehead renderas=\"sect4\">"
207 "<phrase role=\"table-title\">" << title << "</phrase>"
208 "</bridgehead>\n";
209 os << "<tgroup cols=\"" << num_cols << "\">\n";
210 os << "<thead>\n";
211 os << "<row>\n";
212
213 if(time_static_xpressive) os << "<entry>static xpressive</entry>";
214 if(time_dynamic_xpressive) os << "<entry>dynamic xpressive</entry>";
215 if(time_greta) os << "<entry>GRETA</entry>";
216 if(time_safe_greta) os << "<entry>GRETA<para/>(non-recursive mode)</entry>";
217 if(time_boost) os << "<entry>Boost</entry>";
218 //if(time_posix) os << "<entry>POSIX</entry>";
219 //if(time_pcre) os << "<entry>PCRE</entry>";
220 if(show_description) os << "<entry>Text</entry>";
221 os << "<entry>Expression</entry>";
222 os << "\n</row>\n";
223 os << "</thead>\n";
224 os << "<tbody>\n";
225
226 //
227 // Now enumerate through all the test results:
228 //
229 std::list<results>::const_iterator first, last;
230 first = result_list.begin();
231 last = result_list.end();
232 while(first != last)
233 {
234 os << "<row>\n";
235 if(time_static_xpressive) print_result(os, first->static_xpressive_time, first->factor);
236 if(time_dynamic_xpressive) print_result(os, first->dynamic_xpressive_time, first->factor);
237 if(time_greta) print_result(os, first->greta_time, first->factor);
238 if(time_safe_greta) print_result(os, first->safe_greta_time, first->factor);
239 if(time_boost) print_result(os, first->boost_time, first->factor);
240 //if(time_posix) print_result(os, first->posix_time, first->factor);
241 //if(time_pcre) print_result(os, first->pcre_time, first->factor);
242 if(show_description) os << "<entry>" << first->description << "</entry>";
243 os << "<entry><literal>" << first->expression << "</literal></entry>";
244 os << "\n</row>\n";
245 ++first;
246 }
247
248 os << "</tbody>\n"
249 "</tgroup>\n"
250 "</informaltable>\n";
251
252 result_list.clear();
253 }
254 else
255 {
256 os << "<para><emphasis>Results not available...</emphasis></para>\n";
257 }
258
259 std::ofstream file(filename.c_str());
260 file << os.str();
261 }
262