prevent multipass iterators from consuming on incomplete parse

Stephan Menzel <[email protected]> Wed, 22 May 2019 11:06:00 +0100
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <CAEQ568uM86n-QFiKMtyN0brPfr0a0XtdNzLq_1aQnNn160-p4A@mail.gmail.com>
Hello all,

I'm working on a spirit based redis client (
https://github.com/MrMoose/mredis/blob/master/RESP.cpp) and make heavy use
of multi-pass iterators, which I have now discovered a problem with. I seek
advice on how to solve this.

Basically, I have a number of grammars that parse specific message types
and then an alternative message type:

    template <typename InputIterator>
    struct message_parser : qi::grammar<InputIterator, RedisMessage()> {

    message_parser() : message_parser::base_type(m_start, "message") {
         m_start %= m_simple_string | m_integer | m_array | m_null_result |
m_bulk_string | m_error;
    }

    integer_parser<InputIterator>        m_integer;
    simple_string_parser<InputIterator>  m_simple_string;
    bulk_string_parser<InputIterator>    m_bulk_string;
    null_parser<InputIterator>           m_null_result;
    array_parser<InputIterator>          m_array;
    error_parser<InputIterator>          m_error;
    qi::rule<InputIterator, RedisMessage()>  m_start;
    };

Each parser parses one message. I parse those messages directly from an
asio streambuf object and use multipass iterators to do this:

    boost::spirit::multi_pass<stream_iterator_type> first =

boost::spirit::make_default_multi_pass(stream_iterator_type(n_input_stream));
    const boost::spirit::multi_pass<stream_iterator_type> last =
        boost::spirit::make_default_multi_pass(stream_iterator_type());

    const bool retval = qi::parse(first, last, s_response_parser,
n_response);

Now I ran into problems with large messages and after extensive debugging I
found that the multipass iterator will consume the input when it parses
part of a message but not the entire message.

Like when the stream contains the beginning of a large message but it is
incomplete and I need to continue reading. parse() will fail and I see
remaining bytes in the buffers but those parts of the message that were
parsed are already missing.

I suppose this page explains the background:
https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/html/spirit/support/multi_pass.html

Sadly, I don't really understand what this means to me and my use case. How
can I prevent this from happening? I have tried adding flush_multi_pass at
the end of each seperate message but that didn't help.

What I need is for the stream to be "unconsumed", untouched, when the
overall parse command fails and no complete message could be parsed. Is
this possible?

Thanks for any input!

Stephan

_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general