2013-02-25 53 views
2

我有一個格式爲「$ number_of_elements $ e1 $ e2 $ e3」格式的文件。我創建了以下解析器:臨時屬性需要解壓的助推精神

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/include/boost_tuple.hpp> 


int main(int argc, char *argv[]) 
{ 
    std::string input("2 3 3\n"); 

    using boost::phoenix::at_c; 
    using boost::spirit::qi::_1; 
    using boost::spirit::qi::_r1; 
    using boost::spirit::qi::double_; 
    using boost::spirit::qi::omit; 
    using boost::spirit::qi::int_; 
    using boost::spirit::qi::repeat; 
    using boost::spirit::qi::rule; 
    using boost::spirit::qi::space; 
    using boost::spirit::qi::space_type; 
    using boost::spirit::qi::_val; 

    rule<std::string::iterator, double(), space_type> r0 = double_; 
    r0.name("r0"); 
    rule<std::string::iterator, std::vector<double>(size_t), space_type> r1 = repeat(_r1)[r0]; 
    r1.name("r1"); 
    rule<std::string::iterator, boost::tuple<size_t, std::vector<double> >(), space_type> r2 
    = int_ >> r1(at_c<0>(_val)); 
    r2.name("r2"); 
    rule<std::string::iterator, std::vector<double>(), space_type> r3 
    = r2[_val = at_c<1>(_1)]; 
    r3.name("r3"); 
    debug(r0); 
    debug(r1); 
    debug(r2); 
    debug(r3); 
    std::vector<double> res; 
    bool success = boost::spirit::qi::phrase_parse(input.begin(), 
               input.end(), 
               r3, 
               space, 
               res); 
    if (success) { 
    for(std::vector<double>::iterator it = res.begin(); it != res.end(); it++) { 
     std::cout << *it << " " << std::endl; 
    } 
    } 
    return !success; 
} 

我不知道是否有避免複製的機會。我不知道boost phoenix(或gcc)說如果臨時對象刪除優化將由編譯器應用(數據量可能非常大,因此可能會影響性能)。

而且 - 這可能改變r1規則弄成(除非它是通過重複這樣做):

rule<std::string::iterator, std::vector<double>(size_t), space_type> r1 
    = eps[_val.reserve(_r1)] >> repeat(_r1)[r0]; 

(此行不編譯)。

PS。存儲的數量可能相當大,因此在此刻複製/重新分配可能會產生一些影響 - 但我更願意在完全承諾設計之前知道這種優化涉及的是什麼。

PPS。我使用的是gcc 4.4,因此我可以訪問std::move,但沒有其他許多C++ 11功能。

回答

2

哇,這個人帶我一段時間來得到正確的,首先我必須正確地清理代碼,以便我能讀它(我希望你不介意),其餘與語義動作完成:

#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/phoenix_stl.hpp> 

#include <string> 
#include <vector> 
#include <algorithm> 
#include <iterator> 

int main() { 
    namespace qi=boost::spirit::qi; 
    namespace phx=boost::phoenix; 

    //we use no predefined terms to speed up compile times 
    qi::double_type double_; 
    qi::int_type int_; 
    qi::_1_type  _1; 
    qi::_val_type _val; 

    std::string in="3 3.4 5.6 6.7"; 
    auto first=in.cbegin(), 
     last =in.cend(); 

    std::vector<double> out; 

    qi::rule<std::string::const_iterator, std::vector<double>()> r1= 
     int_  
     [ 
      phx::bind(&std::vector<double>::reserve, _val, _1) 
     ] 
     >> ' ' % 
      double_ 
      [ 
       phx::push_back(_val, _1) 
      ] 
     ; 

    qi::parse(first, last, r1, out); 

    std::copy(out.cbegin(), out.cend(), 
     std::ostream_iterator<double>(std::cout, "\n")); 
} 

輸出:

3.4 
5.6 
6.7 

可以看到在這裏工作:

http://liveworkspace.org/code/QBPdC$1

1

std::swapboost::pheonix::swap避免複製。

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/include/boost_tuple.hpp> 


namespace ph = boost::phoenix; 
namespace qi = boost::spirit::qi; 

int main(int argc, char *argv[]) 
{ 
    std::string input("2 3 3\n"); 

    qi::rule<std::string::iterator, qi::space_type, double()> r0 
    = qi::double_; 
    r0.name("r0"); 
    // I'm not sure why this qi::omit is needed but without it the output is empty 
    qi::rule<std::string::iterator, qi::space_type, std::vector<double>(size_t)> r1 
    = qi::omit[qi::eps[ph::reserve(qi::_val, qi::_r1)]] >> qi::repeat(qi::_r1)[r0]; 
    r1.name("r1"); 
    qi::rule<std::string::iterator, qi::space_type, boost::tuple<size_t, std::vector<double> >()> r2 
    = qi::int_ >> r1(ph::at_c<0>(qi::_val)); 
    r2.name("r2"); 
    qi::rule<std::string::iterator, qi::space_type, std::vector<double>()> r3 
    = r2[ph::swap(qi::_val, ph::at_c<1>(qi::_1))]; 
    r3.name("r3"); 
    std::vector<double> res; 
    bool success = qi::phrase_parse(input.begin(), 
        input.end(), 
        r3, 
        qi::space, 
        res); 
    if (success) { 
    for(std::vector<double>::iterator it = res.begin(); it != res.end(); it++) { 
     std::cout << *it << " " << std::endl; 
    } 
    } 
    return !success; 
} 

(對不起不清楚代碼,但我把它作爲運動場boost::spirit

+1

只在一個規則[替代](http://liveworkspace.org/code/333dTY$0)。 – 2013-02-25 19:47:54

+0

@llonesmiz:如果你把它作爲答案發布,我會接受 - 這個問題是關於當地人。 – 2013-02-26 00:54:43