libqi-api  2.1.4.13
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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>
84  class LockAndCall
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  ST s = _wptr.lock(); \
100  if (s) \
101  return _f(AUSE); \
102  else \
103  if (_onFail) \
104  _onFail(); \
105  else \
106  return Result(); \
107  }
108  QI_GEN(genCall)
109 #undef genCall
110  WT _wptr;
111  boost::function<F> _f;
112  boost::function<void()> _onFail;
113  };
114 
115  template<typename T, bool IS_TRACKABLE> struct BindTransform
116  {
117  typedef const T& type;
118  static type transform(const T& arg)
119  {
120  return arg;
121  }
122  template<typename F>
123  static boost::function<F> wrap(const T& arg, boost::function<F> func, boost::function<void()> onFail)
124  {
125  return func;
126  }
127  };
128 
129  template<typename T> struct BindTransform<boost::weak_ptr<T>, false >
130  {
131  typedef T* type;
132  static T* transform(const boost::weak_ptr<T>& arg)
133  {
134  // Note that we assume that lock if successful always return the same pointer
135  // And that if lock fails once, it will fail forever from that point
136  return arg.lock().get();
137  }
138  template<typename F>
139  static boost::function<F> wrap(const boost::weak_ptr<T>& arg, boost::function<F> func, boost::function<void()> onFail)
140  {
141  return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg, func, onFail);
142  }
143  };
144 
145  template<typename T> struct BindTransform<T*, true>
146  {
147  typedef T* type;
148  static T* transform(T* const & arg)
149  {
150  // Note that we assume that lock if successful always return the same pointer
151  return arg;
152  }
153  template<typename F>
154  static boost::function<F> wrap(T*const & arg, boost::function<F> func, boost::function<void()> onFail)
155  {
156  return LockAndCall<boost::weak_ptr<T>, boost::shared_ptr<T>, F>(arg->weakPtr(), func, onFail);
157  }
158  };
159 
161  {
162  throw PointerLockException();
163  }
164  }
165 
166 #ifndef DOXYGEN
167  template<typename RF, typename AF>
168  boost::function<RF> bind(const AF& fun)
169  {
170  return fun;
171  }
172 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
173  template<typename RF, typename AF, typename ARG0 comma ATYPEDECL> \
174  boost::function<RF> bind(const AF& fun, const ARG0& arg0 comma ADECL) \
175  { \
176  typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform; \
177  typename Transform::type transformed = Transform::transform(arg0); \
178  boost::function<RF> f = boost::bind(fun, transformed comma AUSE); \
179  return Transform::wrap(arg0, f, detail::throwPointerLockException); \
180  } \
181  template<typename RF, typename AF, typename ARG0 comma ATYPEDECL> \
182  boost::function<RF> bindWithFallback(const boost::function<void()> onFail, const AF& fun, const ARG0& arg0 comma ADECL) \
183  { \
184  typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform; \
185  typename Transform::type transformed = Transform::transform(arg0); \
186  boost::function<RF> f = boost::bind(fun, transformed comma AUSE); \
187  return Transform::wrap(arg0, f, onFail); \
188  }
189  QI_GEN(genCall)
190 #undef genCall
191 #endif // DOXYGEN
192  template<typename F, typename ARG0>
193  boost::function<F> track(const boost::function<F>& f, const ARG0& arg0)
194  {
195  typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;
196  return Transform::wrap(arg0, f, detail::throwPointerLockException);
197  }
198  template<typename F, typename ARG0>
199  boost::function<F> trackWithFallback(boost::function<void()> onFail,
200  const boost::function<F>& f, const ARG0& arg0)
201  {
202  typedef typename detail::BindTransform<ARG0, boost::is_base_of<TrackableBase, typename boost::remove_pointer<ARG0>::type>::value> Transform;
203  return Transform::wrap(arg0, f, onFail);
204  }
205 }
206 
207 #endif // _QI_DETAILS_TRACKABLE_HXX_
void destroy()
Definition: trackable.hxx:28
boost::weak_ptr< T > weakPtr()
Definition: trackable.hxx:73
void destroy()
Stop and flush the logging system.
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)
Definition: trackable.hxx:94
boost::shared_ptr< T > lock()
Definition: trackable.hxx:67
void throwPointerLockException()
Definition: trackable.hxx:160
#define QI_GEN(f)
Definition: preproc.hpp:471
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:70
Trackable(T *ptr)
Definition: trackable.hxx:21
boost::function< F > trackWithFallback(boost::function< void()> onFail, const boost::function< F > &f, const ARG0 &arg0)
Definition: trackable.hxx:199
boost::function< RF > bind(const AF &fun,...)
boost::function< F > track(const boost::function< F > &f, const ARG0 &arg0)
Definition: trackable.hxx:193