boost::any instead of macros - first pieces of meta template programming
This commit is contained in:
		| @@ -13,6 +13,7 @@ | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| #include <set> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <typeinfo> | ||||
| @@ -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<typename TYPE> void fromNode(TYPE* member, xml::Node& node) { | ||||
|         *member = (TYPE)dynamic_cast<xml::String&>(node); | ||||
|       } | ||||
|       void fromNode(boost::any member, const xml::Node& node); | ||||
|       void toNode(const boost::any member, xml::Node& node) const; | ||||
|       /* | ||||
|       template<typename TYPE, class ALLOC> | ||||
|           void fromNode(std::list<TYPE, ALLOC>* member, xml::Node& node) { | ||||
| @@ -900,13 +905,10 @@ namespace xml { | ||||
|         for (xml::Node::size_type i(0); i<node.children(); ++i) | ||||
|           ... | ||||
|           }*/ | ||||
|       template<typename TYPE> void toNode(TYPE* member, xml::Node& node) const { | ||||
|         std::stringstream ss; | ||||
|         ss<<*member; | ||||
|         node.text(ss.str()); | ||||
|       } | ||||
|       std::map<std::string, boost::any> _xmlNames; | ||||
|       xml::Factory _xmlFactory; | ||||
|       static std::set<FromNodeFunc> _fromNode; | ||||
|       static std::set<ToNodeFunc> _toNode; | ||||
|   }; | ||||
|  | ||||
|   //@} | ||||
|   | ||||
							
								
								
									
										218
									
								
								src/xml.cxx
									
									
									
									
									
								
							
							
						
						
									
										218
									
								
								src/xml.cxx
									
									
									
									
									
								
							| @@ -1016,21 +1016,7 @@ namespace xml { | ||||
|  | ||||
|   //============================================================== Serialization | ||||
|  | ||||
|   //---------------------------------------------------------------------------- | ||||
|   template<> void Serialize::fromNode<Serialize>(Serialize* member, | ||||
|                                                  xml::Node& node) { | ||||
|     //! @todo improve this (inefficient) | ||||
|     std::stringstream ss; // simple but inefficient: rewrite and reread | ||||
|     ss<<node; | ||||
|     member->loadXml(ss, node.name()); | ||||
|   } | ||||
|   template<> void Serialize::toNode<Serialize>(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<std::string, boost::any>::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<TYPE*>(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; | ||||
|     return os; | ||||
|   } | ||||
| @@ -1161,32 +1123,8 @@ namespace xml { | ||||
|     std::auto_ptr<xml::Node> node(factory.read(is)); | ||||
|     for (std::map<std::string, boost::any>::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<TYPE*>(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<typename TYPE> bool assignFromNode(boost::any member, | ||||
|                                               const xml::Node& node) { | ||||
|     if (member.type()==typeid(TYPE*)) { | ||||
|       *boost::any_cast<TYPE*>(member) = | ||||
|         (TYPE)dynamic_cast<const xml::String&>(node); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<typename TYPE> bool assignToNode(const boost::any member, | ||||
|                                             xml::Node& node) { | ||||
|     if (member.type()==typeid(TYPE*)) { | ||||
|       std::stringstream ss; | ||||
|       ss<<*boost::any_cast<TYPE*>(member); | ||||
|       node.text(ss.str()); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<> bool assignFromNode<bool>(boost::any member, | ||||
|                                        const xml::Node& node) { | ||||
|     if (member.type()==typeid(bool*)) { | ||||
|       std::string s(*dynamic_cast<const xml::String&>(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<bool*>(member) = false; | ||||
|       } else { | ||||
|         s = s.substr(start, end-start+1); | ||||
|         *boost::any_cast<bool*>(member) =  | ||||
|           s!="0" && s!="false" && s!="no" && s!="off"; | ||||
|       } | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<> bool assignToNode<bool>(const boost::any member, | ||||
|                                      xml::Node& node) { | ||||
|     if (member.type()==typeid(bool*)) { | ||||
|       node.text(*boost::any_cast<bool*>(member)?"true":"false"); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<> bool assignFromNode<Serialize>(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<<node; | ||||
|       boost::any_cast<Serialize*>(member)->loadXml(ss, node.name()); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<> bool assignToNode<Serialize>(const boost::any member, | ||||
|                                           xml::Node& node) { | ||||
|     if (member.type()==typeid(Serialize*)) { | ||||
|       std::stringstream ss; | ||||
|       boost::any_cast<Serialize*>(member)->saveXml(ss, node.name()); | ||||
|       xml::Factory factory(node); | ||||
|       node = *factory.read(ss); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   template<typename TYPE, class ALLOC> | ||||
|       bool containerFromNode(boost::any member, | ||||
|                              const xml::Node& node) { | ||||
|     LOG("ASSIGN List"); | ||||
|   } | ||||
| //   template<typename TYPE, class ALLOC> | ||||
| //       bool assignToNode(const boost::any member, xml::Node& node) { | ||||
| //   } | ||||
|   void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) { | ||||
|     if (!_fromNode.size()) { // initial initialization | ||||
|       _fromNode.insert(&assignFromNode<Serialize>); | ||||
|       _fromNode.insert(&assignFromNode<std::string>); | ||||
|       _fromNode.insert(&assignFromNode<float>); | ||||
|       _fromNode.insert(&assignFromNode<double>); | ||||
|       _fromNode.insert(&assignFromNode<bool>); | ||||
|       _fromNode.insert(&assignFromNode<char>); | ||||
|       _fromNode.insert(&assignFromNode<signed char>); | ||||
|       _fromNode.insert(&assignFromNode<unsigned char>); | ||||
|       _fromNode.insert(&assignFromNode<short>); | ||||
|       _fromNode.insert(&assignFromNode<signed short>); | ||||
|       _fromNode.insert(&assignFromNode<unsigned short>); | ||||
|       _fromNode.insert(&assignFromNode<int>); | ||||
|       _fromNode.insert(&assignFromNode<signed int>); | ||||
|       _fromNode.insert(&assignFromNode<unsigned int>); | ||||
|       _fromNode.insert(&assignFromNode<long>); | ||||
|       _fromNode.insert(&assignFromNode<signed long>); | ||||
|       _fromNode.insert(&assignFromNode<unsigned long>); | ||||
|     } | ||||
|     _fromNode.insert(fromNodeFunc); | ||||
|   } | ||||
|   //---------------------------------------------------------------------------- | ||||
|   //typedef boost::mpl::vector<Serialize, std::string, float, double, bool, char, signed char, unsigned char, short, signed short, unsigned short, int, signed int, unsigned int, long, signed long, unsigned long> BasicTypes; | ||||
|   //---------------------------------------------------------------------------- | ||||
|   //typedef boost::mpl::vector<Serialize, std::string, float, double, bool, char, signed char, unsigned char, short, signed short, unsigned short, int, signed int, unsigned int, long, signed long, unsigned long> BasicTypes; | ||||
|   template<typename TYPE> class RegisterAssignToNode { | ||||
|       RegisterAssignToNode() { | ||||
|         registerToNode(&assignToNode<TYPE>); | ||||
|       } | ||||
|   }; | ||||
|   void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) { | ||||
|     if (!_toNode.size()) { // initial initialization | ||||
|       _toNode.insert(&assignToNode<Serialize>); | ||||
|       _toNode.insert(&assignToNode<std::string>); | ||||
|       _toNode.insert(&assignToNode<float>); | ||||
|       _toNode.insert(&assignToNode<double>); | ||||
|       _toNode.insert(&assignToNode<bool>); | ||||
|       _toNode.insert(&assignToNode<char>); | ||||
|       _toNode.insert(&assignToNode<signed char>); | ||||
|       _toNode.insert(&assignToNode<unsigned char>); | ||||
|       _toNode.insert(&assignToNode<short>); | ||||
|       _toNode.insert(&assignToNode<signed short>); | ||||
|       _toNode.insert(&assignToNode<unsigned short>); | ||||
|       _toNode.insert(&assignToNode<int>); | ||||
|       _toNode.insert(&assignToNode<signed int>); | ||||
|       _toNode.insert(&assignToNode<unsigned int>); | ||||
|       _toNode.insert(&assignToNode<long>); | ||||
|       _toNode.insert(&assignToNode<signed long>); | ||||
|       _toNode.insert(&assignToNode<unsigned long>); | ||||
|     } | ||||
|     _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<std::string>); | ||||
|     for (std::set<FromNodeFunc>::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<std::string>); | ||||
|     for (std::set<ToNodeFunc>::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::FromNodeFunc> Serialize::_fromNode; | ||||
|   std::set<Serialize::ToNodeFunc> Serialize::_toNode; | ||||
|    | ||||
| } | ||||
|   | ||||
| @@ -115,7 +115,7 @@ class SerializationTest: public CppUnit::TestFixture { | ||||
|         CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss)); | ||||
|         CPPUNIT_ASSERT_EQUAL(std::string("<A>\n" | ||||
|                                          "\t<anInteger>15</anInteger>\n" | ||||
|                                          "\t<aBool>1</aBool>\n" | ||||
|                                          "\t<aBool>true</aBool>\n" | ||||
|                                          "\t<aDouble>123.456</aDouble>\n" | ||||
|                                          "\t<aString>Hello World</aString>\n" | ||||
|                                          "\t<anotherString>This is" | ||||
| @@ -146,7 +146,7 @@ class SerializationTest: public CppUnit::TestFixture { | ||||
|     void complexLoad() { | ||||
|       std::stringstream ss("<A2>\n" | ||||
|                            "  <anInteger>-1234</anInteger>\n" | ||||
|                            "  <aBool>1</aBool>\n" | ||||
|                            "  <aBool>true</aBool>\n" | ||||
|                            "  <aDouble>3.141</aDouble>\n" | ||||
|                            "  <aString>This is A inside of A2</aString>\n" | ||||
|                            "  <anotherString>Another A-String</anotherString>\n" | ||||
| @@ -206,7 +206,7 @@ class SerializationTest: public CppUnit::TestFixture { | ||||
|       CPPUNIT_ASSERT_EQUAL | ||||
|         (std::string("<A2>\n" | ||||
|                      "\t<anInteger>-1234</anInteger>\n" | ||||
|                      "\t<aBool>1</aBool>\n" | ||||
|                      "\t<aBool>true</aBool>\n" | ||||
|                      "\t<aDouble>3.141</aDouble>\n" | ||||
|                      "\t<aString>This is A inside of A2</aString>\n" | ||||
|                      "\t<anotherString>Another A-String</anotherString>\n" | ||||
| @@ -225,7 +225,7 @@ class SerializationTest: public CppUnit::TestFixture { | ||||
|         ("<C>\n" | ||||
|          "  <a2>\n" | ||||
|          "    <anInteger>-1234</anInteger>\n" | ||||
|          "    <aBool>1</aBool>\n" | ||||
|          "    <aBool>true</aBool>\n" | ||||
|          "    <aDouble>3.141</aDouble>\n" | ||||
|          "    <aString>This is A inside of A2</aString>\n" | ||||
|          "    <anotherString>Another A-String</anotherString>\n" | ||||
| @@ -311,7 +311,7 @@ class SerializationTest: public CppUnit::TestFixture { | ||||
|         (std::string("<C>\n" | ||||
|                      "\t<a2>\n" | ||||
|                      "\t\t<anInteger>-1234</anInteger>\n" | ||||
|                      "\t\t<aBool>1</aBool>\n" | ||||
|                      "\t\t<aBool>true</aBool>\n" | ||||
|                      "\t\t<aDouble>3.141</aDouble>\n" | ||||
|                      "\t\t<aString>This is A inside of A2</aString>\n" | ||||
|                      "\t\t<anotherString>Another A-String</anotherString>\n" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user