- Aldebaran documentation |
- C++ Libraries |
- index

libqi-api 2.8.7.4

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Examples

- File List
- File Members

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>
22 inline Trackable<T>::Trackable()
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>
63 inline Trackable<T>::~Trackable()
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>
84 T defaultConstruct()
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>
98 class LockAndCall
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
158 struct IsAsyncBindImpl
159 {
160 struct ArbitraryBigBuf
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>
180 struct BindTransformImpl
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 {
198 using ObjectWrapType = ObjectWrap<T*, std::is_base_of<Actor, T>::value>;
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
282 inline void throwPointerLockException()
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)
348 -> decltype(bindWithFallback(detail::throwPointerLockException,
349 std::forward<AF>(fun),
350 std::forward<Arg0>(arg0),
351 std::forward<Args>(args)...))
352 {
353 return bindWithFallback(detail::throwPointerLockException,
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)
361 -> decltype(bindWithFallback(detail::throwPointerLockException,
362 fun,
363 std::forward<Instance>(instance),
364 std::forward<Args1>(args1)...))
365 {
366 return bindWithFallback(detail::throwPointerLockException,
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),
378 detail::BindTransform<Arg0>::transform(arg0),
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_
qi::detail::BindTransformImpl::transform
static T transform(T arg)
Definition: trackable.hxx:182
qi::detail::LockAndCall::operator()
auto operator()(Args &&...args) -> decltype(std::declval< F >()(std::forward< Args >(args)...))
Definition: trackable.hxx:113
qi::detail::IsAsyncBindImpl::ArbitraryBigBuf
Definition: trackable.hxx:160
qi::bindSilent
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bindSilent(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:300
qi::log::destroy
void destroy()
Stop and flush the logging system.
qi::trackWithFallback
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
qi::detail::ObjectWrap< T, false >::wrap
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:138
qi::track
auto track(F &&f, T &&toTrack) -> decltype(trackWithFallback(detail::throwPointerLockException, std::forward< F >(f), std::forward< T >(toTrack)))
Definition: trackable.hxx:420
qi::detail::BindTransformImpl< T *, false >::wrap_type
typename ObjectWrapType::template wrap_type< F > wrap_type
Definition: trackable.hxx:200
qi::detail::ObjectWrap< T, true >::wrap_type
decltype(std::declval< T >() ->strandedUnwrapped(std::declval< typename std::decay< F >::type >())) wrap_type
Definition: trackable.hxx:150
qi::detail::defaultConstruct
T defaultConstruct()
Definition: trackable.hxx:84
qi::detail::IsAsyncBindImpl::f
static decltype(T::is_async) f(int)
qi::bindWithFallback
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
qi::detail::BindTransformImpl
Definition: trackable.hxx:180
qi::Trackable::wait
void wait()
Definition: trackable.hxx:44
qi::detail::defaultConstruct< void >
void defaultConstruct< void >()
Definition: trackable.hxx:90
qi::detail::ObjectWrap< T, false >::wrap_type
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:136
qi::detail::BindTransform
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
qi::detail::IsAsyncBindImpl::ArbitraryBigBuf::arbitrary_buf
char arbitrary_buf[128]
Definition: trackable.hxx:162
qi::detail::throwPointerLockException
void throwPointerLockException()
Definition: trackable.hxx:282
qiLogError
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:120
qi::detail::LockAndCall::LockAndCall
LockAndCall(WT arg, F func, boost::function< void()> onFail)
Definition: trackable.hxx:105
qi::Trackable::destroy
void destroy()
Definition: trackable.hxx:37
qi::detail::IsAsyncBind
Definition: trackable.hxx:172
qi::bind
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
qi::detail::BindTransformImpl< T *, false >::wrap
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:208
qi::detail::ObjectWrap< T, true >::wrap
static wrap_type< F > wrap(const T &arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:152
qi::detail::ObjectWrap
Definition: trackable.hxx:130
qi::detail::BindTransformImpl< T *, false >::transform
static T * transform(T *arg)
Definition: trackable.hxx:202
qi::detail::LockAndCall
Definition: trackable.hxx:98
qi::detail::BindTransformImpl::wrap
static wrap_type< F > wrap(T arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:189
qi::Trackable::weakPtr
boost::weak_ptr< T > weakPtr() const
Definition: trackable.hxx:76
qi::Trackable::~Trackable
~Trackable()
Definition: trackable.hxx:63
qi::detail::IsAsyncBindImpl
Definition: trackable.hxx:158
qi::detail::QI_API_DEPRECATED_MSG
struct QI_API_DEPRECATED_MSG(Use 'QI_TYPE_ENUM'instead) QI_TYPE_ENUM_REGISTER_
Definition: typeinterface.hpp:411
qi::detail::WorkaroundVS2015
Definition: trackable.hxx:319
qi::Trackable
Object tracking by blocking destruction while shared pointers are present.
Definition: trackable.hpp:45
qi::detail::BindTransformImpl< T *, true >::transform
static T * transform(T *arg)
Definition: trackable.hxx:220
qi::trackSilent
auto trackSilent(F &&f, T &&toTrack) -> decltype(trackWithFallback(
Definition: trackable.hxx:427
qi::detail::BindTransformImpl< T *, true >::wrap
static wrap_type< F > wrap(T *arg, F &&func, boost::function< void()> onFail)
Definition: trackable.hxx:227
qi::detail::BindTransformImpl::wrap_type
typename std::decay< F >::type wrap_type
Definition: trackable.hxx:187
qi::bind
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:308
qi::detail::WorkaroundVS2015::type
decltype(boost::bind(std::declval< AF >(), detail::BindTransform< Arg0 >::transform(std::declval< Arg0 >()), std::declval< Args >()...)) type
Definition: trackable.hxx:324
qi::PointerLockException
Definition: trackable.hpp:81
qi::Trackable::Trackable
Trackable()
Default constructor.
Definition: trackable.hxx:22