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

Can I give hints to the list operator(%) for memory allocation in Boost.Spirit.Qi?

本文关键字:内存 分配 提示 Spirit Boost Qi 运算符 列表 我可以      更新时间:2023-10-16

我想解析以下数据列表。

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).或者有没有一种技术可以避免重新分配矢量内存?

提前感谢您的帮助。

是的。您可以在操作中保留。

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

概念验证:住在科里鲁

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

请注意,

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

住在科里鲁

#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