libqi-api
2.0.6.8
|
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_