2017-01-26 20 views
1

Я использую boost::asio::async_read_until, чтобы прочитать \n исправленную строку из сокета TCP. Позвольте мне, пожалуйста, помните, что async_read_until подпись следующее:Boost ASIO ForwardIterator для streambuf

http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/reference.html#boost_asio.reference.async_read_until

void-or-deduced async_read_until(
    AsyncReadStream & s, 
    boost::asio::basic_streambuf<Allocator> & b, 
    char delim, 
    ReadHandler handler); 

Здесь

boost::asio::streambuf b; 

является автоматическое изменения размера объекта для хранения полученных данных.

Насколько я понимаю, он внутренне состоит из последовательности буфера, списка буферов boost :: asio. Однако нет простого способа получить ForwardIterator для перебора этого внутреннего буфера, который состоит из нескольких смежных областей.

Я нахожу следующую схему использования:

std::istream stream(&b); 
std::istream_iterator<char> end; 
std::istream_iterator<char> begin(stream); 

Однако здесь end и begin являются InputIterators.

В то же время, boost::spirit::phrase_parse(begin, end, grammar, space, obj) анализатор, который может использоваться для синтаксического анализа, полученный из двинул линии требует begin и end быть ForwardIterators:

http://www.boost.org/doc/libs/1_63_0/libs/spirit/doc/html/spirit/support/multi_pass.html

Это требуется для возвратов. Однако данные на самом деле уже хранятся в буфере памяти в объекте boost::asio::streambuf b, ничто не мешает итератору разыменоваться более одного раза.

+0

Я мог бы написать свой собственный итератор (итерации по BufferSequenced элементам один за другим) и использовать b.data() для итерации по нему. Но, я думаю, должен быть стандартный способ ... – 0x2207

+0

@Nim вы можете просто выполнить многопроходную адаптацию streambuf_iterator (точно так же boost :: spirit :: istream_iterator адаптирует istream_iterator). Но даже это не нужно. Буферные итераторы буфера Asio отвечают требованиям, см. Мой ответ. – sehe

ответ

3

подталкивания имеет buffers_begin() и buffers_end(), которые вы можете использовать на streambuf «s data():

Live On Coliru

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

namespace a = boost::asio; 
namespace qi = boost::spirit::qi; 

#include <iostream> 
int main() 
{ 
    a::streambuf input; 
    std::ostream(&input) << "123, 4, 5; 78, 8, 9;\n888, 8, 8;"; 

    auto f = a::buffers_begin(input.data()), l = a::buffers_end(input.data()); 
    //std::copy(f, l, std::ostream_iterator<char>(std::cout)); 

    std::vector<std::vector<int> > parsed; 
    bool ok = qi::phrase_parse(f, l, *(qi::int_ % ',' >> ';'), qi::space, parsed); 

    if (ok) { 
     std::cout << "parsed: \n"; 
     for (auto& row : parsed) { 
      for (auto& v : row) { std::cout << v << " "; } 
      std::cout << ";\n"; 
     } 
    } 
    else 
     std::cout << "parse failed\n"; 

    if (f!=l) 
     std::cout << "remaining unparsed input: '" << std::string(f,l) << "'\n"; 
} 

Печать (как и ожидалось):

parsed: 
123 4 5 ; 
78 8 9 ; 
888 8 8 ; 

Примечание не забывайте consume() проанализированную часть входа!

+0

О, круто - я не понял, что 'buffers_begin()' et-al вернул подходящий итератор для этого! Я удалю свой комментарий .. – Nim

+0

Спасибо. Ответ имеет смысл. Я был уверен, что buffers_begin/end() повторяется над буферами последовательности. – 0x2207