Rev 24665 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* actions.h
*
*
* Created by Andreas Vox on 02.06.06.
* Copyright 2006 under GPL2. All rights reserved.
*
*/
#ifndef ACTIONS_H
#define ACTIONS_H
#include <map>
#include <string>
#include "digester.h"
namespace desaxe {
/**
* Action / Action_body follow the handle/body pattern. This allows to omit the
* new operator when creating Action expressions and make dynamic memory handling
* more secure.
* Base class for the body of all actions. Usually Digester calls these methods,
* but subclasses are also allowed to call those methods if they know what they are
* doing...
*/
class Action_body
{
protected:
Action_body() {}
virtual ~Action_body() {}
virtual void begin(const Xml_string&, Xml_attr) {}
virtual void end(const Xml_string&) {}
virtual void chars(const Xml_string&) {}
virtual void reset() {}
Digester* dig {nullptr};
private:
int refs { 0 };
friend class Action;
};
/**
* Actions do all the real work when digesting XML files: creating new objects,
* setting attributes, calling methods. Each Action gets control two or more times
* for each time the corresponding rule triggers: 1 x begin(), 0- x chars(), 1 x end().
* They come in two basic flavors: Generators create a new object in their begin()
* method and put it on the object stack. Other Actions use objects on the stack,
* XML attributes or XML text to store this data in other objects. This is usually
* done in the end() method.
* Warning: end() methods are called in reverse order. This is to ensure that they
* see exactly the same stack content as their corresponding begin() method.
* This is the handle class which delegates to the body
*/
class Action
{
public:
inline Digester* digester() { return body->dig; }
inline void setDigester(Digester* dig) { body->dig = dig; }
inline void begin(const Xml_string& tag, Xml_attr attr)
{ body->begin(tag, attr); }
inline void end(const Xml_string& tag) { body->end(tag); }
inline void chars(const Xml_string& data) { body->chars(data); }
// Handle stuff:
Action(const Action& other)
{
body = other.body;
body->refs++;
}
virtual ~Action()
{
if (--body->refs == 0)
delete body;
}
Action& operator=(const Action& other)
{
if (body != other.body) {
if (--body->refs == 0)
delete body;
body = other.body;
++body->refs;
}
return *this;
}
virtual void reset()
{
body->reset();
}
protected:
Action(Action_body* body_)
{
body = body_;
body->refs = 1;
}
Action_body* body { nullptr };
private:
Action(); // not defined
};
class Dummy {};
/**
* This class implements typed constructors. They are in a subclass since
* we don't want the type arguments in Action itself.
* Use "class MyAction : public MakeAction<MyAction_body> {} " to define
* your own Actions. You have to implement MyAction constructors if you
* want constructors with arguments.
*/
template <class Body, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy, class Arg4=Dummy, class Arg5=Dummy>
struct MakeAction : public Action
{
MakeAction() : Action(new Body()) {}
MakeAction(Arg1 a1) : Action(new Body(a1)) {}
MakeAction(Arg1 a1, Arg2 a2) : Action(new Body(a1, a2)) {}
MakeAction(Arg1 a1, Arg2 a2, Arg3 a3) : Action(new Body(a1, a2, a3)) {}
MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) : Action(new Body(a1, a2, a3, a4)) {}
MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) : Action(new Body(a1, a2, a3, a4, a5)) {}
};
/**
* Abstract class for actions which leave a new object on the stack
* The begin() method is defined in subclasses and puts the object on stack,
* the generic end() method removes this object from stack.
*/
template<class Type>
class Generator_body : public Action_body
{
public:
virtual Type* eval(Digester* dig_, const Xml_string& tag, Xml_attr attr)
{
dig = dig_;
begin(tag, attr);
Type* res;
res = dig->template top<Type>();
end(tag);
return res;
}
protected:
virtual void end(const Xml_string& ) { dig->pop(); }
};
/**
* Generators have their own handle class, which is a subclass of Action
*/
template<class Type>
class Generator : public Action
{
public:
Type* eval(Digester* dig, const Xml_string& tag, Xml_attr attr)
{
return static_cast<Generator_body<Type>*>(body)->eval(dig, tag, attr);
}
protected:
Generator(Generator_body<Type>* body_) : Action(body_) {}
};
/**
* This class implements typed constructors. They are in a subclass since
* we don't want the type arguments in Generator itself.
* Use "class MyGenerator : public MakeGenerator<MyGenarator_body, MyType> {} " to
* define your own generators. You have to implement MyGenerator constructors if you
* want constructors with arguments.
*/
template <class Body, class Obj_Type, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy>
struct MakeGenerator : public Generator<Obj_Type>
{
MakeGenerator() : Generator<Obj_Type>(new Body()) {}
MakeGenerator(Arg1 a) : Generator<Obj_Type>(new Body(a)) {}
MakeGenerator(Arg1 a1, Arg2 a2) : Generator<Obj_Type>(new Body(a1, a2)) {}
MakeGenerator(Arg1 a1, Arg2 a2, Arg3 a3) : Generator<Obj_Type>(new Body(a1, a2, a3)) {}
};
} // namespace
#endif