1 /* 2 * actions.h 3 * 4 * 5 * Created by Andreas Vox on 02.06.06. 6 * Copyright 2006 under GPL2. All rights reserved. 7 * 8 */ 9 10 11 #ifndef ACTIONS_H 12 #define ACTIONS_H 13 14 #include <map> 15 #include <string> 16 #include "digester.h" 17 18 namespace desaxe { 19 20 /** 21 * Action / Action_body follow the handle/body pattern. This allows to omit the 22 * new operator when creating Action expressions and make dynamic memory handling 23 * more secure. 24 * Base class for the body of all actions. Usually Digester calls these methods, 25 * but subclasses are also allowed to call those methods if they know what they are 26 * doing... 27 */ 28 class Action_body 29 { 30 protected: Action_body()31 Action_body() {} ~Action_body()32 virtual ~Action_body() {} begin(const Xml_string &,Xml_attr)33 virtual void begin(const Xml_string&, Xml_attr) {} end(const Xml_string &)34 virtual void end(const Xml_string&) {} chars(const Xml_string &)35 virtual void chars(const Xml_string&) {} reset()36 virtual void reset() {} 37 38 Digester* dig {nullptr}; 39 private: 40 int refs; 41 friend class Action; 42 }; 43 44 45 46 /** 47 * Actions do all the real work when digesting XML files: creating new objects, 48 * setting attributes, calling methods. Each Action gets control two or more times 49 * for each time the corresponding rule triggers: 1 x begin(), 0- x chars(), 1 x end(). 50 * They come in two basic flavors: Generators create a new object in their begin() 51 * method and put it on the object stack. Other Actions use objects on the stack, 52 * XML attributes or XML text to store this data in other objects. This is usually 53 * done in the end() method. 54 * Warning: end() methods are called in reverse order. This is to ensure that they 55 * see exactly the same stack content as their corresponging begin() method. 56 * This is the handle class which delegates to the body 57 */ 58 class Action 59 { 60 public: digester()61 inline Digester* digester() { return body->dig; } setDigester(Digester * dig)62 inline void setDigester(Digester* dig) { body->dig = dig; } 63 begin(const Xml_string & tag,Xml_attr attr)64 inline void begin(const Xml_string& tag, Xml_attr attr) 65 { body->begin(tag, attr); } end(const Xml_string & tag)66 inline void end(const Xml_string& tag) { body->end(tag); } chars(const Xml_string & data)67 inline void chars(const Xml_string& data) { body->chars(data); } 68 69 // Handle stuff: Action(const Action & other)70 Action(const Action& other) 71 { 72 body = other.body; 73 body->refs++; 74 } ~Action()75 virtual ~Action() 76 { 77 if (--body->refs == 0) 78 delete body; 79 } 80 Action& operator=(const Action& other) 81 { 82 if (body != other.body) { 83 if (--body->refs == 0) 84 delete body; 85 body = other.body; 86 ++body->refs; 87 } 88 return *this; 89 } 90 reset()91 virtual void reset() 92 { 93 body->reset(); 94 } 95 96 protected: Action(Action_body * body_)97 Action(Action_body* body_) 98 { 99 body = body_; 100 body->refs = 1; 101 } 102 103 Action_body* body; 104 105 private: 106 Action(); // not defined 107 }; 108 109 110 class Dummy {}; 111 112 /** 113 * This class implements typed constructors. They are in a subclass since 114 * we don't want the type arguments in Action itself. 115 * Use "class MyAction : public MakeAction<MyAction_body> {} " to define 116 * your own Actions. You have to implement MyAction constructors if you 117 * want constructors with arguments. 118 */ 119 template <class Body, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy, class Arg4=Dummy, class Arg5=Dummy> 120 struct MakeAction : public Action 121 { MakeActionMakeAction122 MakeAction() : Action(new Body()) {} MakeActionMakeAction123 MakeAction(Arg1 a1) : Action(new Body(a1)) {} MakeActionMakeAction124 MakeAction(Arg1 a1, Arg2 a2) : Action(new Body(a1, a2)) {} MakeActionMakeAction125 MakeAction(Arg1 a1, Arg2 a2, Arg3 a3) : Action(new Body(a1, a2, a3)) {} MakeActionMakeAction126 MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) : Action(new Body(a1, a2, a3, a4)) {} MakeActionMakeAction127 MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) : Action(new Body(a1, a2, a3, a4, a5)) {} 128 }; 129 130 131 132 /** 133 * Abstract class for actions which leave a new object on the stack 134 * The begin() method is defined in subclasses and puts the object on stack, 135 * the generic end() method removes this object from stack. 136 */ 137 template<class Type> 138 class Generator_body : public Action_body 139 { 140 public: eval(Digester * dig_,const Xml_string & tag,Xml_attr attr)141 virtual Type* eval(Digester* dig_, const Xml_string& tag, Xml_attr attr) 142 { 143 dig = dig_; 144 begin(tag, attr); 145 Type* res; 146 res = dig->template top<Type>(); 147 end(tag); 148 return res; 149 } 150 protected: end(const Xml_string &)151 virtual void end(const Xml_string& ) { dig->pop(); } 152 }; 153 154 155 156 /** 157 * Generators have their own handle class, which is a subclass of Action 158 */ 159 template<class Type> 160 class Generator : public Action 161 { 162 public: eval(Digester * dig,const Xml_string & tag,Xml_attr attr)163 Type* eval(Digester* dig, const Xml_string& tag, Xml_attr attr) 164 { 165 return static_cast<Generator_body<Type>*>(body)->eval(dig, tag, attr); 166 } 167 168 protected: Generator(Generator_body<Type> * body_)169 Generator(Generator_body<Type>* body_) : Action(body_) {} 170 }; 171 172 173 /** 174 * This class implements typed constructors. They are in a subclass since 175 * we don't want the type arguments in Generator itself. 176 * Use "class MyGenerator : public MakeGenerator<MyGenarator_body, MyType> {} " to 177 * define your own generators. You have to implement MyGenerator constructors if you 178 * want constructors with arguments. 179 */ 180 template <class Body, class Obj_Type, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy> 181 struct MakeGenerator : public Generator<Obj_Type> 182 { MakeGeneratorMakeGenerator183 MakeGenerator() : Generator<Obj_Type>(new Body()) {} MakeGeneratorMakeGenerator184 MakeGenerator(Arg1 a) : Generator<Obj_Type>(new Body(a)) {} MakeGeneratorMakeGenerator185 MakeGenerator(Arg1 a1, Arg2 a2) : Generator<Obj_Type>(new Body(a1, a2)) {} MakeGeneratorMakeGenerator186 MakeGenerator(Arg1 a1, Arg2 a2, Arg3 a3) : Generator<Obj_Type>(new Body(a1, a2, a3)) {} 187 }; 188 189 } // namespace 190 191 #endif 192