From 933208f849d9144060e5c91b6d755b18c833667e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Tue, 28 Apr 2009 07:36:07 +0000 Subject: [PATCH] boost::any instead of macros - first pieces of meta template programming --- src/xml-cxx/xml.hxx | 20 ++-- src/xml.cxx | 220 +++++++++++++++++++++++++----------- test/serialization_test.cxx | 10 +- 3 files changed, 167 insertions(+), 83 deletions(-) diff --git a/src/xml-cxx/xml.hxx b/src/xml-cxx/xml.hxx index 859d0f9..104e436 100644 --- a/src/xml-cxx/xml.hxx +++ b/src/xml-cxx/xml.hxx @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -819,6 +820,8 @@ namespace xml { class Serialize { public: + typedef bool(*FromNodeFunc)(boost::any, const xml::Node&); + typedef bool(*ToNodeFunc)(const boost::any, xml::Node&); //! You must call Serialize::className() if you use this constructor! Serialize() throw(); Serialize(const std::string& className) throw(); @@ -872,10 +875,13 @@ namespace xml { Serialize& persist(std::string& member, const std::string& name) throw(); std::ostream& saveXml(std::ostream& os, - const std::string& name = std::string()) const throw(); + const std::string& name = std::string()) + const throw(); std::istream& loadXml(std::istream& is, const std::string& name = std::string()); std::string schema() const throw(); + static void registerFromNode(FromNodeFunc fromNodeFunc); + static void registerToNode(ToNodeFunc toNodeFunc); protected: virtual void initXmlMembers(); private: @@ -890,9 +896,8 @@ namespace xml { _xmlFactory = schema; return *this; } - template void fromNode(TYPE* member, xml::Node& node) { - *member = (TYPE)dynamic_cast(node); - } + void fromNode(boost::any member, const xml::Node& node); + void toNode(const boost::any member, xml::Node& node) const; /* template void fromNode(std::list* member, xml::Node& node) { @@ -900,13 +905,10 @@ namespace xml { for (xml::Node::size_type i(0); i void toNode(TYPE* member, xml::Node& node) const { - std::stringstream ss; - ss<<*member; - node.text(ss.str()); - } std::map _xmlNames; xml::Factory _xmlFactory; + static std::set _fromNode; + static std::set _toNode; }; //@} diff --git a/src/xml.cxx b/src/xml.cxx index ef113de..fb1d691 100644 --- a/src/xml.cxx +++ b/src/xml.cxx @@ -13,7 +13,7 @@ unsigned int MethodTrace::_level(0); namespace xml { - + //================================================================= EXCEPTIONS //---------------------------------------------------------------------------- @@ -1016,21 +1016,7 @@ namespace xml { //============================================================== Serialization - //---------------------------------------------------------------------------- - template<> void Serialize::fromNode(Serialize* member, - xml::Node& node) { - //! @todo improve this (inefficient) - std::stringstream ss; // simple but inefficient: rewrite and reread - ss<loadXml(ss, node.name()); - } - template<> void Serialize::toNode(Serialize* member, - xml::Node& node) const { - std::stringstream ss; - member->saveXml(ss, node.name()); - xml::Factory factory(node); - node = *factory.read(ss); - } + //---------------------------------------------------------------------------- Serialize::Serialize() throw() {} Serialize::Serialize(const std::string& className) throw(): @@ -1125,32 +1111,8 @@ namespace xml { if (name.size()) node.name(name); for (std::map::const_iterator it(_xmlNames.begin()); - it!=_xmlNames.end(); ++it) { -#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \ - if (it->second.type()==typeid(TYPE*)) \ - toNode(boost::any_cast(it->second), \ - node[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) - throw std::runtime_error(it->first); -#undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX - } + it!=_xmlNames.end(); ++it) + toNode(it->second, node[it->first]); os< node(factory.read(is)); for (std::map::const_iterator it(_xmlNames.begin()); - it!=_xmlNames.end(); ++it) { -#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \ - if (it->second.type()==typeid(TYPE*)) \ - fromNode(boost::any_cast(it->second), \ - (*node)[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) - throw std::runtime_error(it->first); -#undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX - } + it!=_xmlNames.end(); ++it) + fromNode(it->second, (*node)[it->first]); return is; } std::string Serialize::schema() const throw() { @@ -1195,14 +1133,158 @@ namespace xml { ss<<*_xmlFactory; return ss.str(); } + template bool assignFromNode(boost::any member, + const xml::Node& node) { + if (member.type()==typeid(TYPE*)) { + *boost::any_cast(member) = + (TYPE)dynamic_cast(node); + return true; + } + return false; + } + template bool assignToNode(const boost::any member, + xml::Node& node) { + if (member.type()==typeid(TYPE*)) { + std::stringstream ss; + ss<<*boost::any_cast(member); + node.text(ss.str()); + return true; + } + return false; + } + template<> bool assignFromNode(boost::any member, + const xml::Node& node) { + if (member.type()==typeid(bool*)) { + std::string s(*dynamic_cast(node)); + std::string::size_type + start(s.find_first_not_of(" \t\n\r")), + end(s.find_last_not_of(" \t\n\r")); + if (start==std::string::npos) { + *boost::any_cast(member) = false; + } else { + s = s.substr(start, end-start+1); + *boost::any_cast(member) = + s!="0" && s!="false" && s!="no" && s!="off"; + } + return true; + } + return false; + } + template<> bool assignToNode(const boost::any member, + xml::Node& node) { + if (member.type()==typeid(bool*)) { + node.text(*boost::any_cast(member)?"true":"false"); + return true; + } + return false; + } + template<> bool assignFromNode(boost::any member, + const xml::Node& node) { + if (member.type()==typeid(Serialize*)) { + //! @todo improve this (inefficient) + std::stringstream ss; // simple but inefficient: rewrite and reread + ss<(member)->loadXml(ss, node.name()); + return true; + } + return false; + } + template<> bool assignToNode(const boost::any member, + xml::Node& node) { + if (member.type()==typeid(Serialize*)) { + std::stringstream ss; + boost::any_cast(member)->saveXml(ss, node.name()); + xml::Factory factory(node); + node = *factory.read(ss); + return true; + } + return false; + } + template + bool containerFromNode(boost::any member, + const xml::Node& node) { + LOG("ASSIGN List"); + } +// template +// bool assignToNode(const boost::any member, xml::Node& node) { +// } + void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) { + if (!_fromNode.size()) { // initial initialization + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + _fromNode.insert(&assignFromNode); + } + _fromNode.insert(fromNodeFunc); + } + //---------------------------------------------------------------------------- + //typedef boost::mpl::vector BasicTypes; + //---------------------------------------------------------------------------- + //typedef boost::mpl::vector BasicTypes; + template class RegisterAssignToNode { + RegisterAssignToNode() { + registerToNode(&assignToNode); + } + }; + void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) { + if (!_toNode.size()) { // initial initialization + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + _toNode.insert(&assignToNode); + } + _toNode.insert(toNodeFunc); + } void Serialize::initXmlMembers() {} void Serialize::clear() throw() { - _xmlNames.clear(); _xmlFactory.reset(); + _xmlNames.clear(); } void Serialize::copy(const Serialize& o) throw() { clear(); initXmlMembers(); } + void Serialize::fromNode(boost::any member, const xml::Node& node) { + if (!_fromNode.size()) registerFromNode(&assignFromNode); + for (std::set::const_iterator it(_fromNode.begin()); + it!=_fromNode.end(); ++it) + if ((**it)(member, node)) return; // found match + throw std::runtime_error(node.name()); + } + void Serialize::toNode(const boost::any member, xml::Node& node) const { + if (!_toNode.size()) registerToNode(&assignToNode); + for (std::set::const_iterator it(_toNode.begin()); + it!=_toNode.end(); ++it) + if ((**it)(member, node)) return; // found match + throw std::runtime_error(node.name()); + } + std::set Serialize::_fromNode; + std::set Serialize::_toNode; } diff --git a/test/serialization_test.cxx b/test/serialization_test.cxx index 3d92e85..52b2306 100644 --- a/test/serialization_test.cxx +++ b/test/serialization_test.cxx @@ -115,7 +115,7 @@ class SerializationTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss)); CPPUNIT_ASSERT_EQUAL(std::string("\n" "\t15\n" - "\t1\n" + "\ttrue\n" "\t123.456\n" "\tHello World\n" "\tThis is" @@ -146,7 +146,7 @@ class SerializationTest: public CppUnit::TestFixture { void complexLoad() { std::stringstream ss("\n" " -1234\n" - " 1\n" + " true\n" " 3.141\n" " This is A inside of A2\n" " Another A-String\n" @@ -206,7 +206,7 @@ class SerializationTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL (std::string("\n" "\t-1234\n" - "\t1\n" + "\ttrue\n" "\t3.141\n" "\tThis is A inside of A2\n" "\tAnother A-String\n" @@ -225,7 +225,7 @@ class SerializationTest: public CppUnit::TestFixture { ("\n" " \n" " -1234\n" - " 1\n" + " true\n" " 3.141\n" " This is A inside of A2\n" " Another A-String\n" @@ -311,7 +311,7 @@ class SerializationTest: public CppUnit::TestFixture { (std::string("\n" "\t\n" "\t\t-1234\n" - "\t\t1\n" + "\t\ttrue\n" "\t\t3.141\n" "\t\tThis is A inside of A2\n" "\t\tAnother A-String\n"