WIP adjusted BuilderTool (specialisation) and tests....
compiles ok, but segfaults
This commit is contained in:
parent
2bd931b6da
commit
0bb8051fc5
9 changed files with 139 additions and 177 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue