WIP adjusted BuilderTool (specialisation) and tests....

compiles ok, but segfaults
This commit is contained in:
Fischlurch 2008-01-05 01:38:32 +01:00
parent 2bd931b6da
commit 0bb8051fc5
9 changed files with 139 additions and 177 deletions

View file

@ -36,7 +36,7 @@ Credits for many further implementation ideas go to
*/ */
/** @file visitor.cpp /** @file visitor.hpp
** A library implementation of the <b>Visitor Pattern</b> taylored specifically ** A library implementation of the <b>Visitor Pattern</b> taylored specifically
** to cinelerra's needs within the Proc Layer. Visitor enables <b>double dispatch</b> ** to cinelerra's needs within the Proc Layer. Visitor enables <b>double dispatch</b>
** calls, based both on the concrete type of some target object and the concrete type of ** calls, based both on the concrete type of some target object and the concrete type of
@ -90,14 +90,13 @@ namespace cinelerra
*/ */
template template
< typename RET = void, < typename RET = void,
template <class> class ERR = UseDefault, template <class> class ERR = UseDefault
> >
class Tool class Tool : public ERR<RET>
{ {
public: public:
typedef RET ReturnType; ///< Tool function invocation return type typedef RET ReturnType; ///< Tool function invocation return type
typedef Tool<RET> ToolBase; ///< for templating the Tag and Dispatcher typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
typedef ERR<ToolBase> ErrorPolicy;
virtual ~Tool () { }; ///< use RTTI for all visiting tools virtual ~Tool () { }; ///< use RTTI for all visiting tools

View file

@ -27,6 +27,7 @@
#include "common/error.hpp" #include "common/error.hpp"
#include "common/util.hpp" #include "common/util.hpp"
#include "common/singleton.hpp"
#include <vector> #include <vector>
@ -153,7 +154,7 @@ namespace cinelerra
static ReturnType static ReturnType
errorHandler (TAR& target, TOOL& tool) errorHandler (TAR& target, TOOL& tool)
{ {
return TOOL::ErrorPolicy::onUnknown (target, tool); return tool.onUnknown (target);
} }

View file

@ -18,18 +18,16 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
====================================================================
This code is heavily inspired by
The Loki Library (loki-lib/trunk/include/loki/Visitor.h)
Copyright (c) 2001 by Andrei Alexandrescu
This Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
*/ */
/** @file visitorpolicies.hpp
** Policies usable for configuring the cinelerra::visitor::Tool for different kinds of error handling.
** @see buildertool.hpp for another flavor (calling and catch-all-function)
**
*/
#ifndef CINELERRA_VISITORPOLICIES_H #ifndef CINELERRA_VISITORPOLICIES_H
#define CINELERRA_VISITORPOLICIES_H #define CINELERRA_VISITORPOLICIES_H
@ -41,57 +39,36 @@ namespace cinelerra
{ {
namespace visitor namespace visitor
{ {
/* == several Policies usable in conjunction with cinelerra::visitor::Visitable == */
/** /**
* Policy returning just the default return value in case * Policy returning just the default return value in case
* of encountering an unknown Visitor (typically caused by * of encountering an unknown Visitor (typically caused by
* adding a new class to the visitable hierarchy) * adding a new class to the visitable hierarchy)
*/ */
template<class TOOL> template<class RET>
struct UseDefault struct UseDefault
{ {
typedef TOOL::ReturnType Ret;
template<class TAR> template<class TAR>
static Ret onUnknown (TAR&, TOOL&) RET
onUnknown (TAR&)
{ {
return Ret(); return RET();
} }
}; };
/** /**
* Policy to throw when encountering an unknown visiting tool * Policy to throw when encountering an unknown visiting tool
*/ */
template<class TOOL> template<class RET>
struct ThrowException struct ThrowException
{ {
typedef TOOL::ReturnType Ret;
template<class TAR> template<class TAR>
static Ret onUnknown (TAR&, TOOL&) RET
onUnknown (TAR&)
{ {
throw cinelerra::error::Config("unable to decide what tool operation to call"); throw cinelerra::error::Config("unable to decide what tool operation to call");
} }
}; };
/**
* Policy invoking an catch-all function for processing
* an unknown tool / target pair
* @note using this policy effectively enforces
* implementing a catch-all function \c treat(TAR&)
*/
template<class TOOL>
struct InvokeCatchAllFunction
{
typedef TOOL::ReturnType Ret;
template<class TAR>
static Ret onUnknown (TAR& target,TOOL& tool)
{
return tool.catchAll (target);
}
};
} // namespace visitor } // namespace visitor

View file

@ -26,55 +26,16 @@
#include "common/visitor.hpp" #include "common/visitor.hpp"
#include "proc/mobject/builder/buildertool.hpp"
namespace mobject namespace mobject
{ {
namespace builder{ class BuilderTool; }
using cinelerra::visitor::Visitable; using cinelerra::visitor::Visitable;
using cinelerra::visitor::InvokeCatchAllFunction;
/**
* All Buidables support double-dispatch of given Tool operations.
* The actual operation is thus selected at runtime based both on the
* actual type of the Tool class /and/ the actual type of the Buildabele.
*/
class Buildable : public Visitable
< void, // return type of apply
builder::BuilderTool, // visiting tool base class
InvokeCatchAllFunction // how to handle unknown
>
{
public:
/** Catch-all implementation for applying any builder tool
* to some (uspecified) buildable object. Typically the provided
* actual Tool class will contain overloaded fuctions for treating
* different Buildable subclasses specifically and the concrete Buildables
* will define explicitly to be specifically visitable.
*/
// virtual void apply (builder::BuilderTool&); ////////////////////////////// besser weg????
virtual void fallback(builder::BuilderTool&) = 0;
};
/** mark a Buildable subclass as actually treatable
* by some BuilderTool. Note this defines a more concrete
* apply-function, which actually dispatches with a
* Placement<TARGET>. Crutial to make the builder work.
*/
#define DEFINE_BUILDABLE \
virtual void apply (builder::BuilderTool& tool) \
{ return dispatchOp (*this, tool); }
///////////////////////////////bringt das überhaupt was???
#define DEFINE_FALLBACK \
virtual void fallback(builder::BuilderTool& tool) \
{ apply(tool); }

View file

@ -25,42 +25,69 @@
#define MOBJECT_BUILDER_TOOL_H #define MOBJECT_BUILDER_TOOL_H
#include "common/visitor.hpp" #include "common/visitor.hpp"
#include "proc/mobject/buildable.hpp"
namespace mobject namespace mobject
{ {
class Buildable;
namespace builder namespace builder
{ {
using cinelerra::visitor::Tool; /**
* Policy invoking an catch-all function for processing
* an unknown tool / target pair, effectively enforcing the
* implementation of a catch-all function \c onUnknown(BASE&)
*/
template<class RET>
class InvokeCatchAllFunction
{
protected:
virtual ~InvokeCatchAllFunction() {}
public:
virtual RET onUnknown (Buildable& target) = 0;
};
/** /**
* Used according to the visitor pattern: each Tool contains * Base class of all BuilderTools, used according to the visitor pattern:
* the concrete implementation for one task to be done to the various MObject classes * each Tool contains the concrete implementation for one task to be done
* to the various MObject classes. The concrete builder tool implementation
* should not diretcly inherit from this base interface, but rather through
* an instantiation of the BuilderToolType template. Additionally, it should
* inherit from the Applicable template parametrized with all conctrete
* Buildable classes, for which it wants calls to be dispatched.
*/ */
class BuilderTool : public Tool //////////////////////////auf die Zielklasse templaten und Placement festmachen??? typedef cinelerra::visitor::Tool<void, InvokeCatchAllFunction> BuilderTool;
{
protected:
typedef mobject::Buildable Buildable;
public:
/** This operation is to be overloaded for specific MObject subclasses to be treated.
*/
//virtual void treat (Buildable& mElement) = 0;
template<class BB>
void catchy (BB& elem) {elem.fallback(*this); }
};
template<class TO, class BO> template<class TOOLImpl>
void zoing(TO& ttt,BO& bot) class BuilderToolType
{ : public cinelerra::visitor::ToolType<TOOLImpl, BuilderTool>
ttt->treat(bot); { }
} ;
template
< class TAR, // concrete Buildable to be treated
class TOOLImpl // concrete BuilderTool implementation
>
class Applicable
: public cinelerra::visitor::Applicable<TAR,TOOLImpl, BuilderTool>
{ }
;
} // namespace mobject::builder } // namespace mobject::builder
/**
* Marker Interface for classes Visitable by Builder tools.
*/
class Buildable : public cinelerra::visitor::Visitable<builder::BuilderTool>
{ };
} // namespace mobject } // namespace mobject
#endif #endif

View file

@ -47,9 +47,7 @@ namespace mobject
virtual Time& getLength() { return length; } virtual Time& getLength() { return length; }
// DEFINE_PROCESSABLE_BY (builder::BuilderTool); DEFINE_PROCESSABLE_BY (builder::BuilderTool);
DEFINE_BUILDABLE;
DEFINE_FALLBACK;
}; };

View file

@ -60,8 +60,9 @@ namespace cinelerra
}; };
template<class BASE>
class VerboseVisitor class VerboseVisitor
: public Tool : public BASE
{ {
protected: protected:
void talk_to (string guy) void talk_to (string guy)
@ -73,7 +74,7 @@ namespace cinelerra
class Babbler class Babbler
: public Applicable<Boss,Babbler>, : public Applicable<Boss,Babbler>,
public Applicable<BigBoss,Babbler>, public Applicable<BigBoss,Babbler>,
public ToolType<Babbler, VerboseVisitor> public ToolType<Babbler, VerboseVisitor<Tool> >
{ {
public: public:
void treat (Boss&) { talk_to("Boss"); } void treat (Boss&) { talk_to("Boss"); }
@ -83,35 +84,36 @@ namespace cinelerra
// the classes above comprise the standard use case, // the classes above comprise the standard use case,
// what follows are rather exotic corner cases // what follows are rather exotic corner cases
class Blatherer
: public Applicable<BigBoss,Blatherer>, template<class RET>
public ToolType<Blatherer, VerboseVisitor> struct Catched
{ {
public: RET onUnknown (HomoSapiens&) { cout << "we-do-everything-for-YOU!\n"; } ///< catch-all function
void treat (BigBoss&) { talk_to("big Boss"); }
void treat (HomoSapiens&) { talk_to("we-do-everything-for-YOU"); } ///< catch-all function
void catchy(HomoSapiens&) {}
}; };
typedef visitor::Tool<void, Catched> Hastalavista;
typedef Visitable<Hastalavista> Chief; ///< another special kind of visitables
typedef Visitable<void,Blatherer,InvokeCatchAllFunction> Vista2;
class Chief : public Vista2 ///< abstract intermeidary node
{
};
class Leader : public Chief, class Leader : public Chief,
public Boss ///< can act as HomoSapiens or as Chief public Boss ///< can act as HomoSapiens or as Chief
{ {
public: public:
using HomoSapiens::apply; using HomoSapiens::apply;
virtual void apply (Blatherer& tool) { return Vista2::dispatchOp (*this, tool); } virtual void apply (Hastalavista& tool) { return Chief::dispatchOp (*this, tool); }
}; };
class Visionary : public Leader class Visionary : public Leader
{ {
}; };
class Blatherer
: public Applicable<Visionary,Blatherer,Hastalavista>,
public ToolType<Blatherer, VerboseVisitor<Hastalavista> >
{
public:
void treat (Leader&) { talk_to("Mr.Future"); }
};
@ -132,9 +134,9 @@ namespace cinelerra
{ {
virtual void run(Arg arg) virtual void run(Arg arg)
{ {
//known_visitor_known_class(); known_visitor_known_class();
//visitor_not_visiting_some_class(); visitor_not_visiting_some_class();
//visitor_treating_new_subclass(); visitor_treating_new_subclass();
} }
void known_visitor_known_class() void known_visitor_known_class()
@ -174,27 +176,22 @@ namespace cinelerra
HomoSapiens& homo1 (x1); HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2); HomoSapiens& homo2 (x2);
HomoSapiens& homo3 (x3);
Chief& chief1 (x1); Chief& chief1 (x1);
Chief& chief2 (x2); Chief& chief2 (x2);
Leader& lead1 (x1); Leader& lead1 (x1);
Leader& lead2 (x2); Leader& lead2 (x2);
Blatherer bla; Blatherer bla;
VerboseVisitor vista; Babbler bab;
Tool& tool1 (vista); Tool& tool1 (bab);
Tool& tool2 (bla); Hastalavista& tool2 (bla);
cout << "=== Blatherer meets Leader, Visionary and HomoSapiens masqueraded as HomoSapiens ===\n";
homo1.apply (bla); // nothing happens, because Blatherer doesn't declare to do anything as Tool
homo2.apply (bla);
homo3.apply (bla);
cout << "=== Blatherer meets Leader and Visionary masqueraded as Chief ===\n"; cout << "=== Blatherer meets Leader and Visionary masqueraded as Chief ===\n";
chief1.apply (bla); // but now, acting in the Chief hierarchy, the catch-all is called chief1.apply (bla); // but now, acting in the Chief hierarchy, the catch-all is called
chief2.apply (bla); chief2.apply (bla);
cout << "=== VerboseVistr masqueraded as Tool meets Leader and Visionary masqueraded as HomoSapiens ===\n"; cout << "=== Babbler masqueraded as Tool meets Leader and Visionary masqueraded as HomoSapiens ===\n";
homo1.apply (tool1); // because acting in the HomoSapiens hierarch, no visiting happens and no catch-all homo1.apply (tool1); // because acting in the HomoSapiens hierarchy, no visiting happens and no catch-all
homo2.apply (tool1); homo2.apply (tool1);
cout << "=== Blatherer masqueraded as Tool meets Leader and Visionary masqueraded as Leader ===\n"; cout << "=== Blatherer masqueraded as Hastalavista meets Leader and Visionary masqueraded as Leader ===\n";
lead1.apply (tool2); // nothing happens, because Leader here is treated by his HomoSapiens base lead1.apply (tool2); // nothing happens, because Leader here is treated by his HomoSapiens base
lead2.apply (tool2); lead2.apply (tool2);
@ -215,7 +212,7 @@ namespace cinelerra
/** Register this test class... */ /** Register this test class... */
// LAUNCHER (VisitingToolExtended_test, "unit common"); LAUNCHER (VisitingToolExtended_test, "unit common");

View file

@ -41,6 +41,17 @@ namespace cinelerra
{ {
typedef visitor::Tool<> VisitingTool; typedef visitor::Tool<> VisitingTool;
class VerboseVisitor
: public VisitingTool
{
protected:
void talk_to (string guy)
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
};
class HomoSapiens : public Visitable<> class HomoSapiens : public Visitable<>
{ {
public: public:
@ -53,17 +64,17 @@ namespace cinelerra
DEFINE_PROCESSABLE_BY (VisitingTool); DEFINE_PROCESSABLE_BY (VisitingTool);
}; };
// the classes above comprise the standard visitor use case,
// now we'll extend the hierarchy a bit...
class VerboseVisitor
: public VisitingTool class BigBoss : public Boss
{ {
protected: public:
void talk_to (string guy) DEFINE_PROCESSABLE_BY (VerboseVisitor);
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
}; };
class Babbler class Babbler
: public Applicable<Boss,Babbler>, : public Applicable<Boss,Babbler>,
public Applicable<BigBoss,Babbler>, public Applicable<BigBoss,Babbler>,
@ -75,16 +86,6 @@ namespace cinelerra
}; };
// the classes above comprise the standard visitor use case,
// now we'll extend the hierarchy a bit...
class BigBoss : public Boss
{
public:
DEFINE_PROCESSABLE_BY (VerboseVisitor);
};
class Leader : public Boss class Leader : public Boss
{ {
}; };

View file

@ -41,9 +41,25 @@ namespace mobject
using session::Clip; using session::Clip;
using session::AbstractMO; using session::AbstractMO;
using cinelerra::visitor::Applicable;
class DummyMO : public AbstractMO
{
public:
DummyMO() { };
virtual bool isValid() const { return true;}
};
class TestTool : public BuilderToolType<TestTool>,
public Applicable<Clip,TestTool>,
public Applicable<AbstractMO,TestTool>
{
public:
void treat (Clip& c) { cout << "media is: "<< str(c.getMedia()) <<"\n"; }
void treat (AbstractMO&){ cout << "catch-all-MO.\n"; }
void onUnknown (Buildable&){ cout << "catch-all-function called.\n"; }
};
@ -68,21 +84,6 @@ namespace mobject
{ {
virtual void run(Arg arg) virtual void run(Arg arg)
{ {
class DummyMO : public AbstractMO
{
public:
DummyMO() { };
virtual bool isValid() const { return true;}
};
class TestTool : public BuilderTool,
public Applicable<Clip>,
public Applicable<AbstractMO>
{
void treat (Clip& c) { cout << "media is: "<< str(c.getMedia()) <<"\n"; }
void treat (Buildable&){ cout << "catch-all-function called.\n"; }
void treat (AbstractMO&){ cout << "catch-all-MO.\n"; }
};
TestTool t1; TestTool t1;
BuilderTool& tool (t1); BuilderTool& tool (t1);