2008-02-10
boost::serialization
boost::serialization 은, 템플릿 멤버 함수 하나 또는 free function 하나만 정의하면, 해당 클래스를 다양한 스트림으로 직렬화할 수 있게 해준다. 특히 list - vector - map - set 등의 다양한 STL 컨테이너들을 지원한다는 것이 장점이다.
이때, 매크로 없이 & 연산자 만으로 읽고 쓰기를 가능하게 했는데, 이건 템플릿 아카이브 파라미터가 알아서 잘 읽거나 쓰도록 책임을 전가했다는 게 상당히 아름답다.. 단, virtual 이 아니라서 하위 클래스는 모두 이걸 정의해줘야 한다. 그리고 아직 hash_map 은 잘 지원하지 않는 모양인데, 뭔가 복잡한 사정이 있는 듯하다.
주의할 점이라면 아래 예제처럼 쓰려는 객체가 const 여야 한다는 점 정도?
#include "stdafx.h"
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/hash_map.hpp>
class chat_message
{
friend class boost::serialization::access;
public:
chat_message() {}
chat_message(unsigned short id, unsigned short body_length, string msg, wstring wmsg)
: id_(id)
, body_length_(body_length)
, message(msg)
, wmessage(wmsg)
{
for ( size_t i = 0 ; i < 10 ; i ++ )
{
string val = boost::str(boost::format("Hello %1%")%i);
messages[i] = val;
array_[i] = val;
list_.push_back(i);
vector_.push_back(i);
map_[i] = val;
hash_map_[val] = (rand()%2==0 ? true : false);
}
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & id_;
ar & body_length_;
ar & message;
ar & wmessage;
ar & messages; // pritimive array
ar & array_.elems; // boost::array
ar & list_; // std::list
ar & vector_; // std::vector
ar & map_; // std::map
//ar & hash_map_;
}
void check_equal( const chat_message & r ) const
{
BOOST_CHECK_EQUAL(id_,r.id_);
BOOST_CHECK_EQUAL(body_length_,r.body_length_);
BOOST_CHECK_EQUAL(message,r.message);
BOOST_CHECK(wmessage==r.wmessage);
for ( size_t i = 0 ; i < 10 ; i ++ )
{
BOOST_CHECK_EQUAL(messages[i],r.messages[i]);
}
for ( size_t i = 0 ; i < array_.size() ; i ++ )
{
BOOST_CHECK_EQUAL(array_[i],r.array_[i]);
}
{
BOOST_REQUIRE_EQUAL( list_.size(), r.list_.size() );
list<float>::const_iterator itr = list_.begin();
list<float>::const_iterator itr2 = r.list_.begin();
for ( ; itr != list_.end() ; itr ++, itr2++ )
{
BOOST_CHECK_EQUAL( *itr, *itr2 );
}
}
{
BOOST_REQUIRE_EQUAL( vector_.size(), r.vector_.size() );
vector<int>::const_iterator itr = vector_.begin();
vector<int>::const_iterator itr2 = r.vector_.begin();
for ( ; itr != vector_.end() ; itr ++, itr2++ )
{
BOOST_CHECK_EQUAL( *itr, *itr2 );
}
}
{
BOOST_REQUIRE_EQUAL( map_.size(), r.map_.size() );
map<int,string>::const_iterator itr = map_.begin();
map<int,string>::const_iterator itr2 = r.map_.begin();
for ( ; itr != map_.end() ; itr ++, itr2++ )
{
BOOST_CHECK_EQUAL( itr->first, itr2->first );
BOOST_CHECK_EQUAL( itr->second, itr2->second );
}
}
//{
// BOOST_REQUIRE_EQUAL( hash_map_.size(), r.hash_map_.size() );
// stdext::hash_map<string,bool>::const_iterator itr = hash_map_.begin();
// stdext::hash_map<string,bool>::const_iterator itr2 = r.hash_map_.begin();
// for ( ; itr != hash_map_.end() ; itr ++, itr2++ )
// {
// BOOST_CHECK_EQUAL( itr->first, itr2->first );
// BOOST_CHECK_EQUAL( itr->second, itr2->second );
// }
//}
}
private :
unsigned short id_;
unsigned short body_length_;
string message;
wstring wmessage;
string messages[10];
boost::array<string,10> array_;
list<float> list_;
vector<int> vector_;
map<int,string> map_;
stdext::hash_map<string,bool> hash_map_;
};
// TODO
// - archive from/to buffer
// - user defined archive
// - string, wstring load/save
// - stl support (list,vector,map)
BOOST_AUTO_TEST_CASE(test_serialize)
{
const chat_message msg1(35, 59, "Hello World!",L"Welcome!");
{
chat_message msg2;
std::ofstream ofs("serialize.txt");
boost::archive::text_oarchive oa(ofs);
oa << msg1;
ofs.close();
std::ifstream ifs("serialize.txt");
boost::archive::text_iarchive ia(ifs);
ia >> msg2;
ifs.close();
msg1.check_equal(msg2);
}
{
chat_message msg2;
std::ofstream ofs("serialize.bin", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << msg1;
ofs.close();
std::ifstream ifs("serialize.bin", std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> msg2;
ifs.close();
msg1.check_equal(msg2);
}
{
chat_message msg2;
boost::asio::streambuf buf;
ostream os(&buf);
boost::archive::text_oarchive oa(os);
oa << msg1;
istream is(&buf);
boost::archive::text_iarchive ia(is);
ia >> msg2;
msg1.check_equal(msg2);
}
{
chat_message msg2;
boost::asio::streambuf osf;
boost::archive::binary_oarchive oa(osf);
oa << msg1;
boost::archive::binary_iarchive ia(osf);
ia >> msg2;
msg1.check_equal(msg2);
}
// via istream/ostream
{
chat_message msg2;
boost::asio::streambuf buf;
ostream os(&buf);
boost::archive::binary_oarchive oa(os);
oa << msg1;
istream is(&buf);
boost::archive::binary_iarchive ia(is);
ia >> msg2;
msg1.check_equal(msg2);
}
}