introcuded a catch-all hook when applying visiting tools to a hierarchy
This commit is contained in:
parent
4e99e8b66c
commit
78a4bf8e6b
5 changed files with 176 additions and 20 deletions
|
|
@ -34,6 +34,7 @@ This code is heavily inspired by
|
|||
#ifndef CINELERRA_VISITOR_H
|
||||
#define CINELERRA_VISITOR_H
|
||||
|
||||
#include "common/visitorpolicies.hpp"
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
|
|
@ -66,22 +67,29 @@ namespace cinelerra
|
|||
class Applicable
|
||||
{
|
||||
public:
|
||||
typedef RET ReturnType;
|
||||
virtual ~Applicable () { };
|
||||
|
||||
/** to be implemented by concrete tools
|
||||
* wanting to visit type TAR */
|
||||
virtual RET treat (TAR& visitable) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Marker interface / base class for all types
|
||||
* to be treated by a "visiting tool" or visitor.
|
||||
*/
|
||||
template <typename RET = void>
|
||||
template
|
||||
< typename RET = void,
|
||||
class TOOL = Tool,
|
||||
template<typename,class> class ERR = UseDefault
|
||||
>
|
||||
class Visitable
|
||||
{
|
||||
public:
|
||||
/** to be defined by the DEFINE_PROCESSABLE_BY macro
|
||||
* in all classes wanting to be treated by some tool */
|
||||
virtual RET apply (TOOL&) = 0;
|
||||
typedef RET ReturnType;
|
||||
|
||||
protected:
|
||||
|
|
@ -92,7 +100,7 @@ namespace cinelerra
|
|||
* "visiting tool" (acyclic visitor implementation)
|
||||
*/
|
||||
template <class TAR>
|
||||
static RET dispatchOp(TAR& target, Tool& tool)
|
||||
static RET dispatchOp(TAR& target, TOOL& tool)
|
||||
{
|
||||
if (Applicable<TAR,RET>* concreteTool
|
||||
= dynamic_cast<Applicable<TAR,RET>*> (&tool))
|
||||
|
|
@ -100,7 +108,7 @@ namespace cinelerra
|
|||
return concreteTool->treat (target);
|
||||
|
||||
else
|
||||
return ReturnType();
|
||||
return ERR<RET,TOOL>::onUnknown (target,tool);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -109,8 +117,8 @@ namespace cinelerra
|
|||
* by some "visiting tool". Defines the apply-function,
|
||||
* which is the actual access point to invoke the visiting
|
||||
*/
|
||||
#define DEFINE_VISITABLE() \
|
||||
virtual ReturnType apply (Tool& tool) \
|
||||
#define DEFINE_PROCESSABLE_BY(TOOL) \
|
||||
virtual ReturnType apply (TOOL& tool) \
|
||||
{ return dispatchOp (*this, tool); }
|
||||
|
||||
|
||||
|
|
|
|||
92
src/common/visitorpolicies.hpp
Normal file
92
src/common/visitorpolicies.hpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
VISITOR.hpp - Acyclic Visitor library
|
||||
|
||||
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.
|
||||
|
||||
====================================================================
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CINELERRA_VISITORPOLICIES_H
|
||||
#define CINELERRA_VISITORPOLICIES_H
|
||||
|
||||
#include "common/error.hpp"
|
||||
|
||||
|
||||
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<typename RET, class TOOL>
|
||||
struct UseDefault
|
||||
{
|
||||
template<class TAR>
|
||||
static RET onUnknown (TAR&, TOOL&)
|
||||
{
|
||||
return RET();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Policy to throw when encountering an unknown visiting tool
|
||||
*/
|
||||
template<typename RET, class TOOL>
|
||||
struct ThrowException
|
||||
{
|
||||
template<class TAR>
|
||||
static RET onUnknown (TAR&, TOOL&)
|
||||
{
|
||||
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
|
||||
*/
|
||||
template<typename RET, class TOOL>
|
||||
struct InvokeCatchAllFunction
|
||||
{
|
||||
template<class TAR>
|
||||
static RET onUnknown (TAR& target,TOOL& tool)
|
||||
{
|
||||
target.apply (static_cast<TOOL&> (tool));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace visitor
|
||||
|
||||
} // namespace cinelerra
|
||||
#endif
|
||||
|
|
@ -36,6 +36,7 @@ namespace mobject
|
|||
namespace builder{ class BuilderTool; }
|
||||
|
||||
using cinelerra::visitor::Visitable;
|
||||
using cinelerra::visitor::InvokeCatchAllFunction;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +44,11 @@ namespace mobject
|
|||
* 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<>
|
||||
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
|
||||
|
|
@ -52,7 +57,7 @@ namespace mobject
|
|||
* different Buildable subclasses specifically and the concrete Buildables
|
||||
* will define explicitly to be specifically visitable.
|
||||
*/
|
||||
virtual ReturnType apply (builder::BuilderTool&);
|
||||
virtual void apply (builder::BuilderTool&);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,10 @@ out: --> remaining=SingleTestID spam --eggs
|
|||
END
|
||||
|
||||
|
||||
PLANNED "VisitingTool_test" VisitingTool_test <<END
|
||||
TEST "VisitingTool_test" VisitingTool_test <<END
|
||||
out: Hello Boss, nice to meet you...
|
||||
out: Hello big Boss, nice to meet you...
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,22 +26,60 @@
|
|||
//#include "common/factory.hpp"
|
||||
//#include "common/util.hpp"
|
||||
|
||||
//#include <boost/format.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
//using boost::format;
|
||||
using boost::format;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace mobject
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace builder
|
||||
namespace visitor
|
||||
{
|
||||
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 VerboseVisitor
|
||||
: public Tool,
|
||||
public Applicable<Boss>,
|
||||
public Applicable<BigBoss>
|
||||
{
|
||||
void talk_to (string guy)
|
||||
{
|
||||
cout << format ("Hello %s, nice to meet you...\n") % guy;
|
||||
}
|
||||
public:
|
||||
void treat (Boss&) { talk_to("Boss"); }
|
||||
void treat (BigBoss&) { talk_to("big Boss"); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
|
|
@ -58,15 +96,25 @@ namespace mobject
|
|||
{
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
UNIMPLEMENTED ("testing the generic visitor pattern");
|
||||
known_visitor_known_class();
|
||||
visitor_not_visiting_some_class();
|
||||
visitor_treating_new_subclass();
|
||||
TODO ("implement the more complicated visitor test cases");
|
||||
//visitor_not_visiting_some_class();
|
||||
//visitor_treating_new_subclass();
|
||||
}
|
||||
|
||||
void known_visitor_known_class()
|
||||
{
|
||||
UNIMPLEMENTED ("testing the generic visitor pattern");
|
||||
HomoSapiens x1;
|
||||
Boss x2;
|
||||
BigBoss x3;
|
||||
|
||||
HomoSapiens& xx2 (x2);
|
||||
HomoSapiens& xx3 (x3);
|
||||
|
||||
VerboseVisitor wizzy;
|
||||
x1.apply (wizzy);
|
||||
xx2.apply (wizzy);
|
||||
xx3.apply (wizzy);
|
||||
}
|
||||
|
||||
void visitor_not_visiting_some_class()
|
||||
|
|
@ -88,6 +136,6 @@ namespace mobject
|
|||
|
||||
} // namespace test
|
||||
|
||||
} // namespace builder
|
||||
} // namespace visitor
|
||||
|
||||
} // namespace mobject
|
||||
} // namespace cinelerra
|
||||
|
|
|
|||
Loading…
Reference in a new issue