diff --git a/src/common/visitor.hpp b/src/common/visitor.hpp
index a0bed9357..8509c4fc0 100644
--- a/src/common/visitor.hpp
+++ b/src/common/visitor.hpp
@@ -36,7 +36,7 @@ Credits for many further implementation ideas go to
*/
-/** @file visitor.cpp
+/** @file visitor.hpp
** A library implementation of the Visitor Pattern taylored specifically
** to cinelerra's needs within the Proc Layer. Visitor enables double dispatch
** 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 ERR = UseDefault,
+ template class ERR = UseDefault
>
- class Tool
+ class Tool : public ERR
{
public:
typedef RET ReturnType; ///< Tool function invocation return type
- typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
- typedef ERR ErrorPolicy;
+ typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
virtual ~Tool () { }; ///< use RTTI for all visiting tools
diff --git a/src/common/visitordispatcher.hpp b/src/common/visitordispatcher.hpp
index f28b45a09..e81a573d4 100644
--- a/src/common/visitordispatcher.hpp
+++ b/src/common/visitordispatcher.hpp
@@ -27,6 +27,7 @@
#include "common/error.hpp"
#include "common/util.hpp"
+#include "common/singleton.hpp"
#include
@@ -153,7 +154,7 @@ namespace cinelerra
static ReturnType
errorHandler (TAR& target, TOOL& tool)
{
- return TOOL::ErrorPolicy::onUnknown (target, tool);
+ return tool.onUnknown (target);
}
diff --git a/src/common/visitorpolicies.hpp b/src/common/visitorpolicies.hpp
index 5e3cdeb43..2fd0cb37f 100644
--- a/src/common/visitorpolicies.hpp
+++ b/src/common/visitorpolicies.hpp
@@ -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
+ template
struct UseDefault
{
- typedef TOOL::ReturnType Ret;
-
template
- static Ret onUnknown (TAR&, TOOL&)
+ RET
+ onUnknown (TAR&)
{
- return Ret();
+ return RET();
}
};
/**
* Policy to throw when encountering an unknown visiting tool
*/
- template
+ template
struct ThrowException
{
- typedef TOOL::ReturnType Ret;
-
template
- 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
- struct InvokeCatchAllFunction
- {
- typedef TOOL::ReturnType Ret;
-
- template
- static Ret onUnknown (TAR& target,TOOL& tool)
- {
- return tool.catchAll (target);
- }
- };
-
+
} // namespace visitor
diff --git a/src/proc/mobject/buildable.hpp b/src/proc/mobject/buildable.hpp
index b7bbe5483..09de1d953 100644
--- a/src/proc/mobject/buildable.hpp
+++ b/src/proc/mobject/buildable.hpp
@@ -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. 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); }
diff --git a/src/proc/mobject/builder/buildertool.hpp b/src/proc/mobject/builder/buildertool.hpp
index a4d6da5fc..fb472cd05 100644
--- a/src/proc/mobject/builder/buildertool.hpp
+++ b/src/proc/mobject/builder/buildertool.hpp
@@ -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 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
- void catchy (BB& elem) {elem.fallback(*this); }
- };
-
- template
- void zoing(TO& ttt,BO& bot)
- {
- ttt->treat(bot);
- }
+ typedef cinelerra::visitor::Tool BuilderTool;
+
+
+ template
+ class BuilderToolType
+ : public cinelerra::visitor::ToolType
+ { }
+ ;
+
+
+ template
+ < class TAR, // concrete Buildable to be treated
+ class TOOLImpl // concrete BuilderTool implementation
+ >
+ class Applicable
+ : public cinelerra::visitor::Applicable
+ { }
+ ;
} // namespace mobject::builder
+
+
+
+ /**
+ * Marker Interface for classes Visitable by Builder tools.
+ */
+ class Buildable : public cinelerra::visitor::Visitable
+ { };
} // namespace mobject
#endif
diff --git a/src/proc/mobject/session/abstractmo.hpp b/src/proc/mobject/session/abstractmo.hpp
index ccb08cd83..bd4fd5785 100644
--- a/src/proc/mobject/session/abstractmo.hpp
+++ b/src/proc/mobject/session/abstractmo.hpp
@@ -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);
};
diff --git a/tests/components/common/visitingtoolextendedtest.cpp b/tests/components/common/visitingtoolextendedtest.cpp
index 4b5ae4414..79f5b0ab1 100644
--- a/tests/components/common/visitingtoolextendedtest.cpp
+++ b/tests/components/common/visitingtoolextendedtest.cpp
@@ -59,9 +59,10 @@ namespace cinelerra
DEFINE_PROCESSABLE_BY (Tool);
};
-
+
+ template
class VerboseVisitor
- : public Tool
+ : public BASE
{
protected:
void talk_to (string guy)
@@ -73,7 +74,7 @@ namespace cinelerra
class Babbler
: public Applicable,
public Applicable,
- public ToolType
+ public ToolType >
{
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,
- public ToolType
+
+
+ template
+ 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 Hastalavista;
+ typedef Visitable Chief; ///< another special kind of visitables
- typedef Visitable 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,
+ public ToolType >
+ {
+ 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");
diff --git a/tests/components/common/visitingtooltest.cpp b/tests/components/common/visitingtooltest.cpp
index 5fbf9a97a..db9f91588 100644
--- a/tests/components/common/visitingtooltest.cpp
+++ b/tests/components/common/visitingtooltest.cpp
@@ -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,
@@ -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
{
};
diff --git a/tests/components/proc/mobject/builder/buildertooltest.cpp b/tests/components/proc/mobject/builder/buildertooltest.cpp
index 6b0dadd01..9b55b47e6 100644
--- a/tests/components/proc/mobject/builder/buildertooltest.cpp
+++ b/tests/components/proc/mobject/builder/buildertooltest.cpp
@@ -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,
+ public Applicable,
+ public Applicable
+ {
+ 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,
- public Applicable
- {
- 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);