libqi-api  2.4.3.28
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
trackable.hxx
Go to the documentation of this file.
1 #pragma once
2 /*
3  * Copyright (c) 2013 Aldebaran Robotics. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the COPYING file.
6  */
7 
8 #ifndef _QI_DETAILS_TRACKABLE_HXX_
9 #define _QI_DETAILS_TRACKABLE_HXX_
10 
11 #include <boost/function.hpp>
12 #include <boost/bind.hpp>
13 #include <boost/type_traits/is_base_of.hpp>
14 #include <boost/type_traits/remove_pointer.hpp>
15 #include <boost/weak_ptr.hpp>
16 #include <boost/function_types/result_type.hpp>
17 
18 namespace qi
19 {
20  template<typename T>
21  inline Trackable<T>::Trackable(T* ptr)
22  : _wasDestroyed(false)
23  {
24  _ptr = boost::shared_ptr<T>(ptr, boost::bind(&Trackable::_destroyed, _1));
25  }
26 
27  template<typename T>
28  inline void Trackable<T>::destroy()
29  {
30  _ptr.reset();
31  wait();
32  }
33 
34  template<typename T>
35  inline void Trackable<T>::wait()
36  {
37  boost::mutex::scoped_lock lock(_mutex);
38  while (!_wasDestroyed)
39  {
40  _cond.wait(lock);
41  }
42  }
43 
44  template<typename T>
45  inline void Trackable<T>::_destroyed()
46  {
47  // unblock
48  boost::mutex::scoped_lock lock(_mutex);
49  _wasDestroyed = true;
50  _cond.notify_all();
51  }
52 
53  template<typename T>
55  {
56  // We expect destroy() to have been called from parent destructor, so from
57  // this thread.
58  if (!_wasDestroyed)
59  {
60  qiLogError("qi.Trackable") << "Trackable destroyed without calling destroy()";
61  // do it to mitigate the effect, but it's too late
62  destroy();
63  }
64  }
65 
66  template<typename T>
67  inline boost::shared_ptr<T> Trackable<T>::lock()
68  {
69  return _ptr;
70  }
71 
72  template<typename T>
73  inline boost::weak_ptr<T> Trackable<T>::weakPtr()
74  {
75  return boost::weak_ptr<T>(_ptr);
76  }
77 
78  namespace detail
79  {
80  // Functor that locks a weak ptr and make a call if successful
81  // Generalize on shared_ptr and weak_ptr types in case we ever have
82  // other types with their semantics
83  template<typename WT, typename ST, typename F>
85  {
86  public:
87  typedef typename boost::function_types::result_type<F>::type Result;
88  LockAndCall(const WT& arg, boost::function<F> func, boost::function<void()> onFail)
89  : _wptr(arg)
90  , _f(func)
91  , _onFail(onFail)
92  {}
93 
94 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
95  QI_GEN_MAYBE_TEMPLATE_OPEN(comma) \
96  ATYPEDECL \
97  QI_GEN_MAYBE_TEMPLATE_CLOSE(comma) \
98  Result operator()(ADECL) \
99  { \
100  ST s = _wptr.lock(); \
101  if (s) \
102  return _f(AUSE); \
103  else \
104  { \
105  if (_onFail) \
106  _onFail(); \
107  return Result(); \
108  } \
109  }
110  QI_GEN(genCall)
111 #undef genCall
112  WT _wptr;
113  boost::function<F> _f;
114  boost::function<void()> _onFail;
115  };
116 
117  template<typename T, bool IS_TRACKABLE> struct BindTransform
118  {
119  typedef const T& type;
120  static type transform(const T& arg)
121  {
122  return arg;
123  }
124  template<typename F>
125  static boost::function<F> wrap(const T& arg, boost::function<F> func, boost::function<void()> onFail)
126  {
127  return func;
128  }
129  };
130 
131  template<typename T> struct BindTransform<boost::weak_ptr<T>, false >
132  {
133  typedef T* type;
134  static T* transform(const boost::weak_ptr<T>& arg)
135  {
136  // Note that we assume that lock if successful always return the same pointer
137  // And that if lock fails once, it will fail forever from that point
138  return arg.lock().get();
139  }
140  template<typename F>
141  static boost::function<F> wrap(const boost::weak_ptr<T>& arg, boost::function<F> func, boost::function<void()> onFail)
142  {
143  return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg, func, onFail);
144  }
145  };
146 
147  template<typename T> struct BindTransform<T*, true>
148  {
149  typedef T* type;
150  static T* transform(T* const & arg)
151  {
152  // Note that we assume that lock if successful always return the same pointer
153  return arg;
154  }
155  template<typename F>
156  static boost::function<F> wrap(T*const & arg, boost::function<F> func, boost::function<void()> onFail)
157  {
158  return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg->weakPtr(), func, onFail);
159  }
160  };
161 
163  {
164  throw PointerLockException();
165  }
166  }
167 
168 #ifndef DOXYGEN
169  template<typename RF, typename AF>
170  boost::function<RF> bind(const AF& fun)
171  {
172  return fun;
173  }
174 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
175  template <typename RF, typename AF, typename ARG0 comma ATYPEDECL> \
176  boost::function<RF> bind(const AF& fun, const ARG0& arg0 comma ADECL) \
177  { \
178  typedef typename detail::BindTransform< \
179  ARG0, \
180  boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform; \
181  typename Transform::type transformed = Transform::transform(arg0); \
182  boost::function<RF> f = boost::bind(fun, transformed comma AUSE); \
183  return Transform::wrap(arg0, f, detail::throwPointerLockException); \
184  } \
185  template <typename RF, typename AF, typename ARG0 comma ATYPEDECL> \
186  boost::function<RF> bindWithFallback(const boost::function<void()>& onFail, \
187  const AF& fun, \
188  const ARG0& arg0 comma ADECL) \
189  { \
190  typedef typename detail::BindTransform< \
191  ARG0, \
192  boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform; \
193  typename Transform::type transformed = Transform::transform(arg0); \
194  boost::function<RF> f = boost::bind(fun, transformed comma AUSE); \
195  return Transform::wrap(arg0, f, onFail); \
196  } \
197  template <typename RF, typename AF, typename ARG0 comma ATYPEDECL> \
198  boost::function<RF> bindSilent(const AF& fun, const ARG0& arg0 comma ADECL) \
199  { \
200  return bindWithFallback<RF, AF, ARG0 comma ATYPES>(boost::function<void()>(), fun, arg0 comma AUSE); \
201  }
202  QI_GEN(genCall)
203 #undef genCall
204 #endif // DOXYGEN
205  template<typename F, typename ARG0>
206  boost::function<F> track(const boost::function<F>& f, const ARG0& arg0)
207  {
209  return Transform::wrap(arg0, f, detail::throwPointerLockException);
210  }
211  template<typename F, typename ARG0>
212  boost::function<F> trackWithFallback(boost::function<void()> onFail,
213  const boost::function<F>& f, const ARG0& arg0)
214  {
216  return Transform::wrap(arg0, f, onFail);
217  }
218  template<typename F, typename ARG0>
219  boost::function<F> trackSilent(const boost::function<F>& f, const ARG0& arg0)
220  {
221  return trackWithFallback<F, ARG0>(boost::function<void()>(), f, arg0);
222  }
223 }
224 
225 #endif // _QI_DETAILS_TRACKABLE_HXX_
void destroy()
Stop and flush the logging system.
boost::function_types::result_type< F >::type Result
Definition: trackable.hxx:87
boost::function< RF > bind(const AF &fun,...)
boost::function< F > _f
Definition: trackable.hxx:113
static boost::function< F > wrap(const T &arg, boost::function< F > func, boost::function< void()> onFail)
Definition: trackable.hxx:125
boost::shared_ptr< T > lock()
Definition: trackable.hxx:67
void throwPointerLockException()
Definition: trackable.hxx:162
Trackable(T *ptr)
Default constructor.
Definition: trackable.hxx:21
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:113
static T * transform(T *const &arg)
Definition: trackable.hxx:150
boost::function< void()> _onFail
Definition: trackable.hxx:114
void destroy()
Definition: trackable.hxx:28
LockAndCall(const WT &arg, boost::function< F > func, boost::function< void()> onFail)
Definition: trackable.hxx:88
static boost::function< F > wrap(T *const &arg, boost::function< F > func, boost::function< void()> onFail)
Definition: trackable.hxx:156
boost::function< F > track(const boost::function< F > &f, const ARG0 &arg0)
Wrap given function f with a tracking check on arg0, which must be a weak pointer or a Trackable inst...
Definition: trackable.hxx:206
boost::function< F > trackSilent(const boost::function< F > &f, const ARG0 &arg0)
Definition: trackable.hxx:219
boost::function< F > trackWithFallback(boost::function< void()> onFail, const boost::function< F > &f, const ARG0 &arg0)
Wrap given function f with a tracking check on arg0, which must be a weak pointer or a Trackable inst...
Definition: trackable.hxx:212
~Trackable()
Default destructor.
Definition: trackable.hxx:54
Object tracking by blocking destruction while shared pointers are present.
Definition: trackable.hpp:42
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)
Definition: trackable.hxx:94
static type transform(const T &arg)
Definition: trackable.hxx:120
boost::weak_ptr< T > weakPtr()
Definition: trackable.hxx:73
#define QI_GEN(f)
Definition: preproc.hpp:476