ocra-recipes
Doxygen documentation for the ocra-recipes repository
ObserverSubjectBase.h
Go to the documentation of this file.
1 
14 #ifndef _OCRA_OBSERVER_SUBJECT_BASE_H_
15 #define _OCRA_OBSERVER_SUBJECT_BASE_H_
16 
17 #include <functional>
18 #include <algorithm>
19 
20 #include <boost/any.hpp>
21 #include <boost/type_traits/is_class.hpp>
22 #include <boost/type_traits/is_base_of.hpp>
23 #include <boost/static_assert.hpp>
24 #include <boost/ptr_container/ptr_vector.hpp>
25 
26 namespace ocra
27 {
28  // ------------------------------------------------------------
29  // --- INVOKER ------------------------------------------------
30  // ------------------------------------------------------------
31 
32  template<int EVT> class ObserverBase;
33 
35 
45  template<int EVT>
47  {
48  protected:
50  typedef void (observer_base_type::*member_callback_type)(int);
51  typedef void (*free_callback_type)(int);
52 
53  public:
54  virtual ~InvokerBase() {} // Invoker instances are polymorphically destroyed by SubjectBase.
55 
57  template<class T>
59  bool isObserverEqualTo(std::pair<T*, void (T::*)(int)> observer)
60  {
61  return observer.first == getObject() && isCallbackEqualTo(observer.second);
62  }
63 
64  template<class T>
65  bool isCallbackEqualTo(void (T::*callback)(int))
66  {
67  bool result;
68  try {
69  result = callback == boost::any_cast<void (T::*)(int)>(getCallback());
70  }
71  catch(boost::bad_any_cast&) {
72  result = false;
73  }
74  return result;
75  }
76 
78  bool isCallbackEqualTo(void (*callback)(int))
79  {
80  bool result;
81  try {
82  result = callback == boost::any_cast<void (*)(int)>(getCallback());
83  }
84  catch(boost::bad_any_cast&) {
85  result = false;
86  }
87  return result;
88  }
90 
91  public:
93 
98  virtual void trigger(int timestamp) = 0;
99 
100  protected:
101  virtual boost::any getCallback() = 0;
102  virtual void* getObject() = 0;
103  };
104 
105 
106  // ------------------------------------------------------------
107 
109  template<class T, int EVT, bool T_isDerivedFromObserverBase> class Invoker
110  {
111  };
112 
113 
114  // ------------------------------------------------------------
115 
117  template<class T, int EVT>
118  class Invoker<T, EVT, true /*meaning: ObserverBase<EVT> is base of T*/>
119  : public InvokerBase<EVT>
120  {
121  public:
122  Invoker(T& object, void (T::*callback)(int)): object_(object), callback_(callback), timestamp_(-1) {}
123 
124  void trigger(int timestamp)
125  {
126  object_.InvokerBase<EVT>::observer_base_type::trigger(object_, callback_, timestamp, timestamp_);
127  }
128 
129  protected:
130  boost::any getCallback() { return boost::any(callback_); }
131  void* getObject() { return &object_; }
132 
133  private:
134  T& object_;
135  void (T::*callback_)(int);
136  int timestamp_;
137  };
138 
139 
140  // ------------------------------------------------------------
141 
143  template<class T, int EVT>
144  class Invoker<T, EVT, false /*meaning: ObserverBase<EVT> is NOT a base of T*/>
145  : public InvokerBase<EVT>
146  {
147  public:
148  Invoker(T& object, void (T::*callback)(int)): object_(object), callback_(callback) {}
149 
150  void trigger(int timestamp) { if(callback_) (object_.*callback_)(timestamp); }
151 
152  protected:
153  boost::any getCallback() { return boost::any(callback_); }
154  void* getObject() { return &object_; }
155 
156  private:
157  T& object_;
158  void (T::*callback_)(int);
159  };
160 
161 
162  // ------------------------------------------------------------
163 
165  template<int EVT>
166  class Invoker<void, EVT, false /*true would have no meaning in the free function case*/>
167  : public InvokerBase<EVT>
168  {
169  public:
170  Invoker(void (*callback)(int)): callback_(callback) {}
171 
172  void trigger(int timestamp) { if(callback_) (*callback_)(timestamp); }
173 
174  protected:
175  boost::any getCallback() { return boost::any(callback_); }
176  void* getObject() { return 0x0; }
177 
178  private:
179  void (*callback_)(int);
180  };
181 
182  // ------------------------------------------------------------
183 
185  template<int EVT>
186  class Invoker<void, EVT, true>
187  {
188  };
189 
190 
191  // ------------------------------------------------------------
192  // --- OBSERVER_BASE ------------------------------------------
193  // ------------------------------------------------------------
194 
195  template<int EVT> class SubjectBase;
196 
198 
234  template<int EVT>
235  class ObserverBase
236  {
237  protected:
240 
241  public:
243  void bind(subject_type& subject) { subject_ = &subject; }
244 
245  protected:
247  void stopPropagation() { propagate_ = false; }
248 
250  ObserverBase(): subject_(0x0), propagate_(true) {}
254 
255  private:
257  template<class T>
258  void trigger(T& object, void (T::*callback)(int), int timestamp, int& savedTimestamp)
259  {
260  if(timestamp > savedTimestamp)
261  {
262  savedTimestamp = timestamp;
263  propagate_ = true;
264  if(callback)
265  (object.*callback)(timestamp);
266  if(propagate_ && subject_)
267  subject_->propagate(timestamp);
268  }
269  }
270 
271  subject_type* subject_;
272  bool propagate_;
273 
274  template<class, int, bool> friend class Invoker;
275  };
276 
277 
278  // ------------------------------------------------------------
279  // --- SUBJECT_BASE -------------------------------------------
280  // ------------------------------------------------------------
281 
283 
288  template<int EVT> struct SubjectBaseTraitsBase {
290  };
291 
292  template<int EVT, class T>
294  {
296  typedef void (T::*callback_type)(int);
298  typedef std::pair<T*, callback_type> invoker_id_type;
299  typedef std::mem_fun1_ref_t<bool, invoker_base_type, invoker_id_type> invoker_comparator_type;
300  };
301 
302  template<int EVT>
303  struct SubjectBaseTraits<EVT, void> : SubjectBaseTraitsBase<EVT>
304  {
306  typedef void (*callback_type)(int);
308  typedef callback_type invoker_id_type;
309  typedef std::mem_fun1_ref_t<bool, invoker_base_type, invoker_id_type> invoker_comparator_type;
310  };
311 
312  template<int EVT>
313  class SubjectBase
314  {
315  private:
317  protected:
319  SubjectBase() {}
323 
324  public:
326  template<class T>
327  void connect(T& object, typename SubjectBaseTraits<EVT, T>::callback_type newCallback) const
328  {
329  BOOST_STATIC_ASSERT(boost::is_class<T>::value); // Avoid passing (void*,int*,char*,...)
330  observers_.push_back(new typename SubjectBaseTraits<EVT, T>::invoker_type(object, newCallback));
331  }
332 
334  void connect(typename SubjectBaseTraits<EVT, void>::callback_type newCallback) const
335  {
336  observers_.push_back(new typename SubjectBaseTraits<EVT, void>::invoker_type(newCallback));
337  }
338 
340  template<class T>
341  void disconnect(T& object, typename SubjectBaseTraits<EVT, T>::callback_type callback) const
342  {
343  BOOST_STATIC_ASSERT(boost::is_class<T>::value);
344 
345  typename SubjectBaseTraits<EVT, T>::invoker_comparator_type comparator = std::mem_fun_ref(&invoker_base_type::template isObserverEqualTo<T>);
346  typename SubjectBaseTraits<EVT, T>::invoker_id_type elementToErase(&object, callback);
347 
348  observers_.erase_if( std::bind2nd(comparator, elementToErase) );
349  }
350 
352  void disconnect(typename SubjectBaseTraits<EVT, void>::callback_type callbackToErase) const
353  {
355  std::mem_fun_ref<bool, invoker_base_type, void (*)(int)>(&invoker_base_type::isCallbackEqualTo);
356  observers_.erase_if( std::bind2nd(comparator, callbackToErase) );
357  }
358 
360  void propagate(int timestamp) const
361  {
362  std::mem_fun1_ref_t<void, invoker_base_type, int> trigger = std::mem_fun_ref(&invoker_base_type::trigger);
363  std::for_each(observers_.begin(), observers_.end(), std::bind2nd(trigger, timestamp));
364  }
365 
366  void propagate() const { static int timestamp = 0; propagate(++timestamp); }
367 
368  private:
369  mutable boost::ptr_vector<invoker_base_type> observers_;
370  };
371 }
372 
373 #endif
374 
375 // cmake:sourcegroup=utils
SubjectBase< EVT > subject_type
void(observer_base_type::* member_callback_type)(int)
virtual boost::any getCallback()=0
SubjectBaseTraitsBase< EVT >::invoker_base_type invoker_base_type
Invoker< void, EVT, false > invoker_type
void connect(typename SubjectBaseTraits< EVT, void >::callback_type newCallback) const
Call this method to register a free function as a callback.
InvokerBase< EVT > invoker_base_type
void connect(T &object, typename SubjectBaseTraits< EVT, T >::callback_type newCallback) const
Call this method to register a non-static method as a callback.
void(* free_callback_type)(int)
Optimization-based Robot Controller namespace. a library of classes to write and solve optimization p...
bool isObserverEqualTo(std::pair< T *, void(T::*)(int)> observer)
bool isCallbackEqualTo(void(*callback)(int))
std::mem_fun1_ref_t< bool, invoker_base_type, invoker_id_type > invoker_comparator_type
std::mem_fun1_ref_t< bool, invoker_base_type, invoker_id_type > invoker_comparator_type
virtual void * getObject()=0
void disconnect(T &object, typename SubjectBaseTraits< EVT, T >::callback_type callback) const
Disconnect non-static method.
ObserverBase< EVT > observer_base_type
Invoker(T &object, void(T::*callback)(int))
bool isCallbackEqualTo(void(T::*callback)(int))
Base class for objects who can raise events,.
void disconnect(typename SubjectBaseTraits< EVT, void >::callback_type callbackToErase) const
Disconnect free function.
InvokerBase< EVT > invoker_type
void propagate(int timestamp) const
Base class for Observers with propagation system.
virtual void trigger(int timestamp)=0
Invoker(T &object, void(T::*callback)(int))
std::pair< T *, callback_type > invoker_id_type
void bind(subject_type &subject)
Call this method to automatically propagate observed events to observers connected to the subject giv...
SubjectBaseTraitsBase< EVT >::invoker_base_type invoker_base_type
void stopPropagation()
Call this method from your callbacks to avoid propagation to the bound subject (if any)...
Invoker< T, EVT, boost::is_base_of< ObserverBase< EVT >, T >::value > invoker_type