2017-01-26 5 views
1

boost::asio::async_read_untilを使用して、TCPソケットから\n -ended行を読み取ります。ここでstreambufのASIO ForwardIteratorをブーストする

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; 

は、受信したデータを格納するための自動リサイズ対象である:私はasync_read_until署名は、次のされていることを思い出してくださいしてみましょう。

私が理解する限り、内部的にバッファシーケンス、boost :: asioバッファのリストで構成されています。しかし、ForwardIteratorを取得して、複数の連続した領域で構成されるこの内部バッファを反復処理する簡単な方法はありません。

私は、次の使用パターンを見つける:

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

はしかし、ここendbeginはInputIteratorsです。

同時に、酔っぱらっラインから得られた解析するために使用することができるboost::spirit::phrase_parse(begin, end, grammar, space, obj)パーサはbeginendとは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要素を1つずつ繰り返します)を書き、b.data()を使ってそれを反復することができます。しかし、私は標準的な方法があるべきだと思います... – 0x2207

+0

@Nim単純にマルチパスでstreambuf_iteratorを適応させることができます(boost :: spirit :: istream_iteratorはistream_iteratorに適応します)。しかしそれは不必要です。 Asioのバッファ・イテレータが要件を満たすことを促進する、私の答えを見てください。 – sehe

答えて

3

ブーストは、あなたがstreambufdata()に使用することができますbuffers_begin()buffers_end()を持っています

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

関連する問題