1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2011 Thomas Bernard
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
9 #define FUSION_MAX_VECTOR_SIZE 50
10 #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
11 #define BOOST_MPL_LIMIT_LIST_SIZE 50
12 #define BOOST_MPL_LIMIT_VECTOR_SIZE 50
14 #include "../measure.hpp"
15 #include <boost/config/warning_disable.hpp>
16 #include <boost/spirit/include/qi.hpp>
17 #include <boost/spirit/include/phoenix_core.hpp>
18 #include <boost/spirit/include/phoenix_operator.hpp>
19 #include <boost/spirit/include/phoenix_object.hpp>
20 #include <boost/spirit/include/phoenix_fusion.hpp>
21 #include <boost/spirit/include/phoenix_container.hpp>
22 #include <boost/fusion/include/adapt_struct.hpp>
23 #include <boost/fusion/include/io.hpp>
24 #include <boost/spirit/include/qi_permutation.hpp>
25 #include <boost/spirit/home/qi/string/tst_map.hpp>
26 #include <boost/spirit/repository/include/qi_kwd.hpp>
27 #include <boost/spirit/repository/include/qi_keywords.hpp>
28 #include <boost/optional.hpp>
29 #include <boost/spirit/home/phoenix/core/argument.hpp>
30 #include <boost/spirit/home/phoenix/bind/bind_member_variable.hpp>
39 #include <boost/preprocessor/control/if.hpp>
40 #include <boost/preprocessor/seq/for_each_i.hpp>
41 #include <boost/preprocessor/seq/size.hpp>
42 #include <boost/preprocessor/cat.hpp>
43 #include <boost/preprocessor/stringize.hpp>
47 #include "keywords.hpp"
49 #define declOptions(r, data, i, elem) boost::optional<int> BOOST_PP_CAT(option,i);
50 #define fusionOptions(r, data, i, elem) (boost::optional<int>, BOOST_PP_CAT(option,i))
55 namespace qi = boost::spirit::qi;
56 namespace ascii = boost::spirit::ascii;
58 ///////////////////////////////////////////////////////////////////////////
59 // Our parsedData struct
60 ///////////////////////////////////////////////////////////////////////////
61 //[tutorial_parsedData_struct
62 struct parsedDataOptions
64 BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys)
70 parsedDataOptions options;
80 BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys)
89 std::ostream &operator<<(std::ostream & os, client::parsedData &data)
91 os << data.name <<std::endl;
93 #define generateOutput1(r, d, i, elem) if( BOOST_PP_CAT(data.options.option, i) ) os<< BOOST_PP_STRINGIZE( BOOST_PP_CAT(option,i)) <<" "<< * BOOST_PP_CAT(data.options.option , i)<<std::endl;
94 BOOST_PP_SEQ_FOR_EACH_I(generateOutput1,_,keys)
101 std::ostream &operator<<(std::ostream & os, client::parsedData2 &data)
103 os << data.name <<std::endl;
105 #define generateOutput2(r, d, i, elem) if(BOOST_PP_CAT(data.option, i)) os<< BOOST_PP_STRINGIZE( BOOST_PP_CAT(option,i)) <<" "<< * BOOST_PP_CAT(data.option,i)<<std::endl;
106 BOOST_PP_SEQ_FOR_EACH_I(generateOutput2,_,keys)
115 BOOST_FUSION_ADAPT_STRUCT(
116 client::parsedDataOptions,
117 BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys)
120 BOOST_FUSION_ADAPT_STRUCT(
123 (client::parsedDataOptions, options)
126 BOOST_FUSION_ADAPT_STRUCT(
129 BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys)
141 ///////////////////////////////////////////////////////////////////////////////
142 // Our parsedData parser
143 ///////////////////////////////////////////////////////////////////////////////
144 //[tutorial_parsedData_parser
145 template <typename Iterator>
146 struct permutation_parser : qi::grammar<Iterator, parsedData(), ascii::space_type>
148 permutation_parser() : permutation_parser::base_type(start)
155 using boost::phoenix::at_c;
156 using boost::phoenix::assign;
164 quoted_string %= lexeme[+(char_-' ')];
166 #define generateOptions1(r, data, i, elem) BOOST_PP_IF(i, ^(lit(elem) > int_) , (lit(elem) > int_))
167 options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions1,_,keys));
173 v_vals = repeat(1,2)[int_];
176 typedef parsedData parser_target_type;
178 qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
179 qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options;
180 qi::rule<Iterator, std::vector<int>(), ascii::space_type> v_vals;
182 qi::rule<Iterator, parsedData(), ascii::space_type> start;
185 template <typename Iterator>
186 struct alternative_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
188 alternative_parser() : alternative_parser::base_type(start)
195 using boost::phoenix::at_c;
200 quoted_string %= lexeme[+(char_-' ')];
202 #define generateOptions2(r, data, i, elem) BOOST_PP_IF(i, |(lit(elem) > int_[at_c<i+1>(_r1)=_1]) , (lit(elem) > int_[at_c<i+1>(_r1)=_1]))
203 options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions2,_,keys));
206 quoted_string [at_c<0>(_val)=_1]
211 typedef parsedData2 parser_target_type;
213 qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
214 qi::rule<Iterator, void(parsedData2 & ), ascii::space_type> options;
215 qi::rule<Iterator, parsedData2(), ascii::space_type> start;
220 template <typename Iterator,typename variation>
221 struct tst_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
223 typedef variation variation_type;
225 tst_parser() : tst_parser::base_type(startalias)
227 namespace phx = boost::phoenix;
233 using boost::phoenix::at_c;
239 using qi::parameterized_nonterminal;
241 startalias = start.alias();
242 quoted_string %= lexeme[+(char_-' ')];
244 #define generateRules(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1];
245 BOOST_PP_SEQ_FOR_EACH_I(generateRules,_,keys)
247 #define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i))
250 options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys);
251 switch(variation_type::value)
256 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
257 >> *( options [_a=_1] >> lazy(*_a));
264 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
265 >> *( options >> int_);
272 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
273 >> *( options [_a=_1] >> int_);
282 parsedData2 *currentObj;
284 typedef parsedData2 parser_target_type;
286 qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
287 typedef qi::rule<Iterator, ascii::space_type> optionsRule;
288 #define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i);
290 BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys)
292 qi::symbols<char,optionsRule* > options;
293 qi::rule<Iterator, parsedData2(), ascii::space_type> startalias;
294 qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start;
299 template <typename Iterator,typename variation>
300 struct tst_map_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
302 typedef variation variation_type;
303 tst_map_parser() : tst_map_parser::base_type(startalias)
305 namespace phx = boost::phoenix;
311 using boost::phoenix::at_c;
317 using qi::parameterized_nonterminal;
319 startalias = start.alias();
320 quoted_string %= lexeme[+(char_-' ')];
322 #define generateRules3(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1];
323 BOOST_PP_SEQ_FOR_EACH_I(generateRules3,_,keys)
325 #define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i))
328 options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys);
330 switch(variation_type::value)
335 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
336 >> *( options [_a=_1] >> lazy(*_a));
343 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
344 >> *( options >> int_);
351 quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
352 >> *( options [_a=_1] >> int_);
359 parsedData2 *currentObj;
361 typedef parsedData2 parser_target_type;
363 qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
364 typedef qi::rule<Iterator, ascii::space_type> optionsRule;
365 #define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i);
367 BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys)
369 qi::symbols<char,optionsRule*, boost::spirit::qi::tst_map<char,optionsRule*> > options;
370 qi::rule<Iterator, parsedData2(), ascii::space_type> startalias;
371 qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start;
375 template <typename Iterator>
376 struct kwd_parser : qi::grammar<Iterator, parsedData(), ascii::space_type>
378 kwd_parser() : kwd_parser::base_type(start)
388 using boost::spirit::repository::qi::kwd;
390 quoted_string %= lexeme[+(char_-' ')];
392 #define generateOptions4(r, data, i, elem) BOOST_PP_IF(i, / kwd( elem )[ int_ ] , kwd( elem )[ int_ ] )
393 options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions4,_,keys));
401 typedef parsedData parser_target_type;
403 qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
404 qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options;
405 qi::rule<Iterator, boost::fusion::vector<boost::optional<int>,boost::optional<int> > () , ascii::space_type> v_vals;
407 qi::rule<Iterator, parsedData(), ascii::space_type> start;
413 template <typename parserType>
414 struct timeParser : test::base{
415 timeParser(const std::string & str) : str(str)
418 parserType &get_parser(){
419 static parserType parser;
428 using boost::spirit::ascii::space;
430 std::string::const_iterator end = str.end();
431 std::string::const_iterator iter = str.begin();
434 typename parserType::parser_target_type data;
435 r = phrase_parse(iter, end, get_parser(), space, data);
437 if (r && iter == end)
439 this->val += data.name.size();
443 throw std::runtime_error("Parsing failed");
452 typedef std::string::const_iterator iterator_type;
453 typedef client::permutation_parser<iterator_type> permutation_parser;
454 typedef client::kwd_parser<iterator_type> kwd_parser;
455 typedef client::alternative_parser<iterator_type> alternative_parser;
456 typedef client::tst_map_parser<iterator_type, boost::mpl::int_<full> > tst_map_parser;
458 struct permutation_timer_fwd : timeParser<permutation_parser>
460 permutation_timer_fwd() : timeParser<permutation_parser>(fwd) {}
463 struct permutation_timer_back : timeParser<permutation_parser>
465 permutation_timer_back() : timeParser<permutation_parser>(back) {}
468 struct alternative_timer_fwd : timeParser<alternative_parser>
470 alternative_timer_fwd() : timeParser<alternative_parser>(fwd) {}
473 struct alternative_timer_back : timeParser<alternative_parser>
475 alternative_timer_back() : timeParser<alternative_parser>(back) {}
478 struct tst_timer_fwd_full : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > >
480 tst_timer_fwd_full() : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > >(fwd) {}
483 struct tst_timer_fwd_no_assign : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<no_assign> > >
485 tst_timer_fwd_no_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<no_assign> > >(fwd) {}
488 struct tst_timer_fwd_assign : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > >
490 tst_timer_fwd_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > >(fwd) {}
495 struct tst_timer_back : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > >
497 tst_timer_back() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > >(back) {}
500 struct tst_map_timer_fwd : timeParser<tst_map_parser>
502 tst_map_timer_fwd() : timeParser<tst_map_parser>(fwd) {}
505 struct tst_map_timer_back : timeParser<tst_map_parser>
507 tst_map_timer_back() : timeParser<tst_map_parser>(back) {}
510 struct kwd_timer_fwd : timeParser<kwd_parser>
512 kwd_timer_fwd() : timeParser<kwd_parser>(fwd) {}
515 struct kwd_timer_back : timeParser<kwd_parser>
517 kwd_timer_back() : timeParser<kwd_parser>(back) {}
524 ////////////////////////////////////////////////////////////////////////////
526 ////////////////////////////////////////////////////////////////////////////
531 BOOST_SPIRIT_TEST_BENCHMARK(
532 10000000000, // This is the maximum repetitions to execute
533 (permutation_timer_fwd)
534 (permutation_timer_back)
535 (alternative_timer_fwd)
536 (alternative_timer_back)
538 (tst_timer_fwd_no_assign)
539 (tst_timer_fwd_assign)
547 // This is ultimately responsible for preventing all the test code
548 // from being optimized away. Change this to return 0 and you
549 // unplug the whole test's life support system.
550 return test::live_code != 0;