eliaskosunen / scnlib

scanf for modern C++
https://scnlib.dev
Apache License 2.0
1.08k stars 47 forks source link

runtime performance comparison with boost::spirit::x3 #9

Open do-m-en opened 5 years ago

do-m-en commented 5 years ago

At a first glance this library seems to be targeting simple pattern parsing and not grammar parsing (that's the one that I need most of the time) but simple parsing can also be done with boost spirit x3 so I use that library for more or less for all string parsing.

Since this is library is now the basis of a C++ standard proposal I'd be interested in the runtime performance compared to the library that I would like to see being the basis of a standardization efforts - boost::spirit::x3.

I wasn't able to find an example but my basic pattern is usually not a single item but a list of items of unknown length so comparison with something like this would be nice:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>

#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string str{"1.3, 4.5, 20"};

    using boost::spirit::x3::double_;
    using boost::spirit::x3::phrase_parse;
    using boost::spirit::x3::ascii::space;

    std::vector<double> my_vector;

    bool r = phrase_parse(
        str.begin(),
        str.end(),
        double_ >> *(',' >> double_),
        space,
        my_vector
    );
    if (!r) // fail if we did not get a full match
        return 1;

    std::cout << "-------------------------\n";
    std::cout << "Parsing succeeded\n";

    for(auto f : my_vector)
        std::cout << f << ",\n";

    return 0;
}

This can be executed inside https://wandbox.org/

eliaskosunen commented 5 years ago

I will look into this after the Cologne WG21 meeting.

To go over it quickly, something like this can be achieved with scn::getline, in a similar fashion to std::getline with strings, although you'd need to jump through a few hoops. Your use case seems like quite a common one, however, and perhaps doing something like that should be easier. As I said, I'll look into it in about a week.

eliaskosunen commented 5 years ago

I created a repo comparing your above example with a somewhat equivalent example with scnlib: https://github.com/eliaskosunen/scnlib-spirit-benchmark

Spirit is almost twice as fast in this example. This is because scnlib doesn't support this use case well; there's a lot of boilerplate compared to spirit, and the input needs to be scanned and the stream needs to be allocated twice. I consider this a bug, and this is something that needs to be fixed before the next release.

eliaskosunen commented 5 years ago

Actually, my benchmarks were a little off; the time difference is ~25%. This is still a bug, though

eliaskosunen commented 5 years ago

By making string_view work with scn::getline the difference is now ~15%