| 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 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 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_; |
|---|
| 137 | xml_double( double d ) : d_(d) {} |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 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 | } |
|---|