/*========================================================================= 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 * void operator()(T& t,U& u) const * { * * } * }; * * Here is an example of using the double dispatcher. * \code * vtkDoubleDispatcher dispatcher; * dispatcher.Add(makePointsWrapperFunctor()); * dispatcher.Add(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 //Required for the storage of template params to runtime params template 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 dispatcher; * dispatcher.Add(exampleFunctor()); * dispatcher.Add(&exampleFunctorWithState); * \endcode */ template void Add(Functor fun) { VTK_LEGACY_BODY(vtkDoubleDispatcher, "VTK 9.0"); this->AddInternal(fun, 1); } /** * Remove a functor that is bound to the given parameter types. Will * return true if we did remove a functor. */ template 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 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 MappedType; void DoAddFunctor(TypeInfo lhs, TypeInfo rhs, MappedType fun); bool DoRemove(TypeInfo lhs, TypeInfo rhs); typedef std::pair KeyType; typedef std::map MapType; MapType FunctorMap; private: template void AddInternal(const Functor& fun, long); template void AddInternal(Functor* fun, int); }; // We are making all these method non-inline to reduce compile time overhead //---------------------------------------------------------------------------- template class CastingPolicy> template void vtkDoubleDispatcher::AddInternal( const Functor& fun, long) { typedef vtkDoubleDispatcherPrivate::FunctorDoubleDispatcherHelper, CastingPolicy, Functor> Adapter; Adapter ada(fun); MappedType mt(ada); DoAddFunctor(typeid(SomeLhs), typeid(SomeRhs), mt); } //---------------------------------------------------------------------------- template class CastingPolicy> template void vtkDoubleDispatcher::AddInternal( Functor* fun, int) { typedef vtkDoubleDispatcherPrivate::FunctorRefDispatcherHelper, CastingPolicy, Functor> Adapter; Adapter ada(*fun); MappedType mt(ada); DoAddFunctor(typeid(SomeLhs), typeid(SomeRhs), mt); } //---------------------------------------------------------------------------- template class CastingPolicy> void vtkDoubleDispatcher::DoAddFunctor( TypeInfo lhs, TypeInfo rhs, MappedType fun) { FunctorMap[KeyType(lhs, rhs)] = fun; } //---------------------------------------------------------------------------- template class CastingPolicy> bool vtkDoubleDispatcher::DoRemove( TypeInfo lhs, TypeInfo rhs) { return FunctorMap.erase(KeyType(lhs, rhs)) == 1; } //---------------------------------------------------------------------------- template class CastingPolicy> ReturnType vtkDoubleDispatcher::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