libqi-api  release-2.5.3-2016-11-18
 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_DETAIL_TRACKABLE_HXX_
9 #define _QI_DETAIL_TRACKABLE_HXX_
10 
11 #include <type_traits>
12 #include <boost/function.hpp>
13 #include <boost/bind.hpp>
14 #include <boost/weak_ptr.hpp>
15 #include <boost/function_types/result_type.hpp>
16 
17 namespace qi
18 {
19  class Actor;
20 
21  template<typename T>
23  : _wasDestroyed(false)
24  {
25  T* thisAsT = static_cast<T*>(this);
26  _ptr = boost::shared_ptr<T>(thisAsT, boost::bind(&Trackable::_destroyed, _1));
27  }
28 
29  template<typename T>
30  inline Trackable<T>::Trackable(T* ptr)
31  : _wasDestroyed(false)
32  {
33  _ptr = boost::shared_ptr<T>(ptr, boost::bind(&Trackable::_destroyed, _1));
34  }
35 
36  template<typename T>
37  inline void Trackable<T>::destroy()
38  {
39  _ptr.reset();
40  wait();
41  }
42 
43  template<typename T>
44  inline void Trackable<T>::wait()
45  {
46  boost::mutex::scoped_lock lock(_mutex);
47  while (!_wasDestroyed)
48  {
49  _cond.wait(lock);
50  }
51  }
52 
53  template<typename T>
54  inline void Trackable<T>::_destroyed()
55  {
56  // unblock
57  boost::mutex::scoped_lock lock(_mutex);
58  _wasDestroyed = true;
59  _cond.notify_all();
60  }
61 
62  template<typename T>
64  {
65  // We expect destroy() to have been called from parent destructor, so from
66  // this thread.
67  if (!_wasDestroyed)
68  {
69  qiLogError("qi.Trackable") << "Trackable destroyed without calling destroy()";
70  // do it to mitigate the effect, but it's too late
71  destroy();
72  }
73  }
74 
75  template<typename T>
76  inline boost::weak_ptr<T> Trackable<T>::weakPtr()
77  {
78  return boost::weak_ptr<T>(_ptr);
79  }
80 
81  namespace detail
82  {
83  template <typename T>
85  {
86  return {};
87  }
88 
89  template <>
90  inline void defaultConstruct<void>()
91  {
92  }
93 
94  // Functor that locks a weak ptr and make a call if successful
95  // Generalize on shared_ptr and weak_ptr types in case we ever have
96  // other types with their semantics
97  template <typename WT, typename F>
99  {
100  WT _wptr;
101  F _f;
102  boost::function<void()> _onFail;
103 
104  public:
105  LockAndCall(WT arg, F func, boost::function<void()> onFail)
106  : _wptr(std::move(arg))
107  , _f(std::move(func))
108  , _onFail(std::move(onFail))
109  {}
110 
111  template <typename... Args>
112  // decltype(this->_f(std::forward<Args>(args)...)) does not work on vs2013 \o/
113  auto operator()(Args&&... args) -> decltype(std::declval<F>()(std::forward<Args>(args)...))
114  {
115  auto s = _wptr.lock();
116  if (s)
117  return _f(std::forward<Args>(args)...);
118  else
119  {
120  if (_onFail)
121  _onFail();
122  // hehe, you can't write return {}; because of void here... -_-
123  return defaultConstruct<decltype(this->_f(std::forward<Args>(args)...))>();
124  }
125  }
126  };
127 
128  template <typename T, bool IsActor>
129  struct ObjectWrap;
130 
131  template <typename T>
132  struct ObjectWrap<T, false>
133  {
134  template <typename F>
135  using wrap_type = typename std::decay<F>::type;
136  template <typename F>
137  static wrap_type<F> wrap(const T& arg, F&& func, boost::function<void()> onFail)
138  {
139  return std::forward<F>(func);
140  }
141  };
142 
143  template <typename T>
144  struct ObjectWrap<T, true>
145  {
146  static const bool is_async = true;
147  template <typename F>
148  using wrap_type = decltype(
149  std::declval<T>()->stranded(std::declval<typename std::decay<F>::type>()));
150  template <typename F>
151  static wrap_type<F> wrap(const T& arg, F&& func, boost::function<void()> onFail)
152  {
153  return arg->stranded(std::forward<F>(func), std::move(onFail));
154  }
155  };
156 
158  {
160  {
161  char arbitrary_buf[128];
162  };
163  template <typename T>
164  static decltype(T::is_async) f(int);
165  template <typename T>
166  static ArbitraryBigBuf f(void*);
167  };
168 
169  // can't use a "using" here because visual gets the SFINAE wrong in the conditional (lol.)
170  template <typename T>
171  struct IsAsyncBind
172  : std::conditional<sizeof(decltype(IsAsyncBindImpl::template f<T>(0))) != sizeof(IsAsyncBindImpl::ArbitraryBigBuf),
173  std::true_type,
174  std::false_type>::type
175  {
176  };
177 
178  template <bool IsAsync, typename F, typename... Args>
180 
181  template <typename F, typename... Args>
182  struct DecayAsyncResultImpl<false, F, Args...>
183  {
184  using type = decltype(std::declval<F>()(std::declval<Args>()...));
185  };
186 
187  template <typename F, typename... Args>
188  struct DecayAsyncResultImpl<true, F, Args...>
189  {
190  // I'd like to use a decltype, but vs2013 fails to parse this
191  //using type = typename decltype(std::declval<F>()(std::declval<Args>()...))::TemplateValue;
192  using type = typename std::result_of<F(Args...)>::type::TemplateValue;
193  };
194 
195  template <typename T, typename... Args>
197 
198  template <typename T, bool IsTrackable>
200  {
201  static T transform(T arg)
202  {
203  return arg;
204  }
205  template <typename F>
206  using wrap_type = typename std::decay<F>::type;
207  template <typename F>
208  static wrap_type<F> wrap(T arg, F&& func, boost::function<void()> onFail)
209  {
210  return std::forward<F>(func);
211  }
212  };
213 
214  template <typename T>
215  struct BindTransformImpl<T*, false>
216  {
218  template <typename F>
219  using wrap_type = typename ObjectWrapType::template wrap_type<F>;
220 
221  static T* transform(T* arg)
222  {
223  return arg;
224  }
225 
226  template <typename F>
227  static wrap_type<F> wrap(T* arg, F&& func, boost::function<void()> onFail)
228  {
229  return ObjectWrapType::wrap(arg, std::forward<F>(func), onFail);
230  }
231  };
232 
233  template <typename T>
234  struct BindTransformImpl<T*, true>
235  {
236  template <typename F>
237  using wrap_type = LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>;
238 
239  static T* transform(T* arg)
240  {
241  // Note that we assume that lock if successful always return the same pointer
242  return arg;
243  }
244 
245  template <typename F>
246  static wrap_type<F> wrap(T* arg, F&& func, boost::function<void()> onFail)
247  {
248  return LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>(
249  arg->weakPtr(),
250  std::forward<F>(func),
251  onFail);
252  }
253  };
254 
255  template <typename T>
256  struct BindTransformImpl<boost::weak_ptr<T>, false>
257  {
258  template <typename F>
259  using wrap_type = LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>;
260 
261  static T* transform(const boost::weak_ptr<T>& arg)
262  {
263  // Note that we assume that lock if successful always return the same pointer
264  // And that if lock fails once, it will fail forever from that point
265  return arg.lock().get();
266  }
267 
268  template <typename F>
269  static wrap_type<F> wrap(const boost::weak_ptr<T>& arg, F&& func, boost::function<void()> onFail)
270  {
271  return LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>(
272  arg,
273  std::forward<F>(func),
274  onFail);
275  }
276  };
277 
278  template <typename T>
279  struct BindTransformImpl<boost::shared_ptr<T>, false>
280  {
281  using ObjectWrapType = ObjectWrap<boost::shared_ptr<T>, std::is_base_of<Actor, T>::value>;
282  template <typename F>
283  using wrap_type = typename ObjectWrapType::template wrap_type<F>;
284 
285  static boost::shared_ptr<T> transform(boost::shared_ptr<T> arg)
286  {
287  return std::move(arg);
288  }
289 
290  template <typename F>
291  static wrap_type<F> wrap(const boost::shared_ptr<T>& arg, F&& func, boost::function<void()> onFail)
292  {
293  return ObjectWrapType::wrap(arg, std::forward<F>(func), onFail);
294  }
295  };
296 
297  template <typename T, typename K = typename std::decay<T>::type>
298  using BindTransform =
300 
302  {
303  throw PointerLockException();
304  }
305  }
306 
307  template <typename RF, typename AF, typename Arg0, typename... Args>
308  QI_API_DEPRECATED_MSG(Use 'bindWithFallback' without explicit template method signature)
309  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type
310  bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args)
311  {
312  using Transform = detail::BindTransform<Arg0>;
313  auto transformed = Transform::transform(arg0);
314  boost::function<RF> f = boost::bind(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...);
315  return Transform::wrap(arg0, std::move(f), std::move(onFail));
316  }
317  template <typename RF, typename AF, typename Arg0, typename... Args>
318  QI_API_DEPRECATED_MSG(Use 'bindSilent' without explicit template method signature)
319  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type bindSilent(AF&& fun,
320  Arg0&& arg0,
321  Args&&... args)
322  {
323  return bindWithFallback<RF, AF>({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
324  }
325  template <typename RF, typename AF, typename Arg0, typename... Args>
326  QI_API_DEPRECATED_MSG(Use 'bind' without explicit template method signature)
327  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type bind(AF&& fun,
328  Arg0&& arg0,
329  Args&&... args)
330  {
331  return bindWithFallback<RF, AF>(detail::throwPointerLockException, std::forward<AF>(fun), std::forward<Arg0>(arg0),
332  std::forward<Args>(args)...);
333  }
334 
335  template <typename AF, typename Arg0, typename... Args>
336  auto bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args) ->
337  typename detail::BindTransform<Arg0>::template wrap_type<
338  decltype(boost::bind(std::forward<AF>(fun),
340  std::forward<Args>(args)...))>
341  {
342  using Transform = detail::BindTransform<Arg0>;
343  auto transformed = Transform::transform(arg0);
344  return Transform::wrap(arg0,
345  boost::bind(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...),
346  std::move(onFail));
347  }
348  template <typename AF, typename Arg0, typename... Args>
349  auto bindSilent(AF&& fun, Arg0&& arg0, Args&&... args)
350  -> decltype(bindWithFallback({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...))
351  {
352  return bindWithFallback({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
353  }
354  template <typename AF, typename Arg0, typename... Args>
355  auto bind(AF&& fun, Arg0&& arg0, Args&&... args) -> decltype(bindWithFallback(detail::throwPointerLockException,
356  std::forward<AF>(fun),
357  std::forward<Arg0>(arg0),
358  std::forward<Args>(args)...))
359  {
361  std::forward<AF>(fun),
362  std::forward<Arg0>(arg0),
363  std::forward<Args>(args)...);
364  }
365 
366  // with support for R
367  template <typename R, typename AF, typename Arg0, typename... Args>
368  auto bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args) ->
369  typename std::enable_if<!std::is_function<R>::value,
370  typename detail::BindTransform<Arg0>::template wrap_type<
371  decltype(boost::bind<R>(std::forward<AF>(fun),
373  std::forward<Args>(args)...))>>::type
374  {
375  using Transform = detail::BindTransform<Arg0>;
376  auto transformed = Transform::transform(arg0);
377  return Transform::wrap(arg0,
378  boost::bind<R>(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...),
379  std::move(onFail));
380  }
381  template <typename R, typename AF, typename Arg0, typename... Args>
382  auto bindSilent(AF&& fun, Arg0&& arg0, Args&&... args) -> typename std::enable_if<
383  !std::is_function<R>::value,
384  decltype(
385  bindWithFallback<R>({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...))>::type
386  {
387  return bindWithFallback<R>({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
388  }
389  template <typename R, typename AF, typename Arg0, typename... Args>
390  auto bind(AF&& fun, Arg0&& arg0, Args&&... args) ->
391  typename std::enable_if<!std::is_function<R>::value,
392  decltype(bindWithFallback<R>(detail::throwPointerLockException,
393  std::forward<AF>(fun),
394  std::forward<Arg0>(arg0),
395  std::forward<Args>(args)...))>::type
396  {
397  return bindWithFallback<R>(detail::throwPointerLockException,
398  std::forward<AF>(fun),
399  std::forward<Arg0>(arg0),
400  std::forward<Args>(args)...);
401  }
402 
403  template <typename F, typename Arg0>
404  auto trackWithFallback(boost::function<void()> onFail, F&& f, Arg0&& arg0)
405  -> decltype(detail::BindTransform<Arg0>::wrap(std::forward<Arg0>(arg0), std::forward<F>(f), std::move(onFail)))
406  {
407  return detail::BindTransform<Arg0>::wrap(std::forward<Arg0>(arg0), std::forward<F>(f), std::move(onFail));
408  }
409  template <typename F, typename Arg0>
410  auto track(F&& f, Arg0&& arg0)
411  -> decltype(trackWithFallback(detail::throwPointerLockException, std::forward<F>(f), std::forward<Arg0>(arg0)))
412  {
413  return trackWithFallback(detail::throwPointerLockException, std::forward<F>(f), std::forward<Arg0>(arg0));
414  }
415  template <typename F, typename Arg0>
416  auto trackSilent(F&& f, Arg0&& arg0) -> decltype(trackWithFallback({}, std::forward<F>(f), std::forward<Arg0>(arg0)))
417  {
418  return trackWithFallback({}, std::forward<F>(f), std::forward<Arg0>(arg0));
419  }
420 
421  template<typename F, typename Arg0>
422  boost::function<F> trackWithFallback(boost::function<void()> onFail,
423  boost::function<F> f, const Arg0& arg0)
424  {
425  return detail::BindTransform<Arg0>::wrap(arg0, std::move(f), std::move(onFail));
426  }
427  template<typename F, typename Arg0>
428  boost::function<F> trackSilent(boost::function<F> f, const Arg0& arg0)
429  {
430  return trackWithFallback<F, Arg0>({}, std::move(f), arg0);
431  }
432  template<typename F, typename Arg0>
433  boost::function<F> track(boost::function<F> f, const Arg0& arg0)
434  {
435  return trackWithFallback<F, Arg0>(detail::throwPointerLockException, std::move(f), arg0);
436  }
437 }
438 
439 #endif // _QI_DETAIL_TRACKABLE_HXX_
auto operator()(Args &&...args) -> decltype(std::declval< F >()(std::forward< Args >(args)...))
Definition: trackable.hxx:113
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bindSilent(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:319
void destroy()
Stop and flush the logging system.
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:137
typename ObjectWrapType::template wrap_type< F > wrap_type
Definition: trackable.hxx:219
T defaultConstruct()
Definition: trackable.hxx:84
decltype(std::declval< T >() ->stranded(std::declval< typename std::decay< F >::type >())) wrap_type
Definition: trackable.hxx:149
static decltype(T::is_async) f(int)
auto trackSilent(F &&f, Arg0 &&arg0) -> decltype(trackWithFallback(
Definition: trackable.hxx:416
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bindWithFallback(boost::function< void()> onFail, AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:310
decltype(std::declval< F >()(std::declval< Args >()...)) type
Definition: trackable.hxx:184
typename std::result_of< F(Args...)>::type::TemplateValue type
Definition: trackable.hxx:192
void defaultConstruct< void >()
Definition: trackable.hxx:90
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:135
void throwPointerLockException()
Definition: trackable.hxx:301
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:112
LockAndCall(WT arg, F func, boost::function< void()> onFail)
Definition: trackable.hxx:105
void destroy()
Definition: trackable.hxx:37
auto bind(AF &&fun, Arg0 &&arg0, Args &&...args) -> typename std::enable_if<!std::is_function< R >::value, decltype(bindWithFallback< R >(detail::throwPointerLockException, std::forward< AF >(fun), std::forward< Arg0 >(arg0), std::forward< Args >(args)...))>::type
Definition: trackable.hxx:390
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:227
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:151
BindTransformImpl< K, std::is_base_of< TrackableBase, typename std::remove_pointer< K >::type >::value > BindTransform
Definition: trackable.hxx:299
auto track(F &&f, Arg0 &&arg0) -> decltype(trackWithFallback(detail::throwPointerLockException, std::forward< F >(f), std::forward< Arg0 >(arg0)))
Definition: trackable.hxx:410
static wrap_type< F > wrap(T arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:208
struct QI_API_DEPRECATED_MSG(Use 'QI_TYPE_ENUM'instead) QI_TYPE_ENUM_REGISTER_
Object tracking by blocking destruction while shared pointers are present.
Definition: trackable.hpp:43
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:246
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:206
auto trackWithFallback(boost::function< void()> onFail, F &&f, Arg0 &&arg0) -> decltype(detail::BindTransform< Arg0 >::wrap(std::forward< Arg0 >(arg0), std::forward< F >(f), std::move(onFail)))
Definition: trackable.hxx:404
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:327
Trackable()
Default constructor.
Definition: trackable.hxx:22
boost::weak_ptr< T > weakPtr()
Definition: trackable.hxx:76