libqi-api  2.0.6.8
/home/opennao/work/master/sdk/libqi/qi/details/trackable.hxx
Go to the documentation of this file.
00001 #pragma once
00002 /*
00003  * Copyright (c) 2013 Aldebaran Robotics. All rights reserved.
00004  * Use of this source code is governed by a BSD-style license that can be
00005  * found in the COPYING file.
00006  */
00007 
00008 #ifndef _QI_DETAILS_TRACKABLE_HXX_
00009 #define _QI_DETAILS_TRACKABLE_HXX_
00010 
00011 #include <boost/function.hpp>
00012 #include <boost/bind.hpp>
00013 #include <boost/type_traits/is_base_of.hpp>
00014 #include <boost/type_traits/remove_pointer.hpp>
00015 #include <boost/weak_ptr.hpp>
00016 #include <boost/function_types/result_type.hpp>
00017 
00018 namespace qi
00019 {
00020   template<typename T>
00021   inline Trackable<T>::Trackable(T* ptr)
00022   : _wasDestroyed(false)
00023   {
00024     _ptr = boost::shared_ptr<T>(ptr, boost::bind(&Trackable::_destroyed, _1));
00025   }
00026 
00027   template<typename T>
00028   inline void Trackable<T>::destroy()
00029   {
00030     _ptr.reset();
00031     wait();
00032   }
00033 
00034   template<typename T>
00035   inline void Trackable<T>::wait()
00036   {
00037     boost::mutex::scoped_lock lock(_mutex);
00038     while (!_wasDestroyed)
00039     {
00040       _cond.wait(lock);
00041     }
00042   }
00043 
00044   template<typename T>
00045   inline void Trackable<T>::_destroyed()
00046   {
00047     // unblock
00048     boost::mutex::scoped_lock lock(_mutex);
00049     _wasDestroyed = true;
00050     _cond.notify_all();
00051   }
00052 
00053   template<typename T>
00054   inline Trackable<T>::~Trackable()
00055   {
00056     // We expect destroy() to have been called from parent destructor, so from
00057     // this thread.
00058     if (!_wasDestroyed)
00059     {
00060       qiLogError("qi.Trackable") << "Trackable destroyed without calling destroy()";
00061       // do it to mitigate the effect, but it's too late
00062       destroy();
00063     }
00064   }
00065 
00066   template<typename T>
00067   inline boost::shared_ptr<T> Trackable<T>::lock()
00068   {
00069     return _ptr;
00070   }
00071 
00072   template<typename T>
00073   inline boost::weak_ptr<T> Trackable<T>::weakPtr()
00074   {
00075     return boost::weak_ptr<T>(_ptr);
00076   }
00077 
00078   namespace detail
00079   {
00080     // Functor that locks a weak ptr and make a call if successful
00081     // Generalize on shared_ptr and weak_ptr types in case we ever have
00082     // other types with their semantics
00083     template<typename WT, typename ST, typename F>
00084     class LockAndCall
00085     {
00086     public:
00087       typedef typename boost::function_types::result_type<F>::type Result;
00088       LockAndCall(const WT& arg, boost::function<F> func, boost::function<void()> onFail)
00089       : _wptr(arg)
00090       , _f(func)
00091       , _onFail(onFail)
00092       {}
00093 
00094 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
00095      QI_GEN_MAYBE_TEMPLATE_OPEN(comma)                    \
00096      ATYPEDECL                                            \
00097      QI_GEN_MAYBE_TEMPLATE_CLOSE(comma)                   \
00098      Result operator()(ADECL) {                           \
00099        ST s = _wptr.lock();                               \
00100        if (s)                                             \
00101          return _f(AUSE);                                 \
00102        else                                               \
00103          if (_onFail)                                     \
00104            _onFail();                                     \
00105          else                                             \
00106            return Result();                               \
00107       }
00108       QI_GEN(genCall)
00109 #undef genCall
00110       WT _wptr;
00111       boost::function<F> _f;
00112       boost::function<void()> _onFail;
00113     };
00114 
00115     template<typename T, bool IS_TRACKABLE> struct BindTransform
00116     {
00117       typedef const T& type;
00118       static type transform(const T& arg)
00119       {
00120         return arg;
00121       }
00122       template<typename F>
00123       static boost::function<F> wrap(const T& arg, boost::function<F> func, boost::function<void()> onFail)
00124       {
00125         return func;
00126       }
00127     };
00128 
00129     template<typename T> struct BindTransform<boost::weak_ptr<T>, false >
00130     {
00131       typedef T* type;
00132       static T* transform(const boost::weak_ptr<T>& arg)
00133       {
00134         // Note that we assume that lock if successful always return the same pointer
00135         // And that if lock fails once, it will fail forever from that point
00136         return arg.lock().get();
00137       }
00138       template<typename F>
00139       static boost::function<F> wrap(const boost::weak_ptr<T>& arg, boost::function<F> func, boost::function<void()> onFail)
00140       {
00141         return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg, func, onFail);
00142       }
00143     };
00144 
00145     template<typename T> struct BindTransform<T*, true>
00146     {
00147       typedef T* type;
00148       static T* transform(T* const & arg)
00149       {
00150         // Note that we assume that lock if successful always return the same pointer
00151         return arg;
00152       }
00153       template<typename F>
00154       static boost::function<F> wrap(T*const & arg, boost::function<F> func, boost::function<void()> onFail)
00155       {
00156         return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg->weakPtr(), func, onFail);
00157       }
00158     };
00159 
00160     inline void throwPointerLockException()
00161     {
00162       throw PointerLockException();
00163     }
00164   }
00165 
00166 #ifndef DOXYGEN
00167   template<typename RF, typename AF>
00168   boost::function<RF> bind(const AF& fun)
00169   {
00170     return fun;
00171   }
00172 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
00173   template<typename RF, typename AF, typename ARG0 comma ATYPEDECL>      \
00174   boost::function<RF> bind(const AF& fun, const ARG0& arg0 comma ADECL)  \
00175   {                                                                      \
00176     typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;     \
00177     typename Transform::type transformed = Transform::transform(arg0);   \
00178     boost::function<RF> f = boost::bind(fun, transformed comma AUSE);    \
00179     return Transform::wrap(arg0, f, detail::throwPointerLockException);  \
00180   }                                                                      \
00181   template<typename RF, typename AF, typename ARG0 comma ATYPEDECL>      \
00182   boost::function<RF> bindWithFallback(const boost::function<void()> onFail, const AF& fun, const ARG0& arg0 comma ADECL)  \
00183   {                                                                      \
00184     typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;     \
00185     typename Transform::type transformed = Transform::transform(arg0);   \
00186     boost::function<RF> f = boost::bind(fun, transformed comma AUSE);    \
00187     return Transform::wrap(arg0, f, onFail);  \
00188   }
00189   QI_GEN(genCall)
00190 #undef genCall
00191 #endif // DOXYGEN
00192   template<typename F, typename ARG0>
00193   boost::function<F> track(const boost::function<F>& f, const ARG0& arg0)
00194   {
00195     typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;
00196     return Transform::wrap(arg0, f, detail::throwPointerLockException);
00197   }
00198   template<typename F, typename ARG0>
00199   boost::function<F> trackWithFallback(boost::function<void()> onFail,
00200       const boost::function<F>& f, const ARG0& arg0)
00201   {
00202     typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;
00203     return Transform::wrap(arg0, f, onFail);
00204   }
00205 }
00206 
00207 #endif  // _QI_DETAILS_TRACKABLE_HXX_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines