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();
}

comments powered by Disqus