You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
7.6 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkDispatcher.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
/**
* @class vtkDispatcher
* @brief Dispatch to functor based on a pointer type.
*
* vtkDispatcher is a class that allows calling a functor based
* on the derived types of a pointer. This form of dynamic dispatching
* allows the conversion of runtime polymorphism to a compile time polymorphism.
* For example it can be used as a replacement for the vtkTemplateMacro, with
* bonus of being easier to understand
*
* Note: By default the return type is void.
*
* The functors that are passed around can contain state, and are allowed
* to be const or non const. If you are using a functor that does have state,
* make sure your copy constructor is correct.
*
* \code
* struct functor{
* template<typename T>
* void operator()(T& t) const
* {
*
* }
* };
*
* Here is an example of using the dispatcher.
* \code
* statefull functor;
* vtkDispatcher<vtkDataArray> dispatcher;
* dispatcher.Add<vtkCharArray>(&functor);
* dispatcher.Add<vtkDoubleArray>(&functor);
* dispatcher.Add<vtkIdTypeArray>(&functor);
* dispatcher.Add<vtkIntArray>(&functor);
* dispatcher.Add<vtkFloatArray>(&functor);
* dispatcher.Go(ptr1);
* \endcode
*
*
* @sa
* vtkDispatcher
*/
#ifndef vtkDispatcher_h
#define vtkDispatcher_h
#include "vtkConfigure.h"
#ifndef VTK_LEGACY_REMOVE
#include "vtkDispatcher_Private.h" //needed for Functor,CastingPolicy,TypeInfo
#include <map> //Required for the storage of template params to runtime params
////////////////////////////////////////////////////////////////////////////////
// class template FunctorDispatcher
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, typename ReturnType = void,
template <class, class> class CastingPolicy = vtkDispatcherCommon::vtkCaster>
class vtkDispatcher
{
public:
/**
* Add in a functor that is mapped to the template SomeLhs parameter.
* When instances of the parameter is passed in on the Go method we will call
* the functor and pass along the given parameter.
* Note: This copies the functor so pass stateful functors by pointer.
* \code
* vtkDispatcher<vtkDataModel> dispatcher;
* dispatcher.Add<vtkImageData>(exampleFunctor());
* dispatcher.Add<vtkImageData>(&exampleFunctorWithState);
* \endcode
*/
template <class SomeLhs, class Functor>
void Add(Functor fun)
{
VTK_LEGACY_BODY(vtkDispatcher, "VTK 9.0");
this->AddInternal<SomeLhs>(fun, 1);
}
/**
* Remove a functor that is bound to the given parameter type. Will
* return true if we did remove a functor.
*/
template <class SomeLhs>
bool Remove()
{
return DoRemove(typeid(SomeLhs));
}
/**
* Given a pointer to an object that derives from the BaseLhs
* we find the matching functor that was added, and call it passing along
* the given parameter. It should be noted that the functor will be called
* with the parameter being the derived type that Functor was registered with.
* Note: This will only find exact matches. So if you add functor to find
* vtkDataArray, it will not be called if passed with a vtkDoubleArray.
* \code
* vtkDispatcher<vtkDataArray> dispatcher;
* dispatcher.Add(vtkFloatArray>(floatFunctor())
* dispatcher.Add(vtkDoubleArray>(doubleFunctor())
* dispatcher.Go(dataArray1);
* dispatcher.Go(dataArray2);
* \endcode
*/
ReturnType Go(BaseLhs* lhs);
protected:
typedef vtkDispatcherCommon::TypeInfo TypeInfo;
typedef vtkDispatcherPrivate::Functor<ReturnType, BaseLhs> MappedType;
void DoAddFunctor(TypeInfo lhs, MappedType fun);
bool DoRemove(TypeInfo lhs);
typedef std::map<TypeInfo, MappedType> MapType;
MapType FunctorMap;
private:
template <class SomeLhs, class Functor>
void AddInternal(Functor const& fun, long);
template <class SomeLhs, class Functor>
void AddInternal(Functor* fun, int);
};
// We are making all these method non-inline to reduce compile time overhead
//----------------------------------------------------------------------------
template <class BaseLhs, typename ReturnType, template <class, class> class CastingPolicy>
template <class SomeLhs, class Functor>
void vtkDispatcher<BaseLhs, ReturnType, CastingPolicy>::AddInternal(const Functor& fun, long)
{
typedef vtkDispatcherPrivate::FunctorDispatcherHelper<BaseLhs, SomeLhs, ReturnType,
CastingPolicy<SomeLhs, BaseLhs>, Functor>
Adapter;
Adapter ada(fun);
MappedType mt(ada);
DoAddFunctor(typeid(SomeLhs), mt);
}
//----------------------------------------------------------------------------
template <class BaseLhs, typename ReturnType, template <class, class> class CastingPolicy>
template <class SomeLhs, class Functor>
void vtkDispatcher<BaseLhs, ReturnType, CastingPolicy>::AddInternal(Functor* fun, int)
{
typedef vtkDispatcherPrivate::FunctorRefDispatcherHelper<BaseLhs, SomeLhs, ReturnType,
CastingPolicy<SomeLhs, BaseLhs>, Functor>
Adapter;
Adapter ada(*fun);
MappedType mt(ada);
DoAddFunctor(typeid(SomeLhs), mt);
}
//----------------------------------------------------------------------------
template <class BaseLhs, typename ReturnType, template <class, class> class CastingPolicy>
void vtkDispatcher<BaseLhs, ReturnType, CastingPolicy>::DoAddFunctor(TypeInfo lhs, MappedType fun)
{
FunctorMap[TypeInfo(lhs)] = fun;
}
//----------------------------------------------------------------------------
template <class BaseLhs, typename ReturnType, template <class, class> class CastingPolicy>
bool vtkDispatcher<BaseLhs, ReturnType, CastingPolicy>::DoRemove(TypeInfo lhs)
{
return FunctorMap.erase(TypeInfo(lhs)) == 1;
}
//----------------------------------------------------------------------------
template <class BaseLhs, typename ReturnType, template <class, class> class CastingPolicy>
ReturnType vtkDispatcher<BaseLhs, ReturnType, CastingPolicy>::Go(BaseLhs* lhs)
{
typename MapType::key_type k(typeid(*lhs));
typename MapType::iterator i = FunctorMap.find(k);
if (i == FunctorMap.end())
{
// we return a default type, currently i don't want exceptions thrown
return ReturnType();
}
return (i->second)(*lhs);
}
#endif // legacy
#endif // vtkDispatcher_h
// VTK-HeaderTest-Exclude: vtkDispatcher.h