libqi-api  2.8.7.4
 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() const
77  {
78  return boost::weak_ptr<T>(_ptr);
79  }
80 
81  namespace detail
82  {
83  template <typename T>
85  {
86  return T{}; // Default constructor might be explicit, so we are forced to call it explicitly.
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)
114  -> decltype(std::declval<F>()(std::forward<Args>(args)...))
115  {
116  auto s = _wptr.lock();
117  if (s)
118  return _f(std::forward<Args>(args)...);
119  else
120  {
121  if (_onFail)
122  _onFail();
123  // hehe, you can't write return {}; because of void here... -_-
124  return defaultConstruct<decltype(this->_f(std::forward<Args>(args)...))>();
125  }
126  }
127  };
128 
129  template <typename T, bool IsActor>
130  struct ObjectWrap;
131 
132  template <typename T>
133  struct ObjectWrap<T, false>
134  {
135  template <typename F>
136  using wrap_type = typename std::decay<F>::type;
137  template <typename F>
138  static wrap_type<F> wrap(const T& arg, F&& func, boost::function<void()> onFail)
139  {
140  return std::forward<F>(func);
141  }
142  };
143 
144  template <typename T>
145  struct ObjectWrap<T, true>
146  {
147  static const bool is_async = true;
148  template <typename F>
149  using wrap_type = decltype(
150  std::declval<T>()->strandedUnwrapped(std::declval<typename std::decay<F>::type>()));
151  template <typename F>
152  static wrap_type<F> wrap(const T& arg, F&& func, boost::function<void()> onFail)
153  {
154  return arg->strandedUnwrapped(std::forward<F>(func), std::move(onFail));
155  }
156  };
157 
159  {
161  {
162  char arbitrary_buf[128];
163  };
164  template <typename T>
165  static decltype(T::is_async) f(int);
166  template <typename T>
167  static ArbitraryBigBuf f(void*);
168  };
169 
170  // can't use a "using" here because visual gets the SFINAE wrong in the conditional (lol.)
171  template <typename T>
172  struct IsAsyncBind
173  : std::conditional<sizeof(decltype(IsAsyncBindImpl::template f<T>(0))) != sizeof(IsAsyncBindImpl::ArbitraryBigBuf),
174  std::true_type,
175  std::false_type>::type
176  {
177  };
178 
179  template <typename T, bool IsTrackable>
181  {
182  static T transform(T arg)
183  {
184  return arg;
185  }
186  template <typename F>
187  using wrap_type = typename std::decay<F>::type;
188  template <typename F>
189  static wrap_type<F> wrap(T arg, F&& func, boost::function<void()> onFail)
190  {
191  return std::forward<F>(func);
192  }
193  };
194 
195  template <typename T>
196  struct BindTransformImpl<T*, false>
197  {
199  template <typename F>
200  using wrap_type = typename ObjectWrapType::template wrap_type<F>;
201 
202  static T* transform(T* arg)
203  {
204  return arg;
205  }
206 
207  template <typename F>
208  static wrap_type<F> wrap(T* arg, F&& func, boost::function<void()> onFail)
209  {
210  return ObjectWrapType::wrap(arg, std::forward<F>(func), onFail);
211  }
212  };
213 
214  template <typename T>
215  struct BindTransformImpl<T*, true>
216  {
217  template <typename F>
218  using wrap_type = LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>;
219 
220  static T* transform(T* arg)
221  {
222  // Note that we assume that lock if successful always return the same pointer
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 LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>(
230  arg->weakPtr(),
231  std::forward<F>(func),
232  onFail);
233  }
234  };
235 
236  template <typename T>
237  struct BindTransformImpl<boost::weak_ptr<T>, false>
238  {
239  template <typename F>
240  using wrap_type = LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>;
241 
242  static T* transform(const boost::weak_ptr<T>& arg)
243  {
244  // Note that we assume that lock if successful always return the same pointer
245  // And that if lock fails once, it will fail forever from that point
246  return arg.lock().get();
247  }
248 
249  template <typename F>
250  static wrap_type<F> wrap(const boost::weak_ptr<T>& arg, F&& func, boost::function<void()> onFail)
251  {
252  return LockAndCall<boost::weak_ptr<T>, typename std::decay<F>::type>(
253  arg,
254  std::forward<F>(func),
255  onFail);
256  }
257  };
258 
259  template <typename T>
260  struct BindTransformImpl<boost::shared_ptr<T>, false>
261  {
262  using ObjectWrapType = ObjectWrap<boost::shared_ptr<T>, std::is_base_of<Actor, T>::value>;
263  template <typename F>
264  using wrap_type = typename ObjectWrapType::template wrap_type<F>;
265 
266  static boost::shared_ptr<T> transform(boost::shared_ptr<T> arg)
267  {
268  return std::move(arg);
269  }
270 
271  template <typename F>
272  static wrap_type<F> wrap(const boost::shared_ptr<T>& arg, F&& func, boost::function<void()> onFail)
273  {
274  return ObjectWrapType::wrap(arg, std::forward<F>(func), onFail);
275  }
276  };
277 
278  template <typename T>
279  using BindTransform =
280  BindTransformImpl<typename std::decay<T>::type, std::is_base_of<TrackableBase, typename std::remove_pointer<typename std::decay<T>::type>::type>::value>;
281 
283  {
284  throw PointerLockException();
285  }
286  }
287 
288  template <typename RF, typename AF, typename Arg0, typename... Args>
289  QI_API_DEPRECATED_MSG(Use 'bindWithFallback' without explicit template method signature)
290  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type
291  bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args)
292  {
293  using Transform = detail::BindTransform<Arg0>;
294  auto transformed = Transform::transform(arg0);
295  boost::function<RF> f = boost::bind(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...);
296  return Transform::wrap(arg0, std::move(f), std::move(onFail));
297  }
298  template <typename RF, typename AF, typename Arg0, typename... Args>
299  QI_API_DEPRECATED_MSG(Use 'bindSilent' without explicit template method signature)
300  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type bindSilent(AF&& fun,
301  Arg0&& arg0,
302  Args&&... args)
303  {
304  return bindWithFallback<RF, AF>({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
305  }
306  template <typename RF, typename AF, typename Arg0, typename... Args>
307  QI_API_DEPRECATED_MSG(Use 'bind' without explicit template method signature)
308  typename std::enable_if<std::is_function<RF>::value, boost::function<RF>>::type bind(AF&& fun,
309  Arg0&& arg0,
310  Args&&... args)
311  {
312  return bindWithFallback<RF, AF>(detail::throwPointerLockException, std::forward<AF>(fun), std::forward<Arg0>(arg0),
313  std::forward<Args>(args)...);
314  }
315 
316  namespace detail
317  {
318  template<typename AF, typename Arg0, typename... Args>
319  struct WorkaroundVS2015 // TODO: Remove once we upgrade from VS2015
320  {
321  using type = decltype(boost::bind(
322  std::declval<AF>(),
323  detail::BindTransform<Arg0>::transform(std::declval<Arg0>()),
324  std::declval<Args>()...));
325  };
326  }
327 
328  template <typename AF, typename Arg0, typename... Args>
329  auto bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args)
330  -> typename detail::BindTransform<Arg0>::template wrap_type<
331  typename detail::WorkaroundVS2015<AF, Arg0, Args...>::type
332  >
333  {
334  using Transform = detail::BindTransform<Arg0>;
335  auto transformed = Transform::transform(arg0);
336  return Transform::wrap(arg0,
337  boost::bind(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...),
338  std::move(onFail));
339  }
340  template <typename AF, typename Arg0, typename... Args>
341  auto bindSilent(AF&& fun, Arg0&& arg0, Args&&... args)
342  -> decltype(bindWithFallback({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...))
343  {
344  return bindWithFallback({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
345  }
346  template <typename AF, typename Arg0, typename... Args>
347  auto bind(AF&& fun, Arg0&& arg0, Args&&... args)
349  std::forward<AF>(fun),
350  std::forward<Arg0>(arg0),
351  std::forward<Args>(args)...))
352  {
354  std::forward<AF>(fun),
355  std::forward<Arg0>(arg0),
356  std::forward<Args>(args)...);
357  }
358 
359  template <typename R, typename T, typename Instance, typename... Args0, typename... Args1>
360  auto bind(R(T::*fun)(Args0...), Instance&& instance, Args1&&... args1)
362  fun,
363  std::forward<Instance>(instance),
364  std::forward<Args1>(args1)...))
365  {
367  fun,
368  std::forward<Instance>(instance),
369  std::forward<Args1>(args1)...);
370  }
371 
372  // with support for R
373  template <typename R, typename AF, typename Arg0, typename... Args>
374  auto bindWithFallback(boost::function<void()> onFail, AF&& fun, Arg0&& arg0, Args&&... args)
375  -> typename std::enable_if<!std::is_function<R>::value,
376  typename detail::BindTransform<Arg0>::template wrap_type<
377  decltype(boost::bind<R>(std::forward<AF>(fun),
379  std::forward<Args>(args)...))>>::type
380  {
381  using Transform = detail::BindTransform<Arg0>;
382  auto transformed = Transform::transform(arg0);
383  return Transform::wrap(arg0,
384  boost::bind<R>(std::forward<AF>(fun), std::move(transformed), std::forward<Args>(args)...),
385  std::move(onFail));
386  }
387  template <typename R, typename AF, typename Arg0, typename... Args>
388  auto bindSilent(AF&& fun, Arg0&& arg0, Args&&... args)
389  -> typename std::enable_if<!std::is_function<R>::value,
390  decltype(bindWithFallback<R>({},
391  std::forward<AF>(fun),
392  std::forward<Arg0>(arg0),
393  std::forward<Args>(args)...))>::type
394  {
395  return bindWithFallback<R>({}, std::forward<AF>(fun), std::forward<Arg0>(arg0), std::forward<Args>(args)...);
396  }
397 
398  template <typename R, typename AF, typename Arg0, typename... Args>
399  auto bind(AF&& fun, Arg0&& arg0, Args&&... args)
400  -> typename std::enable_if<!std::is_function<R>::value,
401  decltype(bindWithFallback<R>(detail::throwPointerLockException,
402  std::forward<AF>(fun),
403  std::forward<Arg0>(arg0),
404  std::forward<Args>(args)...))>::type
405  {
406  return bindWithFallback<R>(detail::throwPointerLockException,
407  std::forward<AF>(fun),
408  std::forward<Arg0>(arg0),
409  std::forward<Args>(args)...);
410  }
411 
412  template <typename F, typename T>
413  auto trackWithFallback(boost::function<void()> onFail, F&& f, T&& toTrack)
414  -> decltype(detail::BindTransform<T>::wrap(std::forward<T>(toTrack), std::forward<F>(f), std::move(onFail)))
415  {
416  return detail::BindTransform<T>::wrap(std::forward<T>(toTrack), std::forward<F>(f), std::move(onFail));
417  }
418 
419  template <typename F, typename T>
420  auto track(F&& f, T&& toTrack)
421  -> decltype(trackWithFallback(detail::throwPointerLockException, std::forward<F>(f), std::forward<T>(toTrack)))
422  {
423  return trackWithFallback(detail::throwPointerLockException, std::forward<F>(f), std::forward<T>(toTrack));
424  }
425 
426  template <typename F, typename T>
427  auto trackSilent(F&& f, T&& toTrack)
428  -> decltype(trackWithFallback({}, std::forward<F>(f), std::forward<T>(toTrack)))
429  {
430  return trackWithFallback({}, std::forward<F>(f), std::forward<T>(toTrack));
431  }
432 
433  template<typename F, typename T>
434  boost::function<F> trackWithFallback(
435  boost::function<void()> onFail, boost::function<F> f, const T& toTrack)
436  {
437  return detail::BindTransform<T>::wrap(toTrack, std::move(f), std::move(onFail));
438  }
439  template<typename F, typename T>
440  boost::function<F> trackSilent(boost::function<F> f, const T& toTrack)
441  {
442  return trackWithFallback<F, T>({}, std::move(f), toTrack);
443  }
444  template<typename F, typename T>
445  boost::function<F> track(boost::function<F> f, const T& toTrack)
446  {
447  return trackWithFallback<F, T>(detail::throwPointerLockException, std::move(f), toTrack);
448  }
449 }
450 
451 #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:300
void destroy()
Stop and flush the logging system.
auto trackWithFallback(boost::function< void()> onFail, F &&f, T &&toTrack) -> decltype(detail::BindTransform< T >::wrap(std::forward< T >(toTrack), std::forward< F >(f), std::move(onFail)))
Definition: trackable.hxx:413
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:138
auto track(F &&f, T &&toTrack) -> decltype(trackWithFallback(detail::throwPointerLockException, std::forward< F >(f), std::forward< T >(toTrack)))
Definition: trackable.hxx:420
typename ObjectWrapType::template wrap_type< F > wrap_type
Definition: trackable.hxx:200
decltype(std::declval< T >() ->strandedUnwrapped(std::declval< typename std::decay< F >::type >())) wrap_type
Definition: trackable.hxx:150
T defaultConstruct()
Definition: trackable.hxx:84
static decltype(T::is_async) f(int)
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:291
void defaultConstruct< void >()
Definition: trackable.hxx:90
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:136
BindTransformImpl< typename std::decay< T >::type, std::is_base_of< TrackableBase, typename std::remove_pointer< typename std::decay< T >::type >::type >::value > BindTransform
Definition: trackable.hxx:280
void throwPointerLockException()
Definition: trackable.hxx:282
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:120
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:399
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:208
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:152
static wrap_type< F > wrap(T arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:189
boost::weak_ptr< T > weakPtr() const
Definition: trackable.hxx:76
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:45
auto trackSilent(F &&f, T &&toTrack) -> decltype(trackWithFallback(
Definition: trackable.hxx:427
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:227
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:187
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:308
decltype(boost::bind(std::declval< AF >(), detail::BindTransform< Arg0 >::transform(std::declval< Arg0 >()), std::declval< Args >()...)) type
Definition: trackable.hxx:324
Trackable()
Default constructor.
Definition: trackable.hxx:22