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
** 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
@ -90,14 +90,13 @@ namespace cinelerra
*/
template
< typename RET = void,
template <class> class ERR = UseDefault,
template <class> class ERR = UseDefault
>
class Tool
class Tool : public ERR<RET>
{
public:
typedef RET ReturnType; ///< Tool function invocation return type
typedef Tool<RET> ToolBase; ///< for templating the Tag and Dispatcher
typedef ERR<ToolBase> ErrorPolicy;
typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
virtual ~Tool () { }; ///< use RTTI for all visiting tools

View file

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

View file

@ -17,19 +17,17 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
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
#define CINELERRA_VISITORPOLICIES_H
@ -41,58 +39,37 @@ namespace cinelerra
{
namespace visitor
{
/* == several Policies usable in conjunction with cinelerra::visitor::Visitable == */
/**
* Policy returning just the default return value in case
* of encountering an unknown Visitor (typically caused by
* adding a new class to the visitable hierarchy)
*/
template<class TOOL>
template<class RET>
struct UseDefault
{
typedef TOOL::ReturnType Ret;
template<class TAR>
static Ret onUnknown (TAR&, TOOL&)
RET
onUnknown (TAR&)
{
return Ret();
return RET();
}
};
/**
* Policy to throw when encountering an unknown visiting tool
*/
template<class TOOL>
template<class RET>
struct ThrowException
{
typedef TOOL::ReturnType Ret;
template<class TAR>
static Ret onUnknown (TAR&, TOOL&)
RET
onUnknown (TAR&)
{
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

View file

@ -26,55 +26,16 @@
#include "common/visitor.hpp"
#include "proc/mobject/builder/buildertool.hpp"
namespace mobject
{
namespace builder{ class BuilderTool; }
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
#include "common/visitor.hpp"
#include "proc/mobject/buildable.hpp"
namespace mobject
{
class Buildable;
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
* the concrete implementation for one task to be done to the various MObject classes
* Base class of all BuilderTools, used according to the visitor pattern:
* 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???
{
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>
void zoing(TO& ttt,BO& bot)
{
ttt->treat(bot);
}
typedef cinelerra::visitor::Tool<void, InvokeCatchAllFunction> BuilderTool;
template<class TOOLImpl>
class BuilderToolType
: public cinelerra::visitor::ToolType<TOOLImpl, BuilderTool>
{ }
;
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
/**
* Marker Interface for classes Visitable by Builder tools.
*/
class Buildable : public cinelerra::visitor::Visitable<builder::BuilderTool>
{ };
} // namespace mobject
#endif

View file

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

View file

@ -59,9 +59,10 @@ namespace cinelerra
DEFINE_PROCESSABLE_BY (Tool);
};
template<class BASE>
class VerboseVisitor
: public Tool
: public BASE
{
protected:
void talk_to (string guy)
@ -73,7 +74,7 @@ namespace cinelerra
class Babbler
: public Applicable<Boss,Babbler>,
public Applicable<BigBoss,Babbler>,
public ToolType<Babbler, VerboseVisitor>
public ToolType<Babbler, VerboseVisitor<Tool> >
{
public:
void treat (Boss&) { talk_to("Boss"); }
@ -82,36 +83,37 @@ namespace cinelerra
// the classes above comprise the standard use case,
// what follows are rather exotic corner cases
class Blatherer
: public Applicable<BigBoss,Blatherer>,
public ToolType<Blatherer, VerboseVisitor>
template<class RET>
struct Catched
{
public:
void treat (BigBoss&) { talk_to("big Boss"); }
void treat (HomoSapiens&) { talk_to("we-do-everything-for-YOU"); } ///< catch-all function
void catchy(HomoSapiens&) {}
RET onUnknown (HomoSapiens&) { cout << "we-do-everything-for-YOU!\n"; } ///< catch-all function
};
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,
public Boss ///< can act as HomoSapiens or as Chief
{
public:
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 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)
{
//known_visitor_known_class();
//visitor_not_visiting_some_class();
//visitor_treating_new_subclass();
known_visitor_known_class();
visitor_not_visiting_some_class();
visitor_treating_new_subclass();
}
void known_visitor_known_class()
@ -174,27 +176,22 @@ namespace cinelerra
HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2);
HomoSapiens& homo3 (x3);
Chief& chief1 (x1);
Chief& chief2 (x2);
Leader& lead1 (x1);
Leader& lead2 (x2);
Blatherer bla;
VerboseVisitor vista;
Tool& tool1 (vista);
Tool& 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);
Babbler bab;
Tool& tool1 (bab);
Hastalavista& tool2 (bla);
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
chief2.apply (bla);
cout << "=== VerboseVistr 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
cout << "=== Babbler masqueraded as Tool meets Leader and Visionary masqueraded as HomoSapiens ===\n";
homo1.apply (tool1); // because acting in the HomoSapiens hierarchy, no visiting happens and no catch-all
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
lead2.apply (tool2);
@ -215,7 +212,7 @@ namespace cinelerra
/** 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;
class VerboseVisitor
: public VisitingTool
{
protected:
void talk_to (string guy)
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
};
class HomoSapiens : public Visitable<>
{
public:
@ -52,17 +63,17 @@ namespace cinelerra
public:
DEFINE_PROCESSABLE_BY (VisitingTool);
};
class VerboseVisitor
: public VisitingTool
// the classes above comprise the standard visitor use case,
// now we'll extend the hierarchy a bit...
class BigBoss : public Boss
{
protected:
void talk_to (string guy)
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
public:
DEFINE_PROCESSABLE_BY (VerboseVisitor);
};
class Babbler
: public Applicable<Boss,Babbler>,
@ -74,17 +85,7 @@ namespace cinelerra
void treat (BigBoss&) { talk_to("Big Boss"); }
};
// 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
{
};

View file

@ -41,10 +41,26 @@ namespace mobject
using session::Clip;
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)
{
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;
BuilderTool& tool (t1);