WIP desperately trying to work out a really usable visitor implementation

This commit is contained in:
Fischlurch 2007-12-22 08:45:09 +01:00
parent 5703451ee0
commit 46b200809e
10 changed files with 341 additions and 10 deletions

View file

@ -25,7 +25,8 @@ ABBREVIATE_BRIEF = "The $name class" \
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = ../../src/
STRIP_FROM_PATH = ../../src/ \
../../tests/
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
@ -178,7 +179,7 @@ TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex

View file

@ -80,7 +80,8 @@ namespace cinelerra
{
static RET onUnknown (TAR& target,TOOL& tool)
{
tool.treat (target);
//tool.treat (target);
tool.catchy (target);
}
};

View file

@ -32,12 +32,12 @@ namespace mobject
* contain overloaded fuctions for treating
* different Buildable subclasses specifically
*/
Buildable::ReturnType
/* Buildable::ReturnType
Buildable::apply (builder::BuilderTool& tool)
{
return dispatchOp (*this, tool);
}
*/
} // namespace mobject

View file

@ -57,8 +57,24 @@ namespace mobject
* different Buildable subclasses specifically and the concrete Buildables
* will define explicitly to be specifically visitable.
*/
virtual void apply (builder::BuilderTool&);
// 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

@ -41,7 +41,7 @@ namespace mobject
* Used according to the visitor pattern: each Tool contains
* the concrete implementation for one task to be done to the various MObject classes
*/
class BuilderTool : public Tool
class BuilderTool : public Tool //////////////////////////auf die Zielklasse templaten und Placement festmachen???
{
protected:
typedef mobject::Buildable Buildable;
@ -49,8 +49,16 @@ namespace mobject
public:
/** This operation is to be overloaded for specific MObject subclasses to be treated.
*/
virtual void treat (Buildable& mElement) = 0;
//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);
}
} // namespace mobject::builder

View file

