containment can be serialized

master
Marc Wäckerlin 16 years ago
parent 17dc91d35e
commit dd834119f3
  1. 5
      doc/examples/contain_serialization.cxx
  2. 103
      src/xml-cxx/xml.hxx
  3. 57
      src/xml.cxx

@ -37,6 +37,10 @@ class B: public xml::Serialize {
} }
}; };
std::ostream& fn(std::ostream& os) {
os<<std::endl<<"HALLO"<<std::endl;
}
int main(int, char**) { int main(int, char**) {
{ // Serialization as a member { // Serialization as a member
std::stringstream ss("<b>\n" std::stringstream ss("<b>\n"
@ -54,6 +58,7 @@ int main(int, char**) {
std::cout<<"Text B: "<<b.txt<<std::endl; std::cout<<"Text B: "<<b.txt<<std::endl;
std::cout<<"Text A: "<<b.a.txt<<std::endl; std::cout<<"Text A: "<<b.a.txt<<std::endl;
b.saveXml(std::cout)<<std::endl; b.saveXml(std::cout)<<std::endl;
std::cout<<fn;
} }
return 0; return 0;
} }

@ -739,52 +739,69 @@ namespace xml {
@section serActual Actual Status @section serActual Actual Status
Instead of: The following member types are supported
- All built-in C++ types are supported
- std::string is supported
- Contained classes are supported
@code The following will be supported soon (ideas):
class A { - lists, maps
protected: - inheritance
int _anInteger; - choices (one of)
bool _aBool; - optional members (pointer)
double _aDouble;
std::string _aString;
std::string _anotherString;
unsigned long _aLong;
};
@endcode
You have to write: Pointers cannot be stored.
There are many ways of implemenation. best practice is to
inherit xml::Serialize and to overwrite
xml::Serialize::initXmlMembers:
@code @code
class A { class A: public xml::Serialize {
protected: protected:
XML_DECLARE_MEMBER(int, anInteger); // all persitent members must be registered
XML_DECLARE_MEMBER(bool, aBool); virtual void initXmlMembers() {
XML_DECLARE_MEMBER(double, aDouble); className("A"); // giving a class name is very important
XML_DECLARE_MEMBER(std::string, aString); persist(_anInteger, "anInteger");
XML_DECLARE_MEMBER(std::string, anotherString); persist(_aBool, "aBool");
XML_DECLARE_MEMBER(unsigned long, aLong); persist(_aDouble, "aDouble");
private: persist(_aString, "aString");
XML_INIT_BEGIN(A); persist(_anotherString, "anotherString");
XML_INIT_MEMBER(A, anInteger); persist(_aLong, "aLong");
XML_INIT_MEMBER(A, aBool); }
XML_INIT_MEMBER(A, aDouble); private:
XML_INIT_MEMBER(A, aString); int _anInteger;
XML_INIT_MEMBER(A, anotherString); bool _aBool;
XML_INIT_MEMBER(A, aLong); double _aDouble;
XML_INIT_END; std::string _aString;
std::string _anotherString;
unsigned long _aLong;
}; };
@endcode
You get: class B: public xml::Serialize {
- All the members (with @c _ as member prefix) protected:
- method <code>void saveXml(std::ostream&) const</code> virtual void initXmlMembers() {
- method <code>void loadXml(std::istream&)</code> className("B");
persist(_a); // name must not be given, it's already known
persist(_anInteger, "anInteger");
}
private:
A _a; // contains an A
int _anInteger;
};
@todo Up to now: Only base types plus std::string are supported, int main(int, char**) {
no list, no inheritance is possible and no optional members. A a;
B b;
// ... do something with a and b, then write it to stdout:
a.saveXml(std::out)<<std::endl;
b.saveXml(std::out)<<std::endl;
return 0;
}
@endcode
@example serialization.cxx */ @example serialization.cxx
@example contain_serialization.cxx */
//@{ //@{
class Serialize { class Serialize {
@ -797,10 +814,10 @@ namespace xml {
Serialize& persist(Serialize& ser) throw(); Serialize& persist(Serialize& ser) throw();
template<typename TYPE> template<typename TYPE>
Serialize& persist(TYPE& member, const std::string& name) throw() { Serialize& persist(TYPE& member, const std::string& name) throw() {
assert(mapName<TYPE>().find(name)==mapName<TYPE>().end()); assert(mapName<TYPE>().find(std::make_pair(this, name))==mapName<TYPE>().end());
assert(mapMember<TYPE>().find(&member)==mapMember<TYPE>().end()); assert(mapMember<TYPE>().find(&member)==mapMember<TYPE>().end());
assert(_xmlNames.find(name)==_xmlNames.end()); assert(_xmlNames.find(name)==_xmlNames.end());
mapName<TYPE>()[name] = &member; mapName<TYPE>()[std::make_pair(this, name)] = &member;
mapMember<TYPE>()[&member] = name; mapMember<TYPE>()[&member] = name;
_xmlNames[name] = &typeid(TYPE); _xmlNames[name] = &typeid(TYPE);
xml::Node schema(*_xmlFactory); xml::Node schema(*_xmlFactory);
@ -813,8 +830,10 @@ namespace xml {
protected: protected:
virtual void initXmlMembers(); virtual void initXmlMembers();
private: private:
template<typename TYPE> std::map<std::string, TYPE*>& mapName() const { template<typename TYPE>
static std::map<std::string, TYPE*> MAP; std::map<std::pair<const Serialize*, std::string>, TYPE*>&
mapName() const {
static std::map<std::pair<const Serialize*, std::string>, TYPE*> MAP;
return MAP; return MAP;
} }
template<typename TYPE> std::map<TYPE*, std::string>& mapMember() const { template<typename TYPE> std::map<TYPE*, std::string>& mapMember() const {

@ -993,18 +993,55 @@ namespace xml {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<> void Serialize::fromNode<Serialize>(Serialize* member, template<> void Serialize::fromNode<Serialize>(Serialize* member,
xml::Node& node) { xml::Node& node) {
member->_xmlFactory = node[member->_xmlFactory->name()]; //! @todo improve this (inefficient)
std::stringstream ss; // simple but inefficient: rewrite and reread
ss<<node[member->_xmlFactory->name()];
member->loadXml(ss);
} }
template<> void Serialize::toNode<Serialize>(Serialize* member, template<> void Serialize::toNode<Serialize>(Serialize* member,
xml::Node& node) const { xml::Node& node) const {
node[member->_xmlFactory->name()] = *member->_xmlFactory; //! @todo improve this (inefficient)
std::stringstream ss; // simple but inefficient: write and reread
member->saveXml(ss);
node[member->_xmlFactory->name()] = *member->_xmlFactory.read(ss);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Serialize::Serialize() throw() {} Serialize::Serialize() throw() {}
Serialize::Serialize(const std::string& className) throw(): Serialize::Serialize(const std::string& className) throw():
_xmlFactory(xml::Node(xml::String(className).limits(1,1))) { _xmlFactory(xml::Node(xml::String(className).limits(1,1))) {
} }
Serialize::~Serialize() {}; Serialize::~Serialize() {
// Remove my entries from the maps
for (std::map<std::string, const std::type_info*>::const_iterator
it(_xmlNames.begin());
it!=_xmlNames.end(); ++it) {
#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \
if (*it->second==typeid(TYPE)) { \
mapMember<TYPE>() \
.erase(mapName<TYPE>()[std::make_pair(this, it->first)]); \
mapName<TYPE>().erase(std::make_pair(this, it->first)); \
} else
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(Serialize)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(float)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(double)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(bool)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(char)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed char)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned char)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(short)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed short)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned short)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(int)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed int)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned int)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(long)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed long)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned long)
{} // ignore coding error here, but memory leaks - better abort?
#undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX
}
}
Serialize& Serialize::className(const std::string& name) throw() { Serialize& Serialize::className(const std::string& name) throw() {
_xmlFactory=xml::Node(xml::String(name).limits(1,1)); _xmlFactory=xml::Node(xml::String(name).limits(1,1));
return *this; return *this;
@ -1012,7 +1049,7 @@ namespace xml {
Serialize& Serialize::persist(Serialize& ser) throw() { Serialize& Serialize::persist(Serialize& ser) throw() {
ser.initXmlMembers(); ser.initXmlMembers();
std::string name(ser._xmlFactory->name()); std::string name(ser._xmlFactory->name());
mapName<Serialize>()[name] = &ser; mapName<Serialize>()[std::make_pair(this, name)] = &ser;
mapMember<Serialize>()[&ser] = name; mapMember<Serialize>()[&ser] = name;
_xmlNames[name] = &typeid(Serialize); _xmlNames[name] = &typeid(Serialize);
xml::Node schema(*_xmlFactory); xml::Node schema(*_xmlFactory);
@ -1026,9 +1063,9 @@ namespace xml {
for (std::map<std::string, const std::type_info*>::const_iterator for (std::map<std::string, const std::type_info*>::const_iterator
it(_xmlNames.begin()); it(_xmlNames.begin());
it!=_xmlNames.end(); ++it) { it!=_xmlNames.end(); ++it) {
#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \ #define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \
if (*it->second==typeid(TYPE)) \ if (*it->second==typeid(TYPE)) \
toNode(mapName<TYPE>()[it->first], node); \ toNode(mapName<TYPE>()[std::make_pair(this, it->first)], node); \
else else
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(Serialize) QWERTZ_CHECK_TYPE_ZTREWQ___XXX(Serialize)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string) QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string)
@ -1059,9 +1096,9 @@ namespace xml {
for (std::map<std::string, const std::type_info*>::const_iterator for (std::map<std::string, const std::type_info*>::const_iterator
it(_xmlNames.begin()); it(_xmlNames.begin());
it!=_xmlNames.end(); ++it) { it!=_xmlNames.end(); ++it) {
#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \ #define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \
if (*it->second==typeid(TYPE)) \ if (*it->second==typeid(TYPE)) \
fromNode(mapName<TYPE>()[it->first], *node); \ fromNode(mapName<TYPE>()[std::make_pair(this, it->first)], *node); \
else else
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(Serialize) QWERTZ_CHECK_TYPE_ZTREWQ___XXX(Serialize)
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string) QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string)

Loading…
Cancel
Save