diff options
Diffstat (limited to 'shared/loki/Visitor.h')
-rw-r--r-- | shared/loki/Visitor.h | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/shared/loki/Visitor.h b/shared/loki/Visitor.h new file mode 100644 index 00000000..4425a9fa --- /dev/null +++ b/shared/loki/Visitor.h @@ -0,0 +1,355 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_VISITOR_INC_ +#define LOKI_VISITOR_INC_ + +// $Id: Visitor.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +/// \defgroup VisitorGroup Visitor + +#include "Typelist.h" +#include "HierarchyGenerators.h" + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class BaseVisitor +/// +/// \ingroup VisitorGroup +/// The base class of any Acyclic Visitor +//////////////////////////////////////////////////////////////////////////////// + + class BaseVisitor + { + public: + virtual ~BaseVisitor() {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class Visitor +/// +/// \ingroup VisitorGroup +/// The building block of Acyclic Visitor +/// +/// \par Usage +/// +/// Defining the visitable class: +/// +/// \code +/// class RasterBitmap : public BaseVisitable<> +/// { +/// public: +/// LOKI_DEFINE_VISITABLE() +/// }; +/// \endcode +/// +/// Way 1 to define a visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<RasterBitmap>, +/// public Visitor<Paragraph> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// Way 2 to define the visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<LOKI_TYPELIST_2(RasterBitmap, Paragraph)> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// Way 3 to define the visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<Seq<RasterBitmap, Paragraph>::Type> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// \par Using const visit functions: +/// +/// Defining the visitable class (true for const): +/// +/// \code +/// class RasterBitmap : public BaseVisitable<void, DefaultCatchAll, true> +/// { +/// public: +/// LOKI_DEFINE_CONST_VISITABLE() +/// }; +/// \endcode +/// +/// Defining the visitor which only calls const member functions: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<RasterBitmap, void, true>, +/// { +/// public: +/// void Visit(const RasterBitmap&); // visit a RasterBitmap by a const member function +/// }; +/// \endcode +/// +/// \par Example: +/// +/// test/Visitor/main.cpp +//////////////////////////////////////////////////////////////////////////////// + + template <class T, typename R = void, bool ConstVisit = false> + class Visitor; + + template <class T, typename R> + class Visitor<T, R, false> + { + public: + typedef R ReturnType; + typedef T ParamType; + virtual ~Visitor() {} + virtual ReturnType Visit(ParamType&) = 0; + }; + + template <class T, typename R> + class Visitor<T, R, true> + { + public: + typedef R ReturnType; + typedef const T ParamType; + virtual ~Visitor() {} + virtual ReturnType Visit(ParamType&) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Visitor (specialization) +// This specialization is not present in the book. It makes it easier to define +// Visitors for multiple types in a shot by using a typelist. Example: +// +// class SomeVisitor : +// public BaseVisitor // required +// public Visitor<LOKI_TYPELIST_2(RasterBitmap, Paragraph)> +// { +// public: +// void Visit(RasterBitmap&); // visit a RasterBitmap +// void Visit(Paragraph &); // visit a Paragraph +// }; +//////////////////////////////////////////////////////////////////////////////// + + template <class Head, class Tail, typename R> + class Visitor<Typelist<Head, Tail>, R, false> + : public Visitor<Head, R, false>, public Visitor<Tail, R, false> + { + public: + typedef R ReturnType; + // using Visitor<Head, R>::Visit; + // using Visitor<Tail, R>::Visit; + }; + + template <class Head, typename R> + class Visitor<Typelist<Head, NullType>, R, false> : public Visitor<Head, R, false> + { + public: + typedef R ReturnType; + using Visitor<Head, R, false>::Visit; + }; + + template <class Head, class Tail, typename R> + class Visitor<Typelist<Head, Tail>, R, true> + : public Visitor<Head, R, true>, public Visitor<Tail, R, true> + { + public: + typedef R ReturnType; + // using Visitor<Head, R>::Visit; + // using Visitor<Tail, R>::Visit; + }; + + template <class Head, typename R> + class Visitor<Typelist<Head, NullType>, R, true> : public Visitor<Head, R, true> + { + public: + typedef R ReturnType; + using Visitor<Head, R, true>::Visit; + }; + + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitorImpl +// Implements non-strict visitation (you can implement only part of the Visit +// functions) +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, typename R = void> class BaseVisitorImpl; + + template <class Head, class Tail, typename R> + class BaseVisitorImpl<Typelist<Head, Tail>, R> + : public Visitor<Head, R> + , public BaseVisitorImpl<Tail, R> + { + public: + // using BaseVisitorImpl<Tail, R>::Visit; + + virtual R Visit(Head&) + { return R(); } + }; + + template <class Head, typename R> + class BaseVisitorImpl<Typelist<Head, NullType>, R> + : public Visitor<Head, R> + { + public: + virtual R Visit(Head&) + { return R(); } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitable +//////////////////////////////////////////////////////////////////////////////// + +template <typename R, typename Visited> +struct DefaultCatchAll +{ + static R OnUnknownVisitor(Visited&, BaseVisitor&) + { return R(); } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitable +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename R = void, + template <typename, class> class CatchAll = DefaultCatchAll, + bool ConstVisitable = false + > + class BaseVisitable; + + template<typename R,template <typename, class> class CatchAll> + class BaseVisitable<R, CatchAll, false> + { + public: + typedef R ReturnType; + virtual ~BaseVisitable() {} + virtual ReturnType Accept(BaseVisitor&) = 0; + + protected: // give access only to the hierarchy + template <class T> + static ReturnType AcceptImpl(T& visited, BaseVisitor& guest) + { + // Apply the Acyclic Visitor + if (Visitor<T,R>* p = dynamic_cast<Visitor<T,R>*>(&guest)) + { + return p->Visit(visited); + } + return CatchAll<R, T>::OnUnknownVisitor(visited, guest); + } + }; + + template<typename R,template <typename, class> class CatchAll> + class BaseVisitable<R, CatchAll, true> + { + public: + typedef R ReturnType; + virtual ~BaseVisitable() {} + virtual ReturnType Accept(BaseVisitor&) const = 0; + + protected: // give access only to the hierarchy + template <class T> + static ReturnType AcceptImpl(const T& visited, BaseVisitor& guest) + { + // Apply the Acyclic Visitor + if (Visitor<T,R,true>* p = dynamic_cast<Visitor<T,R,true>*>(&guest)) + { + return p->Visit(visited); + } + return CatchAll<R, T>::OnUnknownVisitor(const_cast<T&>(visited), guest); + } + }; + + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_VISITABLE() +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable +/// (in addition to deriving it from BaseVisitable<R>) +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_VISITABLE() \ + virtual ReturnType Accept(::Loki::BaseVisitor& guest) \ + { return AcceptImpl(*this, guest); } + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_CONST_VISITABLE() +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable by const member +/// functions (in addition to deriving it from BaseVisitable<R>) +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_CONST_VISITABLE() \ + virtual ReturnType Accept(::Loki::BaseVisitor& guest) const \ + { return AcceptImpl(*this, guest); } + +//////////////////////////////////////////////////////////////////////////////// +/// \class CyclicVisitor +/// +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable (in addition to +/// deriving it from BaseVisitable<R> +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, class TList> + class CyclicVisitor : public Visitor<TList, R> + { + public: + typedef R ReturnType; + // using Visitor<TList, R>::Visit; + + template <class Visited> + ReturnType GenericVisit(Visited& host) + { + Visitor<Visited, ReturnType>& subObj = *this; + return subObj.Visit(host); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable by a cyclic visitor +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) \ + virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \ + { return guest.GenericVisit(*this); } + +} // namespace Loki + + + +#endif // end file guardian + |