/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2011 Thomas Bernard Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #define FUSION_MAX_VECTOR_SIZE 50 #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS #define BOOST_MPL_LIMIT_LIST_SIZE 50 #define BOOST_MPL_LIMIT_VECTOR_SIZE 50 #include "../measure.hpp" #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_object.hpp> #include <boost/spirit/include/phoenix_fusion.hpp> #include <boost/spirit/include/phoenix_container.hpp> #include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/io.hpp> #include <boost/spirit/include/qi_permutation.hpp> #include <boost/spirit/home/qi/string/tst_map.hpp> #include <boost/spirit/repository/include/qi_kwd.hpp> #include <boost/spirit/repository/include/qi_keywords.hpp> #include <boost/optional.hpp> #include <boost/spirit/home/phoenix/core/argument.hpp> #include <boost/spirit/home/phoenix/bind/bind_member_variable.hpp> #include <iostream> #include <string> #include <complex> #include <vector> #include <iterator> #include <stdexcept> #include <boost/preprocessor/control/if.hpp> #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/preprocessor/seq/size.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/stringize.hpp> #define KEYS_5 #include "keywords.hpp" #define declOptions(r, data, i, elem) boost::optional<int> BOOST_PP_CAT(option,i); #define fusionOptions(r, data, i, elem) (boost::optional<int>, BOOST_PP_CAT(option,i)) namespace client { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; /////////////////////////////////////////////////////////////////////////// // Our parsedData struct /////////////////////////////////////////////////////////////////////////// //[tutorial_parsedData_struct struct parsedDataOptions { BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys) }; struct parsedData { std::string name; parsedDataOptions options; void clear() { name.clear(); } }; struct parsedData2 { std::string name; BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys) void clear() { name.clear(); } }; } std::ostream &operator<<(std::ostream & os, client::parsedData &data) { os << data.name <<std::endl; #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; BOOST_PP_SEQ_FOR_EACH_I(generateOutput1,_,keys) os<<std::endl; return os; } std::ostream &operator<<(std::ostream & os, client::parsedData2 &data) { os << data.name <<std::endl; #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; BOOST_PP_SEQ_FOR_EACH_I(generateOutput2,_,keys) os<<std::endl; return os; } BOOST_FUSION_ADAPT_STRUCT( client::parsedDataOptions, BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys) ) BOOST_FUSION_ADAPT_STRUCT( client::parsedData, (std::string, name) (client::parsedDataOptions, options) ) BOOST_FUSION_ADAPT_STRUCT( client::parsedData2, (std::string, name) BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys) ) enum variation { full, no_assign, assign }; namespace client { /////////////////////////////////////////////////////////////////////////////// // Our parsedData parser /////////////////////////////////////////////////////////////////////////////// //[tutorial_parsedData_parser template <typename Iterator> struct permutation_parser : qi::grammar<Iterator, parsedData(), ascii::space_type> { permutation_parser() : permutation_parser::base_type(start) { using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using boost::phoenix::at_c; using boost::phoenix::assign; using qi::_r1; using qi::_1; using qi::_val; using qi::omit; using qi::repeat; quoted_string %= lexeme[+(char_-' ')]; #define generateOptions1(r, data, i, elem) BOOST_PP_IF(i, ^(lit(elem) > int_) , (lit(elem) > int_)) options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions1,_,keys)); start %= quoted_string >> options; ; v_vals = repeat(1,2)[int_]; } typedef parsedData parser_target_type; qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options; qi::rule<Iterator, std::vector<int>(), ascii::space_type> v_vals; qi::rule<Iterator, parsedData(), ascii::space_type> start; }; template <typename Iterator> struct alternative_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type> { alternative_parser() : alternative_parser::base_type(start) { using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using boost::phoenix::at_c; using qi::_r1; using qi::_1; using qi::_val; quoted_string %= lexeme[+(char_-' ')]; #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])) options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions2,_,keys)); start = quoted_string [at_c<0>(_val)=_1] >> *options(_val); ; } typedef parsedData2 parser_target_type; qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; qi::rule<Iterator, void(parsedData2 & ), ascii::space_type> options; qi::rule<Iterator, parsedData2(), ascii::space_type> start; }; template <typename Iterator,typename variation> struct tst_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type> { typedef variation variation_type; tst_parser() : tst_parser::base_type(startalias) { namespace phx = boost::phoenix; using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using boost::phoenix::at_c; using qi::_r1; using qi::_1; using qi::_a; using qi::_val; using qi::locals; using qi::parameterized_nonterminal; startalias = start.alias(); quoted_string %= lexeme[+(char_-' ')]; #define generateRules(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1]; BOOST_PP_SEQ_FOR_EACH_I(generateRules,_,keys) #define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i)) options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys); switch(variation_type::value) { case full: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options [_a=_1] >> lazy(*_a)); ; break; } case no_assign: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options >> int_); ; break; } case assign: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options [_a=_1] >> int_); ; break; } } } parsedData2 *currentObj; typedef parsedData2 parser_target_type; qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; typedef qi::rule<Iterator, ascii::space_type> optionsRule; #define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i); BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys) qi::symbols<char,optionsRule* > options; qi::rule<Iterator, parsedData2(), ascii::space_type> startalias; qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start; }; template <typename Iterator,typename variation> struct tst_map_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type> { typedef variation variation_type; tst_map_parser() : tst_map_parser::base_type(startalias) { namespace phx = boost::phoenix; using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using boost::phoenix::at_c; using qi::_r1; using qi::_1; using qi::_a; using qi::_val; using qi::locals; using qi::parameterized_nonterminal; startalias = start.alias(); quoted_string %= lexeme[+(char_-' ')]; #define generateRules3(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1]; BOOST_PP_SEQ_FOR_EACH_I(generateRules3,_,keys) #define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i)) options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys); switch(variation_type::value) { case full: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options [_a=_1] >> lazy(*_a)); ; break; } case no_assign: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options >> int_); ; break; } case assign: { start = quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val] >> *( options [_a=_1] >> int_); ; break; } } } parsedData2 *currentObj; typedef parsedData2 parser_target_type; qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; typedef qi::rule<Iterator, ascii::space_type> optionsRule; #define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i); BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys) qi::symbols<char,optionsRule*, boost::spirit::qi::tst_map<char,optionsRule*> > options; qi::rule<Iterator, parsedData2(), ascii::space_type> startalias; qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start; }; template <typename Iterator> struct kwd_parser : qi::grammar<Iterator, parsedData(), ascii::space_type> { kwd_parser() : kwd_parser::base_type(start) { using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using qi::_r1; using qi::_1; using qi::_val; using boost::spirit::repository::qi::kwd; quoted_string %= lexeme[+(char_-' ')]; #define generateOptions4(r, data, i, elem) BOOST_PP_IF(i, / kwd( elem )[ int_ ] , kwd( elem )[ int_ ] ) options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions4,_,keys)); start %= quoted_string >> options; ; } typedef parsedData parser_target_type; qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options; qi::rule<Iterator, boost::fusion::vector<boost::optional<int>,boost::optional<int> > () , ascii::space_type> v_vals; qi::rule<Iterator, parsedData(), ascii::space_type> start; }; } template <typename parserType> struct timeParser : test::base{ timeParser(const std::string & str) : str(str) { } parserType &get_parser(){ static parserType parser; return parser; } std::string str; void benchmark() { using boost::spirit::ascii::space; bool r = false; std::string::const_iterator end = str.end(); std::string::const_iterator iter = str.begin(); typename parserType::parser_target_type data; r = phrase_parse(iter, end, get_parser(), space, data); if (r && iter == end) { this->val += data.name.size(); } else { throw std::runtime_error("Parsing failed"); } } }; typedef std::string::const_iterator iterator_type; typedef client::permutation_parser<iterator_type> permutation_parser; typedef client::kwd_parser<iterator_type> kwd_parser; typedef client::alternative_parser<iterator_type> alternative_parser; typedef client::tst_map_parser<iterator_type, boost::mpl::int_<full> > tst_map_parser; struct permutation_timer_fwd : timeParser<permutation_parser> { permutation_timer_fwd() : timeParser<permutation_parser>(fwd) {} }; struct permutation_timer_back : timeParser<permutation_parser> { permutation_timer_back() : timeParser<permutation_parser>(back) {} }; struct alternative_timer_fwd : timeParser<alternative_parser> { alternative_timer_fwd() : timeParser<alternative_parser>(fwd) {} }; struct alternative_timer_back : timeParser<alternative_parser> { alternative_timer_back() : timeParser<alternative_parser>(back) {} }; struct tst_timer_fwd_full : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > > { tst_timer_fwd_full() : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > >(fwd) {} }; struct tst_timer_fwd_no_assign : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<no_assign> > > { tst_timer_fwd_no_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<no_assign> > >(fwd) {} }; struct tst_timer_fwd_assign : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > > { tst_timer_fwd_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > >(fwd) {} }; struct tst_timer_back : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > > { tst_timer_back() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > >(back) {} }; struct tst_map_timer_fwd : timeParser<tst_map_parser> { tst_map_timer_fwd() : timeParser<tst_map_parser>(fwd) {} }; struct tst_map_timer_back : timeParser<tst_map_parser> { tst_map_timer_back() : timeParser<tst_map_parser>(back) {} }; struct kwd_timer_fwd : timeParser<kwd_parser> { kwd_timer_fwd() : timeParser<kwd_parser>(fwd) {} }; struct kwd_timer_back : timeParser<kwd_parser> { kwd_timer_back() : timeParser<kwd_parser>(back) {} }; //////////////////////////////////////////////////////////////////////////// // Main program //////////////////////////////////////////////////////////////////////////// int main() { BOOST_SPIRIT_TEST_BENCHMARK( 10000000000, // This is the maximum repetitions to execute (permutation_timer_fwd) (permutation_timer_back) (alternative_timer_fwd) (alternative_timer_back) (tst_timer_fwd_full) (tst_timer_fwd_no_assign) (tst_timer_fwd_assign) (tst_timer_back) (tst_map_timer_fwd) (tst_map_timer_back) (kwd_timer_fwd) (kwd_timer_back) ) // This is ultimately responsible for preventing all the test code // from being optimized away. Change this to return 0 and you // unplug the whole test's life support system. return test::live_code != 0; }