/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2005,2006 INRIA * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #ifndef CALLBACK_H #define CALLBACK_H #include "ptr.h" #include "fatal-error.h" #include "empty.h" #include "type-traits.h" namespace ns3 { /*** * \internal * This code was originally written based on the techniques * described in http://www.codeproject.com/cpp/TTLFunction.asp * It was subsequently rewritten to follow the architecture * outlined in "Modern C++ Design" by Andrei Alexandrescu in * chapter 5, "Generalized Functors". * * This code uses: * - default template parameters to saves users from having to * specify empty parameters when the number of parameters * is smaller than the maximum supported number * - the pimpl idiom: the Callback class is passed around by * value and delegates the crux of the work to its pimpl * pointer. * - two pimpl implementations which derive from CallbackImpl * FunctorCallbackImpl can be used with any functor-type * while MemPtrCallbackImpl can be used with pointers to * member functions. * - a reference list implementation to implement the Callback's * value semantics. * * This code most notably departs from the alexandrescu * implementation in that it does not use type lists to specify * and pass around the types of the callback arguments. * Of course, it also does not use copy-destruction semantics * and relies on a reference list rather than autoPtr to hold * the pointer. */ template struct CallbackTraits; template struct CallbackTraits { static T & GetReference (T * const p) { return *p; } }; class CallbackImplBase { public: CallbackImplBase () : m_count (1) {} virtual ~CallbackImplBase () {} void Ref (void) { m_count++; } void Unref (void) { m_count--; if (m_count == 0) { delete this; } } virtual bool IsEqual (CallbackImplBase const *other) const = 0; private: uint32_t m_count; }; // declare the CallbackImpl class template class CallbackImpl; // define CallbackImpl for 0 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (void) = 0; }; // define CallbackImpl for 1 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1) = 0; }; // define CallbackImpl for 2 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1, T2) = 0; }; // define CallbackImpl for 3 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1, T2, T3) = 0; }; // define CallbackImpl for 4 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1, T2, T3, T4) = 0; }; // define CallbackImpl for 5 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1, T2, T3, T4, T5) = 0; }; // define CallbackImpl for 6 params template class CallbackImpl : public CallbackImplBase { public: virtual ~CallbackImpl () {} virtual R operator() (T1, T2, T3, T4, T5, T6) = 0; }; // an impl for Functors: template class FunctorCallbackImpl : public CallbackImpl { public: FunctorCallbackImpl (T const &functor) : m_functor (functor) {} virtual ~FunctorCallbackImpl () {} R operator() (void) { return m_functor (); } R operator() (T1 a1) { return m_functor (a1); } R operator() (T1 a1,T2 a2) { return m_functor (a1,a2); } R operator() (T1 a1,T2 a2,T3 a3) { return m_functor (a1,a2,a3); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { return m_functor (a1,a2,a3,a4); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { return m_functor (a1,a2,a3,a4,a5); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) { return m_functor (a1,a2,a3,a4,a5,a6); } virtual bool IsEqual (CallbackImplBase const *other) const { FunctorCallbackImpl const *otherDerived = dynamic_cast const *> (other); if (otherDerived == 0) { return false; } else if (otherDerived->m_functor != m_functor) { return false; } return true; } private: T m_functor; }; // an impl for pointer to member functions template class MemPtrCallbackImpl : public CallbackImpl { public: MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr) : m_objPtr (objPtr), m_memPtr (mem_ptr) {} virtual ~MemPtrCallbackImpl () {} R operator() (void) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (); } R operator() (T1 a1) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1); } R operator() (T1 a1,T2 a2) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1, a2); } R operator() (T1 a1,T2 a2,T3 a3) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) { return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5, a6); } virtual bool IsEqual (CallbackImplBase const *other) const { MemPtrCallbackImpl const *otherDerived = dynamic_cast const *> (other); if (otherDerived == 0) { return false; } else if (otherDerived->m_objPtr != m_objPtr || otherDerived->m_memPtr != m_memPtr) { return false; } return true; } private: OBJ_PTR const m_objPtr; MEM_PTR m_memPtr; }; class CallbackBase { public: virtual ~CallbackBase () {} virtual CallbackImplBase *PeekImpl (void) const = 0; virtual Ptr GetImpl (void) const = 0; }; /** * \brief Callback template class * * This class template implements the Functor Design Pattern. * It is used to declare the type of a Callback: * - the first non-optional template argument represents * the return type of the callback. * - the second optional template argument represents * the type of the first argument to the callback. * - the third optional template argument represents * the type of the second argument to the callback. * - the fourth optional template argument represents * the type of the third argument to the callback. * - the fifth optional template argument represents * the type of the fourth argument to the callback. * - the sixth optional template argument represents * the type of the fifth argument to the callback. * * Callback instances are built with the \ref MakeCallback * template functions. Callback instances have POD semantics: * the memory they allocate is managed automatically, without * user intervention which allows you to pass around Callback * instances by value. * * Sample code which shows how to use this class template * as well as the function templates \ref MakeCallback : * \include samples/main-callback.cc */ template class Callback : public CallbackBase { public: // There are two dummy args below to ensure that this constructor is // always properly disambiguited by the c++ compiler template Callback (FUNCTOR const &functor, bool, bool) : m_impl (Create > (functor)) {} template Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr) : m_impl (Create > (objPtr, mem_ptr)) {} Callback (Ptr > const &impl) : m_impl (impl) {} bool IsNull (void) const { return (PeekImpl () == 0)?true:false; } void Nullify (void) { m_impl = 0; } Callback () : m_impl () {} R operator() (void) const { return (*(PeekImpl ())) (); } R operator() (T1 a1) const { return (*(PeekImpl ())) (a1); } R operator() (T1 a1, T2 a2) const { return (*(PeekImpl ())) (a1,a2); } R operator() (T1 a1, T2 a2, T3 a3) const { return (*(PeekImpl ())) (a1,a2,a3); } R operator() (T1 a1, T2 a2, T3 a3, T4 a4) const { return (*(PeekImpl ())) (a1,a2,a3,a4); } R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const { return (*(PeekImpl ())) (a1,a2,a3,a4,a5); } R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const { return (*(PeekImpl ())) (a1,a2,a3,a4,a5,a6); } bool IsEqual (CallbackBase const &other) const { return PeekImpl ()->IsEqual (other.PeekImpl ()); } bool CheckType (CallbackBase const& other) const { CallbackImplBase *otherBase = other.PeekImpl (); if (dynamic_cast *> (otherBase) != 0) { return true; } else { return false; } } void Assign (CallbackBase const &other) { if (!CheckType (other)) { NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")" " got=" << typeid (other).name () << ", expected=" << typeid (*this).name ()); } const Callback *goodType = static_cast *> (&other); *this = *goodType; } void Assign (Ptr other) { CallbackImpl *impl = dynamic_cast *> (PeekPointer (other)); if (other == 0) { NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")" " got=" << typeid (other).name () << ", expected=" << typeid (*impl).name ()); } *this = Callback (impl); } virtual PtrGetImpl (void) const { return m_impl; } private: virtual CallbackImpl *PeekImpl (void) const { return PeekPointer (m_impl); } Ptr > m_impl; }; /** * \defgroup MakeCallback MakeCallback * */ /** * \ingroup MakeCallback * \param memPtr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes no arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*memPtr) (void), OBJ objPtr) { return Callback (objPtr, memPtr); } template Callback MakeCallback (R (T::*mem_ptr) () const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes one argument * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes two arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes three arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes four arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes five arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param mem_ptr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes five arguments * and potentially return a value. */ template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6), OBJ objPtr) { return Callback (objPtr, mem_ptr); } template Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6) const, OBJ objPtr) { return Callback (objPtr, mem_ptr); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes no arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) ()) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes one argument * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes two arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1,T2)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes three arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1,T2,T3)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes four arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1,T2,T3,T4)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes five arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \param fnPtr function pointer * \return a wrapper Callback * Build Callbacks for functions which takes five arguments * and potentially return a value. */ template Callback MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5,T6)) { return Callback (fnPtr, true, true); } /** * \ingroup MakeCallback * \return a wrapper Callback * Build a null callback which takes no arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes one argument * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes two arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes three arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes four arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes five arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /** * \ingroup MakeCallback * \overload Callback MakeNullCallback (void) * \return a wrapper Callback * Build a null callback which takes five arguments * and potentially return a value. */ template Callback MakeNullCallback (void) { return Callback (); } /* * The following is experimental code. It works but we have * not yet determined whether or not it is really useful and whether * or not we really want to use it. */ // an impl for Bound Functors: template class BoundFunctorCallbackImpl : public CallbackImpl { public: template BoundFunctorCallbackImpl (FUNCTOR functor, ARG a) : m_functor (functor), m_a (a) {} virtual ~BoundFunctorCallbackImpl () {} R operator() (void) { return m_functor (m_a); } R operator() (T1 a1) { return m_functor (m_a,a1); } R operator() (T1 a1,T2 a2) { return m_functor (m_a,a1,a2); } R operator() (T1 a1,T2 a2,T3 a3) { return m_functor (m_a,a1,a2,a3); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { return m_functor (m_a,a1,a2,a3,a4); } R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { return m_functor (m_a,a1,a2,a3,a4,a5); } virtual bool IsEqual (CallbackImplBase const *other) const { BoundFunctorCallbackImpl const *otherDerived = dynamic_cast const *> (other); if (otherDerived == 0) { return false; } else if (otherDerived->m_functor != m_functor || otherDerived->m_a != m_a) { return false; } return true; } private: T m_functor; typename TypeTraits::ReferencedType m_a; }; template Callback MakeBoundCallback (R (*fnPtr) (TX), ARG a) { Ptr > impl = Create >(fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1), ARG a) { Ptr > impl = Create > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2), ARG a) { Ptr > impl = Create > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3), ARG a) { Ptr > impl = Create > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), ARG a) { Ptr > impl = Create > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), ARG a) { Ptr > impl = Create > (fnPtr, a); return Callback (impl); } }; // namespace ns3 #endif /* CALLBACK_H */