Wednesday, 5 March 2008

Update: Serializing Boost.Tuple using Boost.Serialization

So as I often do while sleeping, I was thinking about the code I posted yesterday and I realized that it was way more complicated than it needed to be. I started out by writing:

template<typename Archive, typename T1>

void
serialize(Archive & ar,
boost::tuple<T1> & t,

const
unsigned int)
{

ar & t.get<0>();
}


But for some reason, when generalizing for more than one element, I starting using the head and tail members of the tuple. What I should have focused on was generating:
template<typename Archive, typename T1>

void
serialize(Archive & ar,
boost::tuple<T1> & t,

const
unsigned int)
{

ar & t.get<0>();
}


template
<typename Archive, typename T1, T2>
void
serialize(Archive & ar,

boost::tuple<T1,T2> & t,

const
unsigned int)
{


ar & t.get<0>();
ar & t.get<1>();
}
...

And in fact, this is quite easy to do using just the Boost Preprocessor. So simple that I smacked myself when I thought of it:

#include <boost/tuple/tuple.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/preprocessor/repetition.hpp>

namespace boost { namespace serialization {

#define GENERATE_ELEMENT_SERIALIZE(z,which,unused) \
ar & boost::serialization::make_nvp("element",t.get< which >());

#define GENERATE_TUPLE_SERIALIZE(z,nargs,unused) \
template< typename Archive, BOOST_PP_ENUM_PARAMS(nargs,typename T) > \
void serialize(Archive & ar, \
boost::tuple< BOOST_PP_ENUM_PARAMS(nargs,T) > & t, \
const unsigned int version) \
{ \
BOOST_PP_REPEAT_FROM_TO(0,nargs,GENERATE_ELEMENT_SERIALIZE,~); \
}


BOOST_PP_REPEAT_FROM_TO(1,6,GENERATE_TUPLE_SERIALIZE,~);

}}

6 comments:

Anonymous said...

I had to iterate through boost::tuple too.
Its possible to so with some mpl tricks:

http://www.c-plusplus.de/forum/viewtopic-var-p-is-1474821.html#1474821

wouldn't that also work for archive?

Sohail Somani said...

Yes, I believe that would work just fine. I'm not sure there is any mpl trick in there. In this case, the call function would take in the tuple and the archive. Quite elegant actually. Thanks for the tip.

Anonymous said...

I think that could be turned into some interface.
You could handover a functor, taking the tupleelement.

Actually that should be possible with boost::fusion.

Sohail Somani said...

Actually I did consider using fusion to start with. My previous experience with it has been very slow compile times whereas the preprocessor lib is quite fast for most things. That view is probably outdated by now.

Anonymous said...

yeah, fusion can take a lot of memory when compiling. Did a project with spirit2 and fusion2. But for this, I think it should be pretty fast.

Sohail Somani said...

If I get a chance, I'll do it both ways, benchmark and post the results.