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.
222 lines
8.3 KiB
C++
222 lines
8.3 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkDoubleDispatcher.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 vtkDoubleDispatcher
|
|
* @brief Dispatch to functor based on two pointer types.
|
|
*
|
|
* vtkDoubleDispatcher is a class that allows calling a functor based
|
|
* on the derived types of two pointers. 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 when
|
|
* you want to know multiple parameter types, or need to call a specialized implementation
|
|
* for a subset
|
|
*
|
|
* 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,typename U>
|
|
* void operator()(T& t,U& u) const
|
|
* {
|
|
*
|
|
* }
|
|
* };
|
|
*
|
|
* Here is an example of using the double dispatcher.
|
|
* \code
|
|
* vtkDoubleDispatcher<vtkObject,vtkObject,vtkPoints*> dispatcher;
|
|
* dispatcher.Add<vtkPoints,vtkDoubleArray>(makePointsWrapperFunctor());
|
|
* dispatcher.Add<vtkPoints,vtkPoints>(straightCopyFunctor());
|
|
* dispatcher.Go(ptr1,ptr2); //this will return a vtkPoints pointer
|
|
* \endcode
|
|
*
|
|
*
|
|
* @sa
|
|
* vtkDispatcher
|
|
*/
|
|
|
|
#ifndef vtkDoubleDispatcher_h
|
|
#define vtkDoubleDispatcher_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
|
|
|
|
template <class BaseLhs, class BaseRhs = BaseLhs, typename ReturnType = void,
|
|
template <class, class> class CastingPolicy = vtkDispatcherCommon::vtkCaster>
|
|
class vtkDoubleDispatcher
|
|
{
|
|
public:
|
|
/**
|
|
* Add in a functor that is mapped to the combination of the
|
|
* two template parameters passed in. When instances of the two parameters
|
|
* are passed in on the Go method we will call the functor and pass along
|
|
* the given parameters.
|
|
* Note: This copies the functor so pass stateful functors by pointer.
|
|
|
|
* \code
|
|
* vtkDoubleDispatcher<vtkDataModel,vtkCell> dispatcher;
|
|
* dispatcher.Add<vtkImageData,vtkVoxel>(exampleFunctor());
|
|
* dispatcher.Add<vtkImageData,vtkVoxel>(&exampleFunctorWithState);
|
|
* \endcode
|
|
*/
|
|
template <class SomeLhs, class SomeRhs, class Functor>
|
|
void Add(Functor fun)
|
|
{
|
|
VTK_LEGACY_BODY(vtkDoubleDispatcher, "VTK 9.0");
|
|
this->AddInternal<SomeLhs, SomeRhs>(fun, 1);
|
|
}
|
|
|
|
/**
|
|
* Remove a functor that is bound to the given parameter types. Will
|
|
* return true if we did remove a functor.
|
|
*/
|
|
template <class SomeLhs, class SomeRhs>
|
|
bool Remove()
|
|
{
|
|
return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
|
|
}
|
|
|
|
/**
|
|
* Given two pointers of objects that derive from the BaseLhs and BaseRhs
|
|
* we find the matching functor that was added, and call it passing along
|
|
* the given parameters. It should be noted that the functor will be called
|
|
* with the parameters being the derived type that Functor was registered with.
|
|
|
|
* Note: This will only find exact matches. So if you add functor to find
|
|
* vtkDataArray,vtkDataArray, it will not be called if passed with
|
|
* vtkDoubleArray,vtkDoubleArray.
|
|
|
|
* \code
|
|
|
|
* vtkDoubleDispatcher<vtkDataArray,vtkDataArray> dispatcher;
|
|
* dispatcher.Add(vtkFloatArray,vtkFloatArray>(floatFunctor())
|
|
* dispatcher.Add(vtkFloatArray,vtkDoubleArray>(mixedTypeFunctor())
|
|
* dispatcher.Go( dataArray1, dataArray2);
|
|
* \endcode
|
|
*/
|
|
ReturnType Go(BaseLhs* lhs, BaseRhs* rhs);
|
|
|
|
protected:
|
|
typedef vtkDispatcherCommon::TypeInfo TypeInfo;
|
|
typedef vtkDoubleDispatcherPrivate::Functor<ReturnType, BaseLhs, BaseRhs> MappedType;
|
|
|
|
void DoAddFunctor(TypeInfo lhs, TypeInfo rhs, MappedType fun);
|
|
bool DoRemove(TypeInfo lhs, TypeInfo rhs);
|
|
|
|
typedef std::pair<TypeInfo, TypeInfo> KeyType;
|
|
typedef std::map<KeyType, MappedType> MapType;
|
|
MapType FunctorMap;
|
|
|
|
private:
|
|
template <class SomeLhs, class SomeRhs, class Functor>
|
|
void AddInternal(const Functor& fun, long);
|
|
template <class SomeLhs, class SomeRhs, class Functor>
|
|
void AddInternal(Functor* fun, int);
|
|
};
|
|
|
|
// We are making all these method non-inline to reduce compile time overhead
|
|
//----------------------------------------------------------------------------
|
|
template <class BaseLhs, class BaseRhs, typename ReturnType,
|
|
template <class, class> class CastingPolicy>
|
|
template <class SomeLhs, class SomeRhs, class Functor>
|
|
void vtkDoubleDispatcher<BaseLhs, BaseRhs, ReturnType, CastingPolicy>::AddInternal(
|
|
const Functor& fun, long)
|
|
{
|
|
typedef vtkDoubleDispatcherPrivate::FunctorDoubleDispatcherHelper<BaseLhs, BaseRhs, SomeLhs,
|
|
SomeRhs, ReturnType, CastingPolicy<SomeLhs, BaseLhs>, CastingPolicy<SomeRhs, BaseRhs>, Functor>
|
|
Adapter;
|
|
Adapter ada(fun);
|
|
MappedType mt(ada);
|
|
DoAddFunctor(typeid(SomeLhs), typeid(SomeRhs), mt);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class BaseLhs, class BaseRhs, typename ReturnType,
|
|
template <class, class> class CastingPolicy>
|
|
template <class SomeLhs, class SomeRhs, class Functor>
|
|
void vtkDoubleDispatcher<BaseLhs, BaseRhs, ReturnType, CastingPolicy>::AddInternal(
|
|
Functor* fun, int)
|
|
{
|
|
typedef vtkDoubleDispatcherPrivate::FunctorRefDispatcherHelper<BaseLhs, BaseRhs, SomeLhs, SomeRhs,
|
|
ReturnType, CastingPolicy<SomeLhs, BaseLhs>, CastingPolicy<SomeRhs, BaseRhs>, Functor>
|
|
Adapter;
|
|
Adapter ada(*fun);
|
|
MappedType mt(ada);
|
|
DoAddFunctor(typeid(SomeLhs), typeid(SomeRhs), mt);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class BaseLhs, class BaseRhs, typename ReturnType,
|
|
template <class, class> class CastingPolicy>
|
|
void vtkDoubleDispatcher<BaseLhs, BaseRhs, ReturnType, CastingPolicy>::DoAddFunctor(
|
|
TypeInfo lhs, TypeInfo rhs, MappedType fun)
|
|
{
|
|
FunctorMap[KeyType(lhs, rhs)] = fun;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class BaseLhs, class BaseRhs, typename ReturnType,
|
|
template <class, class> class CastingPolicy>
|
|
bool vtkDoubleDispatcher<BaseLhs, BaseRhs, ReturnType, CastingPolicy>::DoRemove(
|
|
TypeInfo lhs, TypeInfo rhs)
|
|
{
|
|
return FunctorMap.erase(KeyType(lhs, rhs)) == 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class BaseLhs, class BaseRhs, typename ReturnType,
|
|
template <class, class> class CastingPolicy>
|
|
ReturnType vtkDoubleDispatcher<BaseLhs, BaseRhs, ReturnType, CastingPolicy>::Go(
|
|
BaseLhs* lhs, BaseRhs* rhs)
|
|
{
|
|
typename MapType::key_type k(typeid(*lhs), typeid(*rhs));
|
|
typename MapType::iterator i = FunctorMap.find(k);
|
|
if (i == FunctorMap.end())
|
|
{
|
|
// we don't want to throw exceptions so we have two options.
|
|
// we can return the default, or make a lightweight struct for return value
|
|
return ReturnType();
|
|
}
|
|
return (i->second)(*lhs, *rhs);
|
|
}
|
|
|
|
#endif // legacy
|
|
#endif // vtkDoubleDispatcher_h
|
|
// VTK-HeaderTest-Exclude: vtkDoubleDispatcher.h
|