new visitor implementation now running.

Veryfied the tests, cleaned up. TODO: concurrency, error checks and convienience shortcuts.
This commit is contained in:
Fischlurch 2008-01-05 14:26:28 +01:00
parent cb602663d0
commit 9aa3cc11e8
14 changed files with 101 additions and 221 deletions

View file

@ -101,7 +101,7 @@ namespace cinelerra
virtual ~Tool () { }; ///< use RTTI for all visiting tools
/** allows discovery of the concrete Tool type when dispatching a
* visitor call. Can be implemented by inheriting from ToolType */
* visitor call. Can be implemented by inheriting from ToolTag */
virtual Tag<ToolBase> getTag() = 0;
};
@ -110,7 +110,7 @@ namespace cinelerra
* Mixin for attaching a type tag to the concrete tool implementation
*/
template<class TOOLImpl, class BASE=Tool<> >
class ToolType : public BASE
class ToolTag : public BASE
{
typedef typename BASE::ToolBase ToolBase;

View file

@ -1,43 +0,0 @@
/*
Buildable - marker interface denoting any MObject able to be treated by Tools
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.
* *****************************************************/
#include "proc/mobject/buildable.hpp"
#include "proc/mobject/builder/buildertool.hpp"
namespace mobject
{
/** typically the provided actual Tool class will
* contain overloaded fuctions for treating
* different Buildable subclasses specifically
*/
/* Buildable::ReturnType
Buildable::apply (builder::BuilderTool& tool)
{
return dispatchOp (*this, tool);
}
*/
} // namespace mobject

View file

@ -1,43 +0,0 @@
/*
BUILDABLE.hpp - marker interface denoting any (M)Object able to be treated by Tools
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.
*/
#ifndef MOBJECT_BUILDABLE_H
#define MOBJECT_BUILDABLE_H
#include "common/visitor.hpp"
#include "proc/mobject/builder/buildertool.hpp"
namespace mobject
{
using cinelerra::visitor::Visitable;
} // namespace mobject
#endif

View file

@ -1,40 +0,0 @@
/*
BuilderTool - Interface, (visiting) tool for processing MObjects
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.
* *****************************************************/
#include "proc/mobject/builder/buildertool.hpp"
namespace mobject
{
namespace builder
{
/** */
} // namespace mobject::builder
} // namespace mobject

View file

@ -56,7 +56,7 @@ namespace mobject
* 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
* an instantiation of the BuilderToolTag template. Additionally, it should
* inherit from the Applicable template parametrized with all conctrete
* Buildable classes, for which it wants calls to be dispatched.
*/
@ -64,8 +64,8 @@ namespace mobject
template<class TOOLImpl>
class BuilderToolType
: public cinelerra::visitor::ToolType<TOOLImpl, BuilderTool>
class BuilderToolTag
: public cinelerra::visitor::ToolTag<TOOLImpl, BuilderTool>
{ }
;

View file

@ -22,7 +22,6 @@
#include "proc/mobject/builder/nodecreatertool.hpp"
#include "proc/mobject/buildable.hpp"
#include "proc/mobject/session/clip.hpp"
#include "proc/mobject/session/effect.hpp"
#include "proc/mobject/session/auto.hpp"

View file

@ -25,7 +25,6 @@
#define MOBJECT_BUILDER_NODECREATERTOOL_H
#include "proc/mobject/builder/buildertool.hpp"
#include "proc/mobject/buildable.hpp"
#include "proc/engine/processor.hpp"

View file

@ -22,7 +22,6 @@
#include "proc/mobject/builder/segmentationtool.hpp"
#include "proc/mobject/buildable.hpp"
#include "proc/mobject/session/clip.hpp"
#include "proc/mobject/session/effect.hpp"
#include "proc/mobject/session/segment.hpp"

View file

@ -26,7 +26,6 @@
#include <list>
#include "proc/mobject/buildable.hpp"
#include "proc/mobject/builder/buildertool.hpp"
#include "proc/mobject/session/segment.hpp"

View file

@ -28,7 +28,6 @@
#include <tr1/memory>
#include "cinelerra.h"
#include "proc/mobject/buildable.hpp"
#include "proc/mobject/builder/buildertool.hpp"
#include "proc/mobject/placement.hpp"
#include "proc/asset.hpp" // TODO finally not needed?

View file

@ -185,15 +185,27 @@ END
TEST "VisitingTool_test" VisitingTool_test <<END
out: === Babbler meets Boss and BigBoss ===
out: Hello Boss, nice to meet you...
out: Hello big Boss, nice to meet you...
out: Hello Big Boss, nice to meet you...
out: === Babbler meets HomoSapiens and Leader ===
out: Hello Boss, nice to meet you...
out: === Blatherer meets Leader, Visionary and HomoSapiens masqueraded as HomoSapiens ===
out: === Blatherer meets Leader and Visionary masqueraded as Chief ===
out: Hello we-do-everything-for-YOU, nice to meet you...
out: Hello we-do-everything-for-YOU, nice to meet you...
out: === VerboseVistr masqueraded as Tool meets Leader and Visionary masqueraded as HomoSapiens ===
out: === Blatherer masqueraded as Tool meets Leader and Visionary masqueraded as Leader ===
return: 0
END
TEST "VisitingToolExtended_test" VisitingToolExtended_test <<END
out: === Babbler meets Boss and BigBoss ===
out: Hello Boss, nice to meet you...
out: Hello Big Boss, nice to meet you...
out: === Babbler meets HomoSapiens and Leader ===
out: Hello Boss, nice to meet you...
out: === Blatherer meets Leader and Visionary masqueraded as Chief ===
out: we-do-everything-for-YOU!
out: Hello Mr.Future, nice to meet you...
out: === Babbler masqueraded as Tool meets Leader and Visionary masqueraded as HomoSapiens ===
out: Hello Boss, nice to meet you...
out: Hello Boss, nice to meet you...
out: === Babbler masqueraded as Tool meets Leader and Visionary masqueraded as Leader ===
out: Hello Boss, nice to meet you...
return: 0
END

View file

@ -23,7 +23,6 @@
#include "common/test/run.hpp"
#include "common/visitor.hpp"
//#include "common/util.hpp"
#include <boost/format.hpp>
#include <iostream>
@ -37,7 +36,7 @@ namespace cinelerra
{
namespace visitor
{
namespace test
namespace test2
{
typedef visitor::Tool<> Tool;
@ -74,7 +73,7 @@ namespace cinelerra
class Babbler
: public Applicable<Boss,Babbler>,
public Applicable<BigBoss,Babbler>,
public ToolType<Babbler, VerboseVisitor<Tool> >
public ToolTag<Babbler, VerboseVisitor<Tool> >
{
public:
void treat (Boss&) { talk_to("Boss"); }
@ -82,53 +81,63 @@ namespace cinelerra
};
// the classes above comprise the standard use case,
// what follows are rather exotic corner cases
// what follows covers rather exotic corner cases
/** defines an catch-all-function instead of the silent default error handler */
template<class RET>
struct Catched
{
RET onUnknown (HomoSapiens&) { cout << "we-do-everything-for-YOU!\n"; } ///< catch-all function
RET onUnknown (HomoSapiens&) { cout << "we-do-everything-for-YOU!\n"; }
};
/** defines another different visiting tool base */
typedef visitor::Tool<void, Catched> Hastalavista;
typedef Visitable<Hastalavista> Chief; ///< another special kind of visitables
#define DEFINE_HASTALAVISTA_PROCESSABLE \
virtual void apply (Hastalavista& tool) \
{ return Chief::dispatchOp (*this, tool); }
/** now mixing the two hierarchies... */
class Leader : public Chief,
public Boss ///< can act as HomoSapiens or as Chief
{
public:
using HomoSapiens::apply;
virtual void apply (Hastalavista& tool) { return Chief::dispatchOp (*this, tool); }
};
class Visionary : public Leader
{
DEFINE_HASTALAVISTA_PROCESSABLE;
};
class Visionary : public Leader
{
DEFINE_HASTALAVISTA_PROCESSABLE;
};
/** Hastalavista-Visiting-Tool
* tailored for the Chief hierarchy
*/
class Blatherer
: public Applicable<Visionary,Blatherer,Hastalavista>,
public ToolType<Blatherer, VerboseVisitor<Hastalavista> >
public ToolTag<Blatherer, VerboseVisitor<Hastalavista> >
{
public:
void treat (Leader&) { talk_to("Mr.Future"); }
};
/*************************************************************************
* @test our lib implementation of the acyclic visitor pattern.
* Defines a hierarchy of test classes to check the following cases
* <ul><li>calling the correct visiting tool specialized function
* for given concrete hierarchy classes</li>
* <li>visiting tool not declaring to visit some class</li>
* <li>newly added class causes the catch-all to be invoked
* when visited by known visitor</li>
* </ul>
* @test more esoteric corner cases of our visitor lib implementation.
* Defines a hierarchy of test classes, which mix two different
* kinds of "visitable" by two disjoint tool base classes. One
* of these base classes uses an explicit error handling
* catch-all-function.
*/
class VisitingToolExtended_test : public Test
{
@ -136,7 +145,7 @@ namespace cinelerra
{
known_visitor_known_class();
visitor_not_visiting_some_class();
visitor_treating_new_subclass();
visiting_mixed_hierarchy();
}
void known_visitor_known_class()
@ -168,11 +177,10 @@ namespace cinelerra
homo2.apply (bab); // treats Leader as Boss
}
void visitor_treating_new_subclass()
void visiting_mixed_hierarchy()
{
Leader x1;
Visionary x2;
HomoSapiens x3;
HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2);
@ -182,26 +190,21 @@ namespace cinelerra
Leader& lead2 (x2);
Blatherer bla;
cout << "=== Blatherer meets Leader and Visionary masqueraded as Chief ===\n";
chief1.apply (bla); // catch-all, because Blatherer doesn't declare to be applicalbe to Leader
chief2.apply (bla); // treat(Visionary&) resolved to treat(Leader&) as expected
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 << "=== 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 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);
// note: the following doesn't compile (an this is a feature, not a bug):
homo1.apply (tool1); // because just going through the VTable, the dispatch works as expected
homo2.apply (tool1); // same here (in both cases, the call is resolved to treat(Boss&) as expected)
// "chief1.apply (tool2)" : because the "Chief"-hierarchy enforces the catch-all function
// and the compiler doesn't know Blatherer actually implements this
// catch-all-function, because of the masqueradeing as Tool. Note
// further: the catch-all function can have a more general type
// (in this case HomoSapiens instead of Chief)
cout << "=== Babbler masqueraded as Tool meets Leader and Visionary masqueraded as Leader ===\n";
lead1.apply (tool1); // nothing happens, because Leader here is treated by his HomoSapiens base
lead2.apply (tool1); // surprisingly the VTable mechanism is choosen here, resulting in an correct dispatch
// note: the following doesn't compile (an this is a feature, not a bug):
// "Chief chief" : is abstract, because the Visitable-Template enforces implementing
// the "apply(TOOL&)" function, either directly or via the

View file

@ -23,7 +23,6 @@
#include "common/test/run.hpp"
#include "common/visitor.hpp"
//#include "common/util.hpp"
#include <boost/format.hpp>
#include <iostream>
@ -37,21 +36,10 @@ namespace cinelerra
{
namespace visitor
{
namespace test
namespace test1
{
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:
@ -64,40 +52,47 @@ namespace cinelerra
DEFINE_PROCESSABLE_BY (VisitingTool);
};
// 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);
DEFINE_PROCESSABLE_BY (VisitingTool);
};
class Visionary : public Boss
{
DEFINE_PROCESSABLE_BY (VisitingTool);
};
class Leader : public Visionary
{
};
class VerboseVisitor
: public VisitingTool
{
protected:
void talk_to (string guy)
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
};
class Babbler
: public Applicable<Boss,Babbler>,
public Applicable<BigBoss,Babbler>,
public ToolType<Babbler, VerboseVisitor>
public Applicable<Visionary,Babbler>,
public ToolTag<Babbler, VerboseVisitor>
{
public:
void treat (Boss&) { talk_to("Boss"); }
void treat (BigBoss&) { talk_to("Big Boss"); }
};
class Leader : public Boss
{
};
class Visionary : public Leader
{
};
// note the following details:
// - Babbler "forgot" to declare being applicable to HomoSapiens
// - BigBoss accepts only the subclass (VerboseVisitor)
// - we have new derived classes without separate "apply()"-implementation
// - we have new derived class Leader without separate "apply()"-implementation
@ -140,16 +135,16 @@ namespace cinelerra
void visiting_extended_hierarchy()
{
HomoSapiens x1;
Visionary x2;
Leader x2;
HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2);
cout << "=== Babbler meets HomoSapiens and Visionary ===\n";
cout << "=== Babbler meets HomoSapiens and Leader ===\n";
Babbler bab;
VisitingTool& vista (bab);
homo1.apply (vista); // error handler (not Applicable to HomoSapiens)
homo2.apply (vista); // treats Visionary as Boss
homo1.apply (vista); // silent error handler (not Applicable to HomoSapiens)
homo2.apply (vista); // Leader handeld as Visionary and treated as Boss
}
};

View file

@ -48,15 +48,16 @@ namespace mobject
public:
DummyMO() { };
virtual bool isValid() const { return true;}
DEFINE_PROCESSABLE_BY (BuilderTool);
};
class TestTool : public BuilderToolType<TestTool>,
class TestTool : public BuilderToolTag<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 treat (AbstractMO&){ cout << "unspecific MO.\n"; }
void onUnknown (Buildable&){ cout << "catch-all-function called.\n"; }
};