better serialization, but test does not work actually

This commit is contained in:
Marc Wäckerlin
2009-04-23 15:10:21 +00:00
parent a9ad45ad4d
commit 37fd5e8695
5 changed files with 473 additions and 149 deletions

View File

@@ -14,6 +14,8 @@
#include <vector>
#include <map>
#include <memory>
#include <typeinfo>
#include <stdexcept>
/*! @mainpage
@@ -82,125 +84,6 @@
@example address.cxx */
/*! @defgroup serialization Class Serialization
@section serIntro Introduction
Boost library (http://boost.org) offers a serialization framework,
which is able to serialize even complex class structures, you only
need to overwrite one or two serialization macros. The
disadvantages are that a lot of macros are needed and it becomes
quite complex as soon as you need inheritance. Also the generated
XML is not very enhanced, especially for Lists and
optional. Editing the boost serialization code by hand is a pain.
Classes could also be serialized using gSOAP (http://gsoap.sf.net)
which is designed for the SOA-Protocol. This serialization is much
more flexible, but it requires a pseudo C++ declaration and a C++
parser/generator. Also it has very bad memory management, since it
is plain C internally.
Our requirements are:
- No precompiler, plain C++.
- Automatic memory management.
- Nice looking XML code that is easy to edit manually.
- Good error messages (exception) in case of bad XML files.
- As few ugly overflow as possible.
@section serActual Actual Status
Instead of:
@code
class A {
protected:
int _anInteger;
bool _aBool;
double _aDouble;
std::string _aString;
std::string _anotherString;
unsigned long _aLong;
};
@endcode
You have to write:
@code
class A {
protected:
XML_DECLARE_MEMBER(int, anInteger);
XML_DECLARE_MEMBER(bool, aBool);
XML_DECLARE_MEMBER(double, aDouble);
XML_DECLARE_MEMBER(std::string, aString);
XML_DECLARE_MEMBER(std::string, anotherString);
XML_DECLARE_MEMBER(unsigned long, aLong);
private:
XML_INIT_BEGIN(A);
XML_INIT_MEMBER(A, anInteger);
XML_INIT_MEMBER(A, aBool);
XML_INIT_MEMBER(A, aDouble);
XML_INIT_MEMBER(A, aString);
XML_INIT_MEMBER(A, anotherString);
XML_INIT_MEMBER(A, aLong);
XML_INIT_END;
};
@endcode
You get:
- All the members (with @c _ as member prefix)
- method <code>void saveXml(std::ostream&) const</code>
- method <code>void loadXml(std::istream&)</code>
@todo Up to now: Only base types plus std::string are supported,
no list, no inheritance is possible and no optional members. */
//@{
#define XML_DECLARE_MEMBER(TYPE, MEMBER) \
void MEMBER##FromNode(xml::Node& node) { \
_##MEMBER = (TYPE)dynamic_cast<xml::String&>(node[#MEMBER]); \
} \
void MEMBER##ToNode(xml::Node& node) const { \
std::stringstream ss; \
ss<<_##MEMBER; \
node[#MEMBER].text(ss.str()); \
} \
TYPE _##MEMBER
#define XML_INIT_BEGIN(CLASS_NAME) \
const CLASS_NAME& saveXml(std::ostream& os) const { \
const_cast<CLASS_NAME*>(this)->initXmlMembers(); \
xml::Node node(*_xmlFactory); \
for (std::vector<XmlSaveMethod>::const_iterator \
it(_saveXmlMemberList.begin()); \
it!=_saveXmlMemberList.end(); ++it) \
(this->*(*it))(node); \
os<<node; \
} \
CLASS_NAME& loadXml(std::istream& is) { \
initXmlMembers(); \
std::auto_ptr<xml::Node> node(_xmlFactory.read(is)); \
for (std::vector<XmlLoadMethod>::const_iterator \
it(_loadXmlMemberList.begin()); \
it!=_loadXmlMemberList.end(); ++it) \
(this->*(*it))(*node); \
} \
private: \
typedef void(CLASS_NAME::*XmlSaveMethod)(xml::Node&) const; \
typedef void(CLASS_NAME::*XmlLoadMethod)(xml::Node&); \
std::vector<XmlSaveMethod> _saveXmlMemberList; \
std::vector<XmlLoadMethod> _loadXmlMemberList; \
void initXmlMembers() { \
if (_xmlFactory) return; \
xml::Node schema(#CLASS_NAME)
#define XML_INIT_MEMBER(CLASS_NAME, MEMBER) \
schema<<xml::String(#MEMBER).limits(1,1); \
_saveXmlMemberList.push_back(&CLASS_NAME::MEMBER##ToNode); \
_loadXmlMemberList.push_back(&CLASS_NAME::MEMBER##FromNode)
#define XML_INIT_END \
_xmlFactory = schema;\
} \
xml::Factory _xmlFactory
//@}
/*! @defgroup xmlConst XML Constant Declarations
There are macros to help you with declaring constants. Chose a C++
@@ -777,7 +660,6 @@ namespace xml {
wrong_node_number);
private:
friend class stream_error;
Factory(const Factory&); // not implemented
bool ws(char c) throw();
std::auto_ptr<Node> read(std::istream& is, const Node& position)
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
@@ -801,5 +683,126 @@ namespace xml {
long _open;
};
/*! @defgroup serialization Class Serialization
@section serIntro Introduction
Boost library (http://boost.org) offers a serialization framework,
which is able to serialize even complex class structures, you only
need to overwrite one or two serialization macros. The
disadvantages are that a lot of macros are needed and it becomes
quite complex as soon as you need inheritance. Also the generated
XML is not very enhanced, especially for Lists and
optional. Editing the boost serialization code by hand is a pain.
Classes could also be serialized using gSOAP (http://gsoap.sf.net)
which is designed for the SOA-Protocol. This serialization is much
more flexible, but it requires a pseudo C++ declaration and a C++
parser/generator. Also it has very bad memory management, since it
is plain C internally.
Our requirements are:
- No precompiler, plain C++.
- Automatic memory management.
- Nice looking XML code that is easy to edit manually.
- Good error messages (exception) in case of bad XML files.
- As few ugly overflow as possible.
@section serActual Actual Status
Instead of:
@code
class A {
protected:
int _anInteger;
bool _aBool;
double _aDouble;
std::string _aString;
std::string _anotherString;
unsigned long _aLong;
};
@endcode
You have to write:
@code
class A {
protected:
XML_DECLARE_MEMBER(int, anInteger);
XML_DECLARE_MEMBER(bool, aBool);
XML_DECLARE_MEMBER(double, aDouble);
XML_DECLARE_MEMBER(std::string, aString);
XML_DECLARE_MEMBER(std::string, anotherString);
XML_DECLARE_MEMBER(unsigned long, aLong);
private:
XML_INIT_BEGIN(A);
XML_INIT_MEMBER(A, anInteger);
XML_INIT_MEMBER(A, aBool);
XML_INIT_MEMBER(A, aDouble);
XML_INIT_MEMBER(A, aString);
XML_INIT_MEMBER(A, anotherString);
XML_INIT_MEMBER(A, aLong);
XML_INIT_END;
};
@endcode
You get:
- All the members (with @c _ as member prefix)
- method <code>void saveXml(std::ostream&) const</code>
- method <code>void loadXml(std::istream&)</code>
@todo Up to now: Only base types plus std::string are supported,
no list, no inheritance is possible and no optional members.
@example serialization.cxx */
//@{
class Serialize {
public:
//! You must call Serialize::className() if you use this constructor!
Serialize() throw();
Serialize(const std::string& className) throw();
virtual ~Serialize();
void className(const std::string& name) throw();
template<typename TYPE>
Serialize& persist(TYPE& member, const std::string& name) {
mapName<TYPE>()[name] = &member;
mapMember<TYPE>()[&member] = name;
_xmlNames[name] = &typeid(TYPE);
xml::Node schema(*_xmlFactory);
schema<<xml::String(name).limits(1,1);
_xmlFactory = schema;
return *this;
}
std::ostream& saveXml(std::ostream& os) const throw();
std::istream& loadXml(std::istream& is);
protected:
virtual void initXmlMembers();
private:
template<typename TYPE> std::map<std::string, TYPE*>& mapName() const {
static std::map<std::string, TYPE*> MAP;
return MAP;
}
template<typename TYPE> std::map<TYPE*, std::string>& mapMember() const {
static std::map<TYPE*, std::string> MAP;
return MAP;
}
template<typename TYPE> void fromNode(TYPE* member, xml::Node& node) {
*member =
(TYPE)dynamic_cast<xml::String&>(node[mapMember<TYPE>()[member]]);
}
template<typename TYPE> void toNode(TYPE* member, xml::Node& node) const {
std::stringstream ss;
ss<<*member;
node[mapMember<TYPE>()[member]].text(ss.str());
}
std::map<std::string, const std::type_info*> _xmlNames;
xml::Factory _xmlFactory;
};
//@}
}
#endif