2009-02-17
boost::preprocessor
boost::preprocessor 는 템플릿을 이용한 메타프로그래밍에 있어서, 템플릿 파라미터들의 반복 같은 "문자열 토큰들의 패턴 처리"를 매크로를 이용해서 손쉽게 처리해주는 라이브러리이다. 보다 상세한 용법은 공식 홈페이지 혹은 레인님 블로그와 리카넷 블로그를 참조하기 바란다.
이걸 이용해서 몇 주전에 포스팅한 boost::tuple 의 직렬화 코드를 만들어봤다. 원래 계획과는 좀 많이 바뀌긴 했는데, 구글로 검색해보니 tuple 을 boost::serialization 으로 직렬화하는 예제가 를 (상당 부분!) 참조했음을 밝힌다.
남은 작업은 여기에 vector 와 list 를 자동으로 직렬화하는 건데, 어째 아무리 검색해봐도 is_vector 라든지 is_list 같은 넘이 없어서 일단은 포기. 결국 mpl 을 뒤져봐야 할지도 모르겠다.
#include "stdafx.h"
#include <boost/tuple/tuple.hpp>
#include <string>
#include <vector>
#include <string>
#include <gtest/gtest.h>
using namespace boost;
using namespace std;
#include <boost/preprocessor/repetition.hpp>
typedef unsigned short strlen_t;
template< class V >
int to_binary( char* buf, const V & v )
{
size_t len = sizeof(v);
memcpy(buf,(const void*)&v,len);
return len;
}
template<class T>
int from_binary( const char * buf, T & t )
{
size_t len = sizeof(t);
memcpy((void*)&t,buf,len);
return len;
}
template<>
int to_binary( char* buf, const string & s )
{
strlen_t sz = (strlen_t)s.size();
memcpy(buf,&sz,sizeof(sz));
if ( sz > 0 )
{
memcpy(buf+sizeof(sz),s.c_str(),sz);
}
return sizeof(sz)+sz;
}
template<>
int from_binary( const char * buf, string & str )
{
strlen_t sz;
memcpy((void*)&sz,buf,sizeof(sz));
if ( sz > 0 )
{
str.assign(buf+sizeof(sz),sz);
assert(str.size()==sz);
}
return sizeof(sz)+sz;
}
template<>
int to_binary( char* buf, const wstring & s )
{
strlen_t sz = (strlen_t)s.size();
memcpy(buf,&sz,sizeof(sz));
if ( sz > 0 )
{
memcpy(buf+sizeof(sz),s.c_str(),sz*sizeof(wchar_t));
}
return sizeof(sz)+sz*sizeof(wchar_t);
}
template<>
int from_binary( const char * buf, wstring & str )
{
strlen_t sz;
memcpy((void*)&sz,buf,sizeof(sz));
if ( sz > 0 )
{
str.assign((wchar_t*)(buf+sizeof(sz)),sz);
assert(str.size()==sz);
}
return sizeof(sz)+sz*sizeof(wchar_t);
}
#define TO_BINARY(z,which,unused) \
byte_written = to_binary( buf + offset, t.get<which>() );\
if ( byte_written < 0 ) { return which; }\
offset += byte_written;
#define TUPLE_TO_BINARY(z,nargs,unused) \
template< BOOST_PP_ENUM_PARAMS(nargs,typename T) > \
int tuple_to_binary( const boost::tuple< BOOST_PP_ENUM_PARAMS(nargs,T) > & t, char * buf, size_t max_len ) \
{ \
int offset = 0; \
int byte_written = 0; \
BOOST_PP_REPEAT_FROM_TO(0,nargs,TO_BINARY,~); \
return offset; \
}
BOOST_PP_REPEAT_FROM_TO(1,6,TUPLE_TO_BINARY,~);
#define FROM_BINARY(z,which,unused) \
byte_read = from_binary( buf + offset, t.get<which>() );\
if ( byte_read < 0 ) { return which; }\
offset += byte_read;
#define BINRY_TO_TUPLE(z,nargs,unused) \
template< BOOST_PP_ENUM_PARAMS(nargs,typename T) > \
int binary_to_tuple( boost::tuple< BOOST_PP_ENUM_PARAMS(nargs,T) > & t, char * buf, size_t max_len ) \
{ \
int offset = 0; \
int byte_read = 0; \
BOOST_PP_REPEAT_FROM_TO(0,nargs,FROM_BINARY,~); \
return offset; \
}
BOOST_PP_REPEAT_FROM_TO(1,6,BINRY_TO_TUPLE,~);
//template< class T0>
//int binary_to_tuple( boost::tuple<t0> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// return offset;
//}
//
//template< class T0 >
//int tuple_to_binary( const boost::tuple<t0> & t, char * buf, size_t max_len )
//{
// int offset = 0;
// int byte_written = 0;
//
// byte_written = to_binary( buf + offset, t.get<0>() );
// if ( byte_written < 0 )
// {
// // error
// return 0;
// }
// offset += byte_written;
//
// return offset;
//}
//
//
//template< class T0, class T1>
//int tuple_to_binary( const boost::tuple<t0,T1> & t, char * buf, size_t max_len )
//{
// int offset = 0;
// int byte_written = 0;
//
// byte_written = to_binary( buf + offset, t.get<0>() );
// if ( byte_written < 0 )
// {
// // error
// return 0;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<1>() );
// if ( byte_written < 0 )
// {
// // error
// return -1;
// }
// offset += byte_written;
//
// return offset;
//}
//
//
//template< class T0, class T1, class T2>
//int tuple_to_binary( const boost::tuple<t0,T1,T2> & t, char * buf, size_t max_len )
//{
// int offset = 0;
// int byte_written = 0;
//
// byte_written = to_binary( buf + offset, t.get<0>() );
// if ( byte_written < 0 )
// {
// // error
// return 0;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<1>() );
// if ( byte_written < 0 )
// {
// // error
// return -1;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<2>() );
// if ( byte_written < 0 )
// {
// // error
// return -2;
// }
// offset += byte_written;
//
// return offset;
//}
//
//
//template< class T0, class T1, class T2, class T3>
//int tuple_to_binary( const boost::tuple<t0,T1,T2,T3> & t, char * buf, size_t max_len )
//{
// int offset = 0;
// int byte_written = 0;
//
// byte_written = to_binary( buf + offset, t.get<0>() );
// if ( byte_written < 0 )
// {
// // error
// return 0;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<1>() );
// if ( byte_written < 0 )
// {
// // error
// return -1;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<2>() );
// if ( byte_written < 0 )
// {
// // error
// return -2;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<3>() );
// if ( byte_written < 0 )
// {
// // error
// return -3;
// }
// offset += byte_written;
//
// return offset;
//}
//
//template< class T0, class T1, class T2, class T3, class T4 >
//int tuple_to_binary( const boost::tuple<t0,T1,T2,T3,T4> & t, char * buf, size_t max_len )
//{
// int offset = 0;
// int byte_written = 0;
//
// //{
// // size_t sz0 = sizeof( tuples::element<0,TUPLE>::type );
// // assert( sz0 == sizeof(int) );
// // size_t sz1 = sizeof( tuples::element<1,TUPLE>::type );
// // assert( sz1 == sizeof(char) );
// // size_t sz2 = sizeof( tuples::element<2,TUPLE>::type );
// // assert( sz2 == sizeof(string) );
// // size_t sz3 = sizeof( tuples::element<3,TUPLE>::type );
// // assert( sz3 == sizeof(float) );
// // size_t sz4 = sizeof( tuples::element<4,TUPLE>::type );
// // assert( sz4 == sizeof(bool) );
// //}
//
// byte_written = to_binary( buf + offset, t.get<0>() );
// if ( byte_written < 0 )
// {
// // error
// return 0;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<1>() );
// if ( byte_written < 0 )
// {
// // error
// return -1;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<2>() );
// if ( byte_written < 0 )
// {
// // error
// return -2;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<3>() );
// if ( byte_written < 0 )
// {
// // error
// return -3;
// }
// offset += byte_written;
//
// byte_written = to_binary( buf + offset, t.get<4>() );
// if ( byte_written < 0 )
// {
// // error
// return -4;
// }
// offset += byte_written;
//
// return offset;
//}
//template< class T0>
//int binary_to_tuple( boost::tuple<t0> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// return offset;
//}
//
//template< class T0, class T1>
//int binary_to_tuple( boost::tuple<t0,T1> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<1>() );
// if ( byte_read < 0 )
// {
// // error
// return -1;
// }
// offset += byte_read;
//
// return offset;
//}
//
//template< class T0, class T1, class T2>
//int binary_to_tuple( boost::tuple<t0,T1,T2> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<1>() );
// if ( byte_read < 0 )
// {
// // error
// return -1;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<2>() );
// if ( byte_read < 0 )
// {
// // error
// return -2;
// }
// offset += byte_read;
//
// return offset;
//}
//
//template< class T0, class T1, class T2, class T3>
//int binary_to_tuple( boost::tuple<t0,T1,T2,T3> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<1>() );
// if ( byte_read < 0 )
// {
// // error
// return -1;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<2>() );
// if ( byte_read < 0 )
// {
// // error
// return -2;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<3>() );
// if ( byte_read < 0 )
// {
// // error
// return -3;
// }
// offset += byte_read;
//
// return offset;
//}
//
//template< class T0, class T1, class T2, class T3, class T4 >
//int binary_to_tuple( boost::tuple<t0,T1,T2,T3,T4> & t, const char * buf, size_t len )
//{
// int offset = 0;
//
// int byte_read = from_binary( buf + offset, t.get<0>() );
// if ( byte_read < 0 )
// {
// // error
// return 0;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<1>() );
// if ( byte_read < 0 )
// {
// // error
// return -1;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<2>() );
// if ( byte_read < 0 )
// {
// // error
// return -2;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<3>() );
// if ( byte_read < 0 )
// {
// // error
// return -3;
// }
// offset += byte_read;
//
// byte_read = from_binary( buf + offset, t.get<4>() );
// if ( byte_read < 0 )
// {
// // error
// return -4;
// }
// offset += byte_read;
//
// return offset;
//}
#define TUPLE_TO_BINARY_TO_TUPLE(t,t1) \
char buf[1024];\
int len = tuple_to_binary(t,buf,1024);\
int len2 = binary_to_tuple(t1,buf,len);\
EXPECT_EQ( len2 , len )
TEST(tuple_to_binary,test1)
{
typedef tuple<int> my_tuple;
my_tuple t, t1;
t.get<0>() = 1024;
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
}
TEST(tuple_to_binary,boolean)
{
typedef tuple<bool,bool> my_tuple;
my_tuple t, t1;
t.get<0>() = true;
t.get<1>() = false;
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
}
TEST(tuple_to_binary,wstring)
{
typedef tuple<string,wstring> my_tuple;
my_tuple t, t1;
t.get<0>() = "Hello";
t.get<1>() = L"World";
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
}
TEST(tuple_to_binary,test2_empty_string)
{
typedef tuple<wstring,wstring> my_tuple;
my_tuple t, t1;
t.get<0>() = L"Hello";
t.get<1>() = L"";
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
}
TEST(tuple_to_binary,test2)
{
typedef tuple<int,char> my_tuple;
my_tuple t, t1;
t.get<0>() = 1024;
t.get<1>() = 'A';
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
}
TEST(tuple_to_binary,test3)
{
typedef tuple<int,char,string> my_tuple;
my_tuple t, t1;
t.get<0>() = 1024;
t.get<1>() = 'A';
t.get<2>() = "Hello World";
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
EXPECT_EQ( t.get<2>() , t1.get<2>() );
}
TEST(tuple_to_binary,test4)
{
typedef tuple<int,char,string,float> my_tuple;
my_tuple t, t1;
t.get<0>() = 1024;
t.get<1>() = 'A';
t.get<2>() = "Hello World";
t.get<3>() = 12.34f;
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
EXPECT_EQ( t.get<2>() , t1.get<2>() );
EXPECT_EQ( t.get<3>() , t1.get<3>() );
}
TEST(tuple_to_binary,test5)
{
typedef tuple<int,char,string,float,bool> my_tuple;
my_tuple t, t1;
t.get<0>() = 1024;
t.get<1>() = 'A';
t.get<2>() = "Hello World";
t.get<3>() = 12.34f;
t.get<4>() = false;
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>() , t1.get<0>() );
EXPECT_EQ( t.get<1>() , t1.get<1>() );
EXPECT_EQ( t.get<2>() , t1.get<2>() );
EXPECT_EQ( t.get<3>() , t1.get<3>() );
EXPECT_EQ( t.get<4>() , t1.get<4>() );
}
TEST(tuple_to_binary,struct)
{
struct my_struct
{
int i;
char c;
float f;
bool b;
};
typedef tuple<my_struct> my_tuple;
my_tuple t, t1;
t.get<0>().i = 1024;
t.get<0>().c = 'A';
t.get<0>().f = 12.34f;
t.get<0>().b = false;
TUPLE_TO_BINARY_TO_TUPLE(t,t1);
EXPECT_EQ( t.get<0>().i , t1.get<0>().i );
EXPECT_EQ( t.get<0>().c , t1.get<0>().c );
EXPECT_EQ( t.get<0>().f , t1.get<0>().f );
EXPECT_EQ( t.get<0>().b , t1.get<0>().b );
}
//TEST(tuple_to_binary,vector)
//{
// struct my_struct
// {
// int i;
// char c;
// float f;
// bool b;
// };
//
// typedef vector<my_struct> my_structs;
// typedef tuple<my_structs> my_tuple;
//
// my_tuple t, t1;
//
// for ( size_t i = 0 ; i < 10 ; i ++ )
// {
// my_struct s;
// s.i = 1024;
// s.c = 'A';
// s.f = 12.34f;
// s.b = false;
//
// t.get<0>().push_back(s);
// }
//
// TUPLE_TO_BINARY_TO_TUPLE(t,t1);
//
// const my_structs & slist = t.get<0>();
// const my_structs & slist1 = t1.get<0>();
//
// EXPECT_EQ( slist1.size(), slist.size() );
// for ( size_t j = 0 ; j < slist1.size() ; j ++ )
// {
// const my_struct & s = slist[j];
// const my_struct & s1 = slist1[j];
//
// EXPECT_EQ( s1.i , s.i );
// EXPECT_EQ( s1.c , s.c );
// EXPECT_EQ( s1.f , s.f );
// EXPECT_EQ( s1.b , s.b );
// }
//}
int main(int argc, char **argv) {
cout << "Running main() from gtest_main.cc\n";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Source: http://boxcatstudio.wordpress.com/2009/02/17/boost-preprocessor/
Category:programming
Tags:boostpreprocessor
Category:programming
Tags:boostpreprocessor