我可以给列表运算符(%)提供Boost.Spirit.Qi内存分配的提示吗?

时间:2018-04-18 06:27:34

标签: c++ boost boost-spirit-qi

我想解析以下数据列表。

N; data1, data2 .... dataN;

example: "100000; 1, 2, 3, 4, 5, ... 100000;" (A very large list)

简单解析:

auto rule = qi::int_ >> qi::lit(';') >> qi::int_ % ',' >> qi::lit(';');

但是,在这种情况下,我认为log2(N)次内存重新分配是根据std::vector的规范发生的。

我认为可以通过以下方法避免这种情况。

int size;
std::vector<int> v;
qi::phrase_parse(itr, end, qi::int_ >> qi::lit(';'), qi::space, size);
v.reserve(size); // reserve memory
qi::phrase_parse(itr, end, qi::int_ % ',' >> qi::lit(';'), qi::space, v);

有没有办法在像这样的单一规则上给出向量的内存分配提示?例如,它就像qi::repeat(N)。还是有一种技术可以避免重新分配矢量内存?

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

是。你可以保留一个动作。

更好的是,在epsilon参数中执行此操作,以便不会丢失自动属性传播。

概念证明: Live On Coliru

已更新:扩展了演示。事实证明,凤凰城已经有reservecapacity以及size的仿函数。

请注意

  • 现在保留区是语义动作
  • 规则使用%=启用自动属性传播,
  • 然后(具有讽刺意味?)使用qi::omit来防止将第一个int_属性插入到容器中

<强> Live On Coliru

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

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

int main() {
    using Attr = std::vector<int>;
    using It   = std::string::const_iterator;

    qi::rule<It, Attr(), qi::space_type> rule;

    rule %= qi::omit[qi::int_ [ px::reserve(qi::_val, qi::_1) ] >> ';' ]
         >> (qi::eps(px::size(qi::_val) < px::capacity(qi::_val)) >> qi::int_) % ','
         >> ';'
         ;

    for (std::string const input : { 
            "42; 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41;", })
    {
        It f = begin(input), l = end(input);
        Attr data;
        std::cout << "Capacity before: " << data.capacity() << "\n";

        if (phrase_parse(f, l, rule, qi::space, data))
            std::cout << "Parsed: " << data.size() << " elements ";
        else
            std::cout << "Parse failed at '" << std::string(f,l) << "' ";

        if (f != l)
            std::cout << "Remaining: '" << std::string(f,l) << "'";
        std::cout << '\n';

        std::cout << "Capacity after: " << data.capacity() << "\n";
    }
}

打印

Capacity before: 0
Parsed: 42 elements 
Capacity after: 42