better serialization, but test does not work actually
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user