3

I am using a karma genarator thats consuming a vector of pairs - simular to http://boost-spirit.com/home/articles/karma-examples/output-generation-from-a-list-of-key-value-pairs-using-spirit-karma/

i built an example to show my problem following the article above

#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/karma.hpp>

namespace karma = boost::spirit::karma;
typedef std::pair<std::string, std::string > pair_type;

template <typename OutputIterator>    
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
    keys_and_values() : keys_and_values::base_type(query)
    {
        query =  *pair;
        // here is the interesting part
        pair  =  karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
    }
karma::rule<OutputIterator, std::vector<pair_type>()> query;
karma::rule<OutputIterator, pair_type()> pair;
};

int main(int argc, char *argv[])
{
    typedef std::back_insert_iterator<std::string> sink_type;

    std::vector<pair_type> v;
    v.push_back(pair_type("key1", "value1"));
    v.push_back(pair_type("key2", "value2"));
    v.push_back(pair_type("key3", "value3"));

    std::string generated;
    sink_type sink(generated);
    keys_and_values<sink_type> g;

    bool result = karma::generate(sink, g, v);

    std::cout << generated << std::endl;

    return 0;
}

What i am trying to achieve is an output like "value1 key1 value1". Normally it would output "key1 value1" (but only if you delete the third karma::string in my example) i already tried lots of stuff with semantic actions e.g.

pair = karma::string[karma::_1 = karma::_val] ...

However, that doesnt work. I probably need something else to get the value from my std::pair.

These 2 questions looked interesting but didnt solve my problem reuse parsed variable with boost karma How to access data of nested objects in boost::spirit::karma?

Rick
  • 33
  • 5
  • Following Mike M's comment in your first linked question, you could use something [like this](http://coliru.stacked-crooked.com/a/3a68e56f6fac0e77). – llonesmiz Oct 27 '14 at 07:07

1 Answers1

3

Although technically karma::duplicate[] would seem the natural match here, I'd probably resort to using a local here:

Update: As the commenter noted, I misread and swapped key/value. Here, BOOT_FUSION_ADAPT_STRUCT_NAMED would appear to be in order!

BOOST_FUSION_ADAPT_STRUCT_NAMED(
    pair_type const, pair_as_vkv,
    (std::string, second)
    (std::string, first)
    (std::string, second)
)

And, now you can just write

template <typename OutputIterator>
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
    keys_and_values() : keys_and_values::base_type(query)
    {
        query = *pair;
        pair = karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
    }
    karma::rule<OutputIterator, std::vector<pair_type>()> query;
    karma::rule<OutputIterator, boost::fusion::adapted::pair_as_vkv()> pair;
};

Without further ado: see it Live On Coliru

Output

value1 key1 value1
value2 key2 value2
value3 key3 value3

Full Listing

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/karma.hpp>

typedef std::pair<std::string, std::string> pair_type;

BOOST_FUSION_ADAPT_STRUCT_NAMED(
    pair_type const, pair_as_vkv,
    (std::string, second)
    (std::string, first)
    (std::string, second)
)

namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;

template <typename OutputIterator>
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
    keys_and_values() : keys_and_values::base_type(query)
    {
        query = *pair;
        pair = karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
    }
    karma::rule<OutputIterator, std::vector<pair_type>()> query;
    karma::rule<OutputIterator, boost::fusion::adapted::pair_as_vkv()> pair;
};

int main(int argc, char *argv[])
{
    typedef std::back_insert_iterator<std::string> sink_type;

    std::vector<pair_type> v;
    v.push_back(pair_type("key1", "value1"));
    v.push_back(pair_type("key2", "value2"));
    v.push_back(pair_type("key3", "value3"));

    std::string generated;
    sink_type sink(generated);
    keys_and_values<sink_type> g;

    karma::generate(sink, g, v);

    std::cout << generated << std::endl;

    return 0;
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • +1. Very nice, but I think the asker wants `value key value` which would complicate a little the rule. Edit: [Not so much](http://coliru.stacked-crooked.com/a/583a26213e31cd39). – llonesmiz Oct 27 '14 at 08:09
  • [Slight modification that may help with readability](http://coliru.stacked-crooked.com/a/f99baedad67b0146). – llonesmiz Oct 27 '14 at 08:17
  • @cv_and_he Oops. Good call. I think my updated answer wins the elegance contest :) (I had to [_visit the mailing list_](http://boost.2283326.n4.nabble.com/Proper-Spirit-usage-with-BOOST-FUSION-ADAPT-STRUCT-NAMED-td3453640.html) for subtle const-correctness hints though!) – sehe Oct 27 '14 at 09:25
  • 1
    Very interesting, shame I can't give you another +1. [This](http://coliru.stacked-crooked.com/a/ea41594344422261) is inspired by your approach (and the "qi/reorder_struct.cpp" example). – llonesmiz Oct 27 '14 at 10:21
  • @cv_and_he Wow. I love this game. It's so much better than code golfing. Virtual +1 for you too – sehe Oct 27 '14 at 10:22
  • 1
    thanks, it works perfectly :) so phoenix and fusion are able to solve my problem. i especially like that i dont need semantic actions anymore – Rick Oct 27 '14 at 12:58