Недавно наткнулся у себя на винте на boost serialization library, которая проходила проверку в прошлом году, однако я так и не понял, почему она не была принята и на какой стадии она сейчас — информацию на сайте boost хрен найдёшь, нужно лезть в архивы рассылки, а это дело весьма утомительное. На Wiki вообще про serialization не слова.
Прошлогодняя версия
здесь.
Неплохая либа, вот только не люблю я дублировать все записи/чтения для save/load отдельно. Поэтому накарябал маленький адаптер, чтобы совместить save/load в одной шаблонной функции.
//-----------------------------------------------------------------------------
// serializer_simple.h
// Initial coding: 2003/07/05 18:14
// Purpose: boost::serialization wrapper, to make save/load simplier
//-----------------------------------------------------------------------------
#pragma once
#include <boost/serialization.hpp>
//-----------------------------------------------------------------------------
namespace lim_internal {
struct Load
{
boost::basic_iarchive& _ar;
boost::version_type _ver;
bool _process;
Load(boost::basic_iarchive& ar, boost::version_type ver, bool process=true)
: _ar(ar), _ver(ver), _process(process)
{}
template<class T> Load& operator,(const T& t)
{
if (_process)
_ar>>(T&)t;
return *this;
}
Load operator!()
{ return Load(_ar,_ver,!_process); }
Load operator()(boost::version_type min_ver)
{ return Load(_ar,_ver, (min_ver<=_ver)?true:false); }
Load operator()(boost::version_type min_ver, boost::version_type max_ver)
{ return Load(_ar,_ver, ((min_ver<=_ver)&&(max_ver>=_ver))?true:false); }
};
struct Save
{
boost::basic_oarchive& _ar;
boost::version_type _ver;
bool _process;
Save(boost::basic_oarchive& ar, boost::version_type ver, bool process=true)
: _ar(ar), _ver(ver), _process(process)
{}
template<class T> Save& operator,(const T& t)
{
if (_process)
_ar<<t;
return *this;
}
Save operator!()
{ return Save(_ar,_ver,!_process); }
Save operator()(boost::version_type min_ver)
{ return Save(_ar,_ver, (min_ver<=_ver)?true:false); }
Save operator()(boost::version_type min_ver, boost::version_type max_ver)
{ return Save(_ar,_ver, ((min_ver<=_ver)&&(max_ver>=_ver))?true:false); }
};
}
//-----------------------------------------------------------------------------
//по-умолчанию переадресация в метод класса.
template <class T, class Serializer> inline void serializer(const T& t, Serializer& s)
{ t.serializer(s); }
// Переадресация boost::serialization в наш адаптер.
// Определять после определения вашей специализации шаблона сериализатора.
#define SERIALIZER(Type,ver) \
inline void serialization<Type>::save(boost::basic_oarchive &ar, const Type &t) \
{ return serializer(t,lim_internal::Save(ar,ver)); } \
inline void serialization<Type>::load(boost::basic_iarchive &ar, Type &t, boost::version_type saved_version) \
{ return serializer(t,lim_internal::Load(ar,saved_version)); } \
inline boost::version_type serialization<Type>::version(const Type &t) \
{ return ver; }
Использовать так:
// test_serialization.cpp : Defines the entry point for the console application.
//
#include "serializer_simple.h"
#include <iostream>
#include <fstream>
using namespace std;
struct MapTile
{ char tile,obj,unit,force,vis; }; //vis добавлен позднее.
//! external serialization of MapTile
template<class Serializer> void serializer(const MapTile& t, Serializer& s)
{
s, t.tile, t.obj, t.unit, t.force; //для всех версий
s(2), t.vis; //только в версии 2 и более поздних
}
SERIALIZER(MapTile,2); //если поставить версию 0 или 1, то не будет сериализован t.vis
//возможно определение serializer-а внутри класса.
//! with internal serialization
struct MapTile2
{
char tile,obj,unit,force,vis;
template<class Serializer> void serializer(Serializer& s) const
{
s, tile, obj, unit, force; //для всех версий
s(2), vis; //только в версии 2 и более поздних
}
};
SERIALIZER(MapTile2,2);
//-----------------------------------------------------------------------------
ostream& operator<<(ostream& os, const MapTile& m)
{ return os<<m.tile<<m.obj<<m.unit<<m.force<<m.vis; }
ostream& operator<<(ostream& os, const MapTile2& m)
{ return os<<m.tile<<m.obj<<m.unit<<m.force<<m.vis; }
MapTile _map;
void load(const char* path)
{
cout<<"loading "<<path<<endl;
std::ifstream ifs(path, std::ios::binary);
boost::biarchive ia(ifs);
ia>>_map;
ifs.close();
}
void save(const char* path)
{
cout<<"saving "<<path<<endl;
std::ofstream ofs(path, std::ios::binary);
boost::boarchive oa(ofs);
oa<<_map;
ofs.close();
}
int main( )
{
_map.tile='t';
_map.obj='o';
_map.unit='u';
_map.force='f';
_map.vis='v';
cout<<_map<<endl;
save("test_map1.bin");
cout<<"changing..."<<endl;
_map.tile='-';
_map.obj='-';
_map.vis='-';
cout<<_map<<endl;
load("test_map1.bin");
cout<<_map<<endl;
return 0;
}
Можно дальше поиграть с определением Load/Save.
Например
!s(2,4),xxx вызовет сериализацию xxx для всех версий, кроме 2,3,4.
s(1,1),xxx — только версию 1, но ни 0, ни 2.
Можно свои операторы/методы добавить и т.п.
Обновление.
Базовый класс для Save/Load адаптеров, для общих фич, например выбор версии.
Более интуитивный выбор версий, например s>=3,a,b,c,d; или s<3,xxx;
Исправлена поддержка массивов. (Контейнеры и всё остальное и раньше работало)
SERIALIZER_MEMBER для объявления внутри класса.
//-----------------------------------------------------------------------------
// serializer_simple.h
// Initial coding: 2003/07/05 18:14
// Purpose: boost::serialization wrapper, to make save/load simplier
//-----------------------------------------------------------------------------
#pragma once
#include <boost/serialization.hpp>
//-----------------------------------------------------------------------------
namespace lim_serialization
{
//generic for both Save and Load
template<class Serializer, class Arch> struct SerializerT
{
typedef SerializerT<Serializer,Arch> Base;
typedef Arch Archive;
typedef boost::version_type Version;
Archive& _ar;
Version _ver;
bool _process;
SerializerT(Archive& ar, Version ver, bool process=true)
: _ar(ar), _ver(ver), _process(process)
{}
Serializer operator!()
{ return Serializer(_ar,_ver,!_process); }
Serializer operator()(Version min_ver)
{ return Serializer(_ar,_ver, (min_ver<=_ver)?true:false); }
Serializer operator()(Version min_ver, Version max_ver)
{ return Serializer(_ar,_ver, ((min_ver<=_ver)&&(max_ver>=_ver))?true:false); }
Serializer operator<(Version min_ver)
{ return Serializer(_ar,_ver, (_ver<min_ver)?true:false); }
Serializer operator>(Version min_ver)
{ return Serializer(_ar,_ver, (_ver>min_ver)?true:false); }
Serializer operator<=(Version min_ver)
{ return Serializer(_ar,_ver, (_ver<=min_ver)?true:false); }
Serializer operator>=(Version min_ver)
{ return Serializer(_ar,_ver, (_ver>=min_ver)?true:false); }
Serializer operator==(Version min_ver)
{ return Serializer(_ar,_ver, (_ver==min_ver)?true:false); }
Serializer operator!=(Version min_ver)
{ return Serializer(_ar,_ver, (_ver!=min_ver)?true:false); }
};
//Load adapter
struct Load : SerializerT<Load,boost::basic_iarchive>
{
Load(Archive& ar, Version ver, bool process=true)
: Base(ar,ver,process)
{}
template<class T, size_t N> Load& operator,(const T (&t)[N])
{
if (_process)
_ar>>(T (&)[N])t;
return *this;
}
template<class T> Load& operator,(const T& t)
{
if (_process)
_ar>>(T&)t;
return *this;
}
};
//Save adapter
struct Save : SerializerT<Save,boost::basic_oarchive>
{
Save(Archive& ar, Version ver, bool process=true)
: Base(ar,ver,process)
{}
template<class T, size_t N> Save& operator,(const T (&t)[N])
{
if (_process)
_ar<<t;
return *this;
}
template<class T> Save& operator,(const T& t)
{
if (_process)
_ar<<t;
return *this;
}
};
}
//-----------------------------------------------------------------------------
//redirect to member by default
template <class T, class Serializer> inline void serializer(const T& t, Serializer& s)
{ t.serializer(s); }
#define SERIALIZER_EXTERNAL(Type,ver) \
inline void serialization<Type>::save(boost::basic_oarchive &ar, const Type &t) \
{ return ::serializer(t,lim_serialization::Save(ar,ver)); } \
inline void serialization<Type>::load(boost::basic_iarchive &ar, Type &t, boost::version_type saved_version) \
{ return ::serializer(t,lim_serialization::Load(ar,saved_version)); } \
inline boost::version_type serialization<Type>::version(const Type &t) \
{ return ver; }
#define SERIALIZER SERIALIZER_EXTERNAL
#define SERIALIZER_MEMBER(ver) \
inline void save(boost::basic_oarchive &ar) const \
{ return ::serializer(*this,lim_serialization::Save(ar,ver)); } \
inline void load(boost::basic_iarchive &ar, boost::version_type saved_version) \
{ return ::serializer(*this,lim_serialization::Load(ar,saved_version)); } \
inline boost::version_type version() const \
{ return ver; }
// test_serializer.cpp : Example of serialization
#include "stdafx.h" //<iostram>, <fstream>, <vector>, "<serializer_simple.h"
using namespace std;
struct struct_t
{
char _arr[10];
struct_t()
{ _arr[0]=0; }
struct_t(char* str)
{ strncpy(_arr,str,10); }
//internal serialization
template<class Serializer> void serializer(Serializer& s) const
{ s,_arr; }
SERIALIZER_MEMBER(0);
};
//-----------------------------------------------------------------------------
// Output to cout
inline ostream& operator<<(ostream& os, const struct_t& st)
{ return os<<st._arr; }
template<class T> inline ostream& operator<<(ostream& os, const vector<T*>& t)
{
for(vector<T*>::const_iterator i=t.begin(); i!=t.end(); ++i)
os<<**i<<endl;
return os;
}
template<class T> void load(T& t, const char* path)
{
cout<<"loading "<<path<<endl;
std::ifstream ifs(path, std::ios::binary);
boost::biarchive ia(ifs);
ia>>t;
ifs.close();
}
template<class T> void save(const T& t, const char* path)
{
cout<<"saving "<<path<<endl;
std::ofstream ofs(path, std::ios::binary);
boost::boarchive oa(ofs);
oa<<t;
ofs.close();
}
int main( )
{
vector<struct_t*> vec;
vec.push_back(new struct_t("struct1"));
vec.push_back(new struct_t(" struct2"));
vec.push_back(new struct_t(" struct3"));
cout<<vec<<endl;
save(vec,"map_test1.bin");
while(!vec.empty())
{
delete vec.back();
vec.pop_back();
}
cout<<vec<<endl;
load(vec,"map_test1.bin");
cout<<vec<<endl;
return 0;
}