@ -102,6 +102,9 @@ namespace mobject
}
virtual ~Placement() {};
/** */ /////////////////////////////////////////////////////////////TODO: totmachen?
// DEFINE_PROCESSABLE_BY (builder::BuilderTool);
/** interface for defining the kind of placement
@ -150,6 +153,7 @@ namespace mobject
(shared_ptr<MObject>::operator-> ()); \
} \
};
// DEFINE_PROCESSABLE_BY (builder::BuilderTool);
/* a note to the maintainer: please don't add any fields or methods to
* these subclasses which aren't also present in Placement<MObject>!

View file

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

View file

@ -0,0 +1,296 @@
/*
VisitingTool(Concept) - working out our own Visitor library implementation
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.
* *****************************************************/
/** @file visitingtoolconept.cpp
** While laying the foundations for EDL and Builder, Ichthyo came accross
** the necessity to create a custom implementation of the Visitor Pattern
** optimally suited for Cinelerra's needs. This implementation file was
** used for the draft and is self-contained. The final solution was then
** extracted as library implementation to visitor.hpp
**
** Basic considerations
** <ul><li>cyclic dependencies should be avoided or at least restricted
** to some library related place</li>
** <li>Visitor is about <i>double dispatch</i>, thus we can't avoid
** using some table lookup implementation, and we can't avoid using
** some of the cooperating classes vtables. Besides that, the
** implementation should not be too wastefull</li>
** <li>individual Visiting Tool implementation classes should be able
** to opt in or opt out on implementing function treating some of
** the visitable subclasses.</li>
** <li>there should be a safe fallback mechanism backed by the
** visitable object's hierarchy relations. If some new class declares
** to be visitable, existing Visiting Tools not treating this new
** visitable type should fall back to the next best match in the
** hierarchy, not to some deaf base class</li>
** </ul>
**
** @see visitor.hpp the final lib implementation
** @see visitingtooltest.cpp test cases using our lib implementation
** @see BuilderTool one especially important instantiiation
**
*/
#include "common/test/run.hpp"
//#include "common/factory.hpp"
//#include "common/util.hpp"
#include <boost/format.hpp>
#include <iostream>
using boost::format;
using std::string;
using std::cout;
namespace cinelerra
{
namespace visitor
{
// ================================================================== Library ====
/** Marker interface "visiting tool".
*/
template<typename RET>
class Tool
{
public:
typedef RET ReturnType;
virtual ~Tool () { }; ///< use RTTI for all visiting tools
};
template<class TOOL>
class ToolRegistry
{
};
template<class TOOLTYPE>
class ToolReg
{
//getTag()
void regCombination(Invoker ii)
{
////OOOOhhh, da hab ich wiiiieder das gleiche Problem: wie krieg ich die Typinfo TAR????
}
};
// alternativ ("halb-zyklisch")
//
template<class TAR, class TOOLTYPE>
class ReToo
{
ReToo()
{
//expliziten Eintrag machen für TAR und TOOLTYPE
}
};
template<class TAR>
class DisTab : ReToo<TAR, ToolTyp1>,
ReToo<TAR, ToolTyp2>
{
};
// der konkrete Dispatch instantiiert diese Klasse
// Voraussetzung: alle Tools hängen nur per Name von ihren Targets ab
template<class TAR, class TOOL>
class Dispatcher
{
// Ctor: for_each(ToolRegistry, call regCombination() )
public:
static TOOL::ReturnType call (TOOL& tool, TAR& target)
{
}
};
/** Marker interface "visitable object".
*/
template
< class TOOL = Tool<void>
>
class Visitable
{
public:
/** to be defined by the DEFINE_PROCESSABLE_BY macro
* in all classes wanting to be treated by some tool */
typedef TOOL::ReturnType ReturnType;
virtual ReturnType apply (TOOL&) = 0;
protected:
virtual ~Visitable () { };
/** @internal used by the DEFINE_VISITABLE macro.
* Dispatches to the actual operation on the
* "visiting tool" (acyclic visitor implementation)
*/
template <class TAR>
static ReturnType dispatchOp(TAR& target, TOOL& tool)
{
return Dispatcher<TAR,TOOL>::call (tool, target);
}
};
/** mark a Visitable subclass as actually treatable
* by some "visiting tool". Defines the apply-function,
* which is the actual access point to invoke the visiting
*/
#define DEFINE_PROCESSABLE_BY(TOOL) \
virtual ReturnType apply (TOOL& tool) \
{ return dispatchOp (*this, tool); }
// ================================================================== Library ====
namespace test
{
class HomoSapiens : public Visitable<>
{
public:
DEFINE_PROCESSABLE_BY (Tool);
};
class Boss : public HomoSapiens
{
public:
DEFINE_PROCESSABLE_BY (Tool);
};
class BigBoss : public Boss
{
public:
DEFINE_PROCESSABLE_BY (Tool);
};
class Leader : public Boss
{
};
class Visionary : public Leader
{
};
class VerboseVisitor
: public Tool
{
protected:
void talk_to (string guy)
{
cout << format ("Hello %s, nice to meet you...\n") % guy;
}
};
class Babbler
: public VerboseVisitor,
public Applicable<Boss>,
public Applicable<BigBoss>
{
public:
void treat (Boss&) { talk_to("Boss"); }
void treat (BigBoss&) { talk_to("big Boss"); }
};
/*************************************************************************
* @test build and run some common cases for developing and verifying
* ichthyo's implementation concept for the 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>
*/
class VisitingTool_concept : public Test
{
virtual void run(Arg arg)
{
known_visitor_known_class();
visitor_not_visiting_some_class();
}
void known_visitor_known_class()
{
Boss x1;
BigBoss x2;
// masquerade as HomoSapiens...
HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2);
cout << "=== Babbler meets Boss and BigBoss ===\n";
Babbler bab;
Visitor& vista (bab);
homo1.apply (vista);
homo2.apply (vista);
}
void visitor_not_visiting_some_class()
{
HomoSapiens x1;
Visionary x2;
HomoSapiens& homo1 (x1);
HomoSapiens& homo2 (x2);
cout << "=== Babbler meets HomoSapiens and Visionary ===\n";
Babbler bab;
Visitor& vista (bab);
homo1.apply (vista); // doesn't visit HomoSapiens
homo2.apply (vista); // treats Visionary as Boss
}
};
/** Register this test class... */
LAUNCHER (VisitingTool_concept, "unit common");
} // namespace test
} // namespace visitor
} // namespace cinelerra

View file

@ -91,6 +91,7 @@ namespace cinelerra
public:
void treat (BigBoss&) { talk_to("big Boss"); }
void treat (HomoSapiens&) { talk_to("we-do-everything-for-YOU"); } ///< catch-all function
void catchy(HomoSapiens&) {}
};

View file

@ -76,10 +76,12 @@ namespace mobject
};
class TestTool : public BuilderTool,
public Applicable<Clip>
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;