Rev 24665 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5633 | avox | 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: |
||
23017 | craig | 31 | Action_body() {} |
32 | virtual ~Action_body() {} |
||
33 | virtual void begin(const Xml_string&, Xml_attr) {} |
||
34 | virtual void end(const Xml_string&) {} |
||
35 | virtual void chars(const Xml_string&) {} |
||
36 | virtual void reset() {} |
||
5633 | avox | 37 | |
23017 | craig | 38 | Digester* dig {nullptr}; |
5633 | avox | 39 | private: |
25210 | jghali | 40 | int refs { 0 }; |
5633 | avox | 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 |
||
24665 | jghali | 55 | * see exactly the same stack content as their corresponding begin() method. |
5633 | avox | 56 | * This is the handle class which delegates to the body |
57 | */ |
||
58 | class Action |
||
59 | { |
||
60 | public: |
||
61 | inline Digester* digester() { return body->dig; } |
||
62 | inline void setDigester(Digester* dig) { body->dig = dig; } |
||
63 | |||
8834 | cbradney | 64 | inline void begin(const Xml_string& tag, Xml_attr attr) |
5633 | avox | 65 | { body->begin(tag, attr); } |
8834 | cbradney | 66 | inline void end(const Xml_string& tag) { body->end(tag); } |
67 | inline void chars(const Xml_string& data) { body->chars(data); } |
||
5633 | avox | 68 | |
69 | // Handle stuff: |
||
70 | Action(const Action& other) |
||
71 | { |
||
72 | body = other.body; |
||
73 | body->refs++; |
||
74 | } |
||
75 | virtual ~Action() |
||
76 | { |
||
77 | if (--body->refs == 0) |
||
78 | delete body; |
||
79 | } |
||
80 | Action& operator=(const Action& other) |
||
81 | { |
||
8046 | avox | 82 | if (body != other.body) { |
83 | if (--body->refs == 0) |
||
84 | delete body; |
||
85 | body = other.body; |
||
86 | ++body->refs; |
||
87 | } |
||
5633 | avox | 88 | return *this; |
89 | } |
||
90 | |||
17743 | jghali | 91 | virtual void reset() |
92 | { |
||
93 | body->reset(); |
||
94 | } |
||
95 | |||
5633 | avox | 96 | protected: |
97 | Action(Action_body* body_) |
||
98 | { |
||
99 | body = body_; |
||
100 | body->refs = 1; |
||
101 | } |
||
102 | |||
25210 | jghali | 103 | Action_body* body { nullptr }; |
17382 | jghali | 104 | |
5633 | avox | 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 | */ |
||
8228 | avox | 119 | template <class Body, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy, class Arg4=Dummy, class Arg5=Dummy> |
5633 | avox | 120 | struct MakeAction : public Action |
121 | { |
||
122 | MakeAction() : Action(new Body()) {} |
||
123 | MakeAction(Arg1 a1) : Action(new Body(a1)) {} |
||
124 | MakeAction(Arg1 a1, Arg2 a2) : Action(new Body(a1, a2)) {} |
||
125 | MakeAction(Arg1 a1, Arg2 a2, Arg3 a3) : Action(new Body(a1, a2, a3)) {} |
||
8228 | avox | 126 | MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) : Action(new Body(a1, a2, a3, a4)) {} |
127 | MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) : Action(new Body(a1, a2, a3, a4, a5)) {} |
||
5633 | avox | 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: |
||
8834 | cbradney | 141 | virtual Type* eval(Digester* dig_, const Xml_string& tag, Xml_attr attr) |
5633 | avox | 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: |
||
9042 | avox | 151 | virtual void end(const Xml_string& ) { dig->pop(); } |
5633 | avox | 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: |
||
8834 | cbradney | 163 | Type* eval(Digester* dig, const Xml_string& tag, Xml_attr attr) |
5633 | avox | 164 | { |
165 | return static_cast<Generator_body<Type>*>(body)->eval(dig, tag, attr); |
||
166 | } |
||
167 | |||
168 | protected: |
||
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 | { |
||
183 | MakeGenerator() : Generator<Obj_Type>(new Body()) {} |
||
184 | MakeGenerator(Arg1 a) : Generator<Obj_Type>(new Body(a)) {} |
||
185 | MakeGenerator(Arg1 a1, Arg2 a2) : Generator<Obj_Type>(new Body(a1, a2)) {} |
||
186 | MakeGenerator(Arg1 a1, Arg2 a2, Arg3 a3) : Generator<Obj_Type>(new Body(a1, a2, a3)) {} |
||
187 | }; |
||
188 | |||
189 | } // namespace |
||
190 | |||
191 | #endif |