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);