OpenLexocad  28.0
Observer.h
Go to the documentation of this file.
1 #pragma once
2 #include <Base/Timer.h>
3 #include <Base/Log.h>
4 #include <sstream>
5 
6 namespace Base
7 {
8 template <class _MessageType>
9 class Subject;
10 
18 template <class _MessageType>
19 class Observer
20 {
21 public:
26  Observer(int observerPriority = 1)
27  : _observerPriority(observerPriority)
28  {
29 
30  };
31 
36  virtual ~Observer()
37  {
38  cDebug("~Observer %s %x", this->name() ? this->name() : "No Name", this);
39  if (!_subjects.empty())
40  {
41  auto copy_subjects = _subjects;
42  cWarn("Observer %s %x is not detached!!!!", this->name() ? this->name() : "No Name", this);
43  for (auto s : copy_subjects)
44  s->detach(this);
45  }
46  __deadVal = 0xDEADBEEF;
47  };
48 
49 
50 
56  virtual void onChange(Subject<_MessageType>* rCaller, _MessageType rcReason) = 0;
57 
63  virtual void onDestroy(Subject<_MessageType>& /*rCaller*/) {}
64 
70  virtual const char* name(void) { return "<no name>"; }
71 
75  inline int getObserverPriority() const { return _observerPriority; }
76 
78  {
79  auto it = std::find(_subjects.begin(), _subjects.end(), t);
80  if (it == _subjects.end())
81  _subjects.push_back(t);
82  else
83  cWarn("Observer is already attached.");
84  };
86  {
87  auto it = std::find(_subjects.begin(), _subjects.end(), t);
88  if (it != _subjects.end())
89  _subjects.erase(it);
90  else
91  cWarn("Observer is already detached.");
92  //_subjects.erase(std::remove(_subjects.begin(), _subjects.end(), t),_subjects.end());
93  };
94 
95  long __deadVal = 0xBADEAFFE;
96 private:
97 
98  std::vector<Subject<_MessageType>*> _subjects;
99  int _observerPriority;
100 };
101 
102 
110 template <class _MessageType>
111 class Subject
112 {
113 public:
115  typedef _MessageType MessageType;
117 
119  {
120  ObserverHolder() = default;
122  : observerPtr(aobserverPtr), observerPriority(aobserverPtr->getObserverPriority()), isAttached(true) /*, isDeleted(false)*/
123  {
124  }
127  mutable bool isAttached;
128  //mutable bool isDeleted;
129  };
130 
131 
132 
137  Subject() : _running_notify{false} { };
138 
143  virtual ~Subject()
144  {
145 
146  if( _running_notify )
147  {
148  cWarn("FATAL ERROR, ~Subject %X call while running notify!" );
149  cDebuggerBreak("FATAL ERROR ~Subject call running notify!");
150  }
151 
152  if (!_ObserverSet.empty())
153  {
154  cWarn("Not detached all observers yet" );
155  }
156  }
157 
165  {
166  if( ToObserv->__deadVal != 0xBADEAFFE )
167  {
168  cWarn("Subject try to attach a deleted Observer");
169  return;
170  }
171 
172  ToObserv->setAttached(this);
173 
174  std::string name = ToObserv->name() ? ToObserv->name() : "No Name";
175  std::ostringstream oss;
176  oss << " " << ToObserv;
177  name += oss.str();
178 
179  if( _running_notify )
180  {
181  if (_ObserverSet_AddedLaterCopy.find(ToObserv) != _ObserverSet_AddedLaterCopy.end())
182  {
183  cWarn("Subject %x, attach Observer %s %X while running notify already attached", this,
184  ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
185  }
186  else
187  {
188  auto ret = _ObserverSet_AddedLater.insert(ObserverHolder(ToObserv));
189  if (ret.second)
190  {
191  cDebug("Subject %x, attach Observer %s %X while running notify", this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
192  }
193  else
194  {
195  cWarn("Subject %x, attach Observer %s %X while running notify already attached", this,
196  ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
197  }
198  }
199  }
200  else
201  {
202  auto ret = _ObserverSet.insert(ObserverHolder(ToObserv));
203  if(ret.second)
204  {
205  cDebug("Subject %x, attach Observer %s %X ",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
206  }
207  else
208  {
209  cWarn("Subject %x, attach Observer %s %X already attached",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
210  }
211  }
212 
213 
214  }
215 
223  {
224  cDebug("DETACH 0x%X",ToObserv);
225  ToObserv->setDetached(this);
226  if( _running_notify )
227  {
228  auto it = _ObserverSet.find(ObserverHolder(ToObserv));
229  if( it != _ObserverSet.end() )
230  {
231  cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
232  (*it).isAttached = false;
233  }
234 
235  auto it2 = _ObserverSet_AddedLater.find(ObserverHolder(ToObserv));
236  if( it2 != _ObserverSet_AddedLater.end() )
237  {
238  cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
239  (*it2).isAttached = false;
240  }
241 
242  auto it3 = _ObserverSet_AddedLaterCopy.find(ObserverHolder(ToObserv));
243  if (it3 != _ObserverSet_AddedLaterCopy.end())
244  {
245  cWarn("**** Subject %x, detach Observer %s %X while running notify", this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
246  (*it2).isAttached = false;
247  }
248 
249  }
250  else
251  {
252  if (_ObserverSet.find(ToObserv) != _ObserverSet.end())
253  {
254  cDebug("Subject %x, detach Observer %s %X",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
255  _ObserverSet.erase(ToObserv);
256  }
257  else
258  {
259  cWarn("Subject %x, detach Observer %s %X not found",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
260  }
261  }
262 
263  }
264 
265  //void observerDeleted(Observer<_MessageType>* ToObserv)
266  //{
267  // auto it = _ObserverSet.find(ObserverHolder(ToObserv));
268  // if( it != _ObserverSet.end() )
269  // {
270  // cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
271  // (*it).isDeleted = true;
272  // }
273  // auto it2 = _ObserverSet_AddedLater.find(ObserverHolder(ToObserv));
274  // if( it2 != _ObserverSet_AddedLater.end() )
275  // {
276  // cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
277  // (*it2).isDeleted = true;
278  // }
279  //
280  //}
281 
285  void detachAll()
286  {
287  if (_running_notify)
289 
290  for (const auto& observer : _ObserverSet)
291  {
292  if( observer.isAttached )
293  observer.observerPtr->setDetached(this);
294  }
295 
296  for (const auto& observer : _ObserverSet_AddedLater)
297  {
298  if( observer.isAttached )
299  observer.observerPtr->setDetached(this);
300  }
301 
302  for (const auto& observer : _ObserverSet_AddedLaterCopy)
303  {
304  if (observer.isAttached)
305  observer.observerPtr->setDetached(this);
306  }
307 
308  _ObserverSet.clear();
309  _ObserverSet_AddedLater.clear();
311  }
312 
320  void notify_internal(_MessageType& rcReason, size_t deep)
321  {
322  if( deep > 10 )
323  {
324  cWarn("ERROR notify_internal, to deep recursion!");
325  cDebuggerBreak("ERROR notify_internal, to deep recursion!");
326  return;
327  }
328 
329  for (const auto& observer : _ObserverSet)
330  {
331  // Was detached, maybe in another observer.
332  if( !observer.isAttached )
333  continue;
334 
336  {
337  // store name here, maybe it is possible, that observer will be deleted in onChange method, so we do not want to access Iter->first after that
338  std::string observerName = (observer.observerPtr)->name() ? (observer.observerPtr)->name() : "<no Name>";
339 
340  Base::Timer t;
341  (observer.observerPtr)->onChange(this, rcReason); // send OnChange-signal
343  {
345  break;
346  }
347 
348  auto myt = t.elapsedMS();
349 
350  if (_observerTime.find(observerName) == _observerTime.end())
351  _observerTime[observerName] = myt;
352  else
353  _observerTime[observerName] += myt;
354 
355  if (myt > 50)
356  cWarn(" Observer (%s) need %f ms", observerName.c_str(), t.elapsedMS());
357  else if (myt > 5)
358  cDebug(" Observer (%s) need %f ms", observerName.c_str(), t.elapsedMS());
359  }
360  else
361  {
362  if (observer.observerPtr->__deadVal == 0xBADEAFFE)
363  {
364  (observer.observerPtr)->onChange(this, rcReason); // send OnChange-signal
366  {
368  break;
369  }
370  }
371  else
372  cWarn("Urgg deleted observer");
373  }
374 
375  }
376 
377 
378  // Is a Observer attached while notify?
379  int counter = 10;
380  while( !_ObserverSet_AddedLater.empty() )
381  {
384  for (const auto& observer : _ObserverSet_AddedLaterCopy)
385  {
386  if (observer.isAttached)
387  {
388  if (observer.observerPtr->__deadVal == 0xBADEAFFE)
389  {
390  (observer.observerPtr)->onChange(this, rcReason); // send OnChange-signal
392  break;
393  _ObserverSet.insert(observer);
394  }
395  else
396  cWarn("Urgg deleted observer");
397  }
398  }
399 
401 
403  {
405  break;
406  }
407 
408  if( (counter--) <= 0 )
409  {
410  cWarn("ERROR _ObserverSet_AddedLater, to many repeats!");
411  cDebuggerBreak("ERROR notify_internal, to deep recursion!");
412  break;
413  }
414  }
415 
416  // Now process the messages we got while running notify...
417  auto copy_messages_WhileRunningNotify = _messages_WhileRunningNotify;
419  for(auto &message : copy_messages_WhileRunningNotify )
420  {
421  notify_internal( message, deep+1 );
422  }
423 
424  }
425 
426  void notify(_MessageType& rcReason)
427  {
428  if (_running_notify)
429  {
430  _messages_WhileRunningNotify.push_back(rcReason);
431  return;
432  }
433  _running_notify = true;
434  notify_internal(rcReason, 1);
435  _running_notify = false;
437 
438  auto observerSetCopy = _ObserverSet;
439  for (auto observer : observerSetCopy)
440  {
441  if( !observer.isAttached )
442  _ObserverSet.erase( observer );
443  }
444 
445  }
446 
451  Observer<_MessageType>* get(const char* Name)
452  {
453  const char* OName;
454  for (auto observer : _ObserverSet)
455  {
456 
457  OName = observer.observerPtr->name(); // get the name
458  if (OName && strcmp(OName, Name) == 0)
459  return observer.observerPtr;
460  }
461 
462  return nullptr;
463  }
464 
465  // std::vector<Observer<_MessageType>*> getAll()
466  //{
467  // std::vector<Observer<_MessageType>*> ret;
468  // for (auto observer : _ObserverSet)
469  // {
470  // ret.push_back(observer.observerPtr);
471  // }
472  // return ret;
473  //
474  //}
475 
476  virtual const char* subject_name(void) { return "NO SUBJECT NAME"; }
477 
478  void resetObserverTime() { _observerTime.clear(); }
479 
480  std::map<std::string, double> getObserverTime() { return _observerTime; }
481 
482 
483 
484 
485 protected:
486 
487 
488  // Compare observers according priority. Higher priority first.
490  {
491  bool operator()(const ObserverHolder& o1, const ObserverHolder& o2) const
492  {
493  if (o1.observerPriority == o2.observerPriority)
494  return o1.observerPtr < o2.observerPtr;
495  else
496  return o1.observerPriority > o2.observerPriority;
497  }
498  };
499 
500 
501  typedef std::set<ObserverHolder, CompareObservers> ObserverSetType;
502 
503  //std::vector<ObserverHolder> getObserverSortedByPriority( const ObserverSetType& obs )
504  //{
505  // std::vector<ObserverHolder> ret( obs.begin(), obs.end() ) ;
506  //
507  // std::sort(ret.begin(), ret.end(), [](const ObserverHolder& a,const ObserverHolder& b)
508  // { return a.observerPriority > b.observerPriority; });
509  //
510  // return ret;
511  //}
512 
516 
519  std::list<_MessageType> _messages_WhileRunningNotify;
520  std::map<std::string, double> _observerTime;
521 };
522 
523 
524 } // namespace Base
Base::Subject::subject_name
virtual const char * subject_name(void)
Definition: Observer.h:476
Base::Subject::detach
void detach(Observer< _MessageType > *ToObserv)
Definition: Observer.h:222
Base::Observer
Definition: Observer.h:20
Base::getLogLevel
LX_BASE_EXPORT LOGLEVEL getLogLevel()
Base::Subject::~Subject
virtual ~Subject()
Definition: Observer.h:143
Base::Subject::ObserverHolder::ObserverHolder
ObserverHolder(ObserverType *aobserverPtr)
Definition: Observer.h:121
cWarn
LX_BASE_EXPORT Base::LogClass cWarn()
entt::observer
basic_observer< entity > observer
Alias declaration for the most common use case.
Definition: entt.hpp:3793
Base::Subject::ObserverType
Observer< _MessageType > ObserverType
Definition: Observer.h:114
Base::Subject::ObserverSetType
std::set< ObserverHolder, CompareObservers > ObserverSetType
Definition: Observer.h:501
cDebug
LX_BASE_EXPORT Base::LogClass cDebug()
Base::Subject::MessageType
_MessageType MessageType
Definition: Observer.h:115
Base::Observer::getObserverPriority
int getObserverPriority() const
Definition: Observer.h:75
Base::Subject::notify_internal
void notify_internal(_MessageType &rcReason, size_t deep)
Definition: Observer.h:320
Base::Subject::get
Observer< _MessageType > * get(const char *Name)
Definition: Observer.h:451
Timer.h
Base::Subject::attach
void attach(Observer< _MessageType > *ToObserv)
Definition: Observer.h:164
Base::Subject::ObserverHolder::ObserverHolder
ObserverHolder()=default
Base::Subject::getObserverTime
std::map< std::string, double > getObserverTime()
Definition: Observer.h:480
Base::Subject::_ObserverSet_AddedLaterCopy
ObserverSetType _ObserverSet_AddedLaterCopy
Set of attached observers at running notify.
Definition: Observer.h:515
Base::Subject::_running_notify
bool _running_notify
Definition: Observer.h:517
Base::Subject::Subject
Subject()
Definition: Observer.h:137
cDebuggerBreak
LX_BASE_EXPORT void cDebuggerBreak(const char *message)
Base::Observer::setAttached
void setAttached(Subject< _MessageType > *t)
Definition: Observer.h:77
Base::Subject::_ObserverSet_AddedLater
ObserverSetType _ObserverSet_AddedLater
Set of attached observers.
Definition: Observer.h:514
Base::Subject::SubjectType
Subject< _MessageType > SubjectType
Definition: Observer.h:116
Base::Observer::setDetached
void setDetached(Subject< _MessageType > *t)
Definition: Observer.h:85
Base::Subject::ObserverHolder::observerPtr
ObserverType * observerPtr
Definition: Observer.h:125
Base::Observer::__deadVal
long __deadVal
Definition: Observer.h:95
Base::Subject::_allDetachedWhileRunningNotify
bool _allDetachedWhileRunningNotify
Definition: Observer.h:518
Base::Observer::name
virtual const char * name(void)
Definition: Observer.h:70
Base::Subject::ObserverHolder::observerPriority
int observerPriority
Definition: Observer.h:126
Base::Observer::onChange
virtual void onChange(Subject< _MessageType > *rCaller, _MessageType rcReason)=0
Base::Subject::_messages_WhileRunningNotify
std::list< _MessageType > _messages_WhileRunningNotify
Definition: Observer.h:519
Base::Subject::detachAll
void detachAll()
Definition: Observer.h:285
Base::Subject::CompareObservers::operator()
bool operator()(const ObserverHolder &o1, const ObserverHolder &o2) const
Definition: Observer.h:491
Base::Subject::ObserverHolder::isAttached
bool isAttached
Definition: Observer.h:127
Base::Subject
Definition: Observer.h:9
Base::Subject::_ObserverSet
ObserverSetType _ObserverSet
Definition: Observer.h:513
Base::Subject::_observerTime
std::map< std::string, double > _observerTime
Definition: Observer.h:520
Base::Observer::Observer
Observer(int observerPriority=1)
Definition: Observer.h:26
Base::D_DEBUG
@ D_DEBUG
Definition: Log.h:18
Base::Subject::ObserverHolder
Definition: Observer.h:119
Base::Subject::notify
void notify(_MessageType &rcReason)
Definition: Observer.h:426
Base::Subject::CompareObservers
Definition: Observer.h:490
Base::Observer::onDestroy
virtual void onDestroy(Subject< _MessageType > &)
Definition: Observer.h:63
Log.h
Base::Subject::resetObserverTime
void resetObserverTime()
Definition: Observer.h:478
Base
Definition: AbstractXMLReader.h:5
Base::Observer::~Observer
virtual ~Observer()
Definition: Observer.h:36