OpenLexocad  27.0
Observer.h
Go to the documentation of this file.
1 #ifndef __OBSERVER_H__
2 #define __OBSERVER_H__
3 
4 
5 #include <Base/Timer.h>
6 
7 
8 #include <assert.h>
9 
10 #include <iostream>
11 #include <list>
12 #include <set>
13 #include <vector>
14 
15 namespace Base
16 {
17 template <class _MessageType>
18 class Subject;
19 
27 template <class _MessageType>
28 class Observer
29 {
30 public:
36  : _observerPriority(1) // default priority
37  {
38 
39  };
40 
45  virtual ~Observer()
46  {
47  cDebug("~Observer %s %x", this->name() ? this->name() : "No Name", this);
48  if (!_subjects.empty())
49  {
50  auto copy_subjects = _subjects;
51  cWarn("Observer %s %x is not detached!!!!", this->name() ? this->name() : "No Name", this);
52  for (auto s : copy_subjects)
53  s->detach(this);
54  }
55  val = 0xDEADBEEF;
56  };
57 
58 
59 
65  virtual void onChange(Subject<_MessageType>* rCaller, _MessageType rcReason) = 0;
66 
72  virtual void onDestroy(Subject<_MessageType>& /*rCaller*/) {}
73 
79  virtual const char* name(void) { return "<no name>"; }
80 
84  void setObserverPriority(int priority) { _observerPriority = priority; }
85  inline int getObserverPriority() const { return _observerPriority; }
86 
87  void setAttached(Subject<_MessageType>* t) { _subjects.push_back(t); };
89  {
90  _subjects.erase( std::find( _subjects.begin(), _subjects.end(), t ));
91  //_subjects.erase(std::remove(_subjects.begin(), _subjects.end(), t),_subjects.end());
92  };
93 
94 private:
95  long val = 0xBADEAFFE;
96  std::vector<Subject<_MessageType>*> _subjects;
97  int _observerPriority;
98 };
99 
100 
108 template <class _MessageType>
109 class Subject
110 {
111 public:
113  typedef _MessageType MessageType;
115 
117  {
118  ObserverHolder() = default;
119  ObserverHolder(ObserverType* aobserverPtr) :observerPtr(aobserverPtr),observerPriority(aobserverPtr->getObserverPriority()), isAttached(true) { }
122  mutable bool isAttached;
123  };
124 
125 
126 
131  Subject() : _running_notify{false} { };
132 
137  virtual ~Subject()
138  {
139 
140  if( _running_notify )
141  {
142  cWarn("FATAL ERROR, ~Subject %X call while running notify!" );
143  cDebuggerBreak("FATAL ERROR ~Subject call running notify!");
144  }
145 
146  if( _ObserverSet.size() != 0 )
147  {
148  cWarn("Not detached all observers yet" );
149  }
150  }
151 
159  {
160 
161  ToObserv->setAttached(this);
162 
163  std::string name = ToObserv->name() ? ToObserv->name() : "No Name";
164  std::ostringstream oss;
165  oss << " " << ToObserv;
166  name += oss.str();
167 
168  if( _running_notify )
169  {
170  cDebug("Subject %x, attach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
171  _ObserverSet_AddedLater.insert(ObserverHolder(ToObserv));
172  }
173 
174  if( _ObserverSet.find(ToObserv) == _ObserverSet.end() )
175  {
176  cDebug("Subject %x, attach Observer %s %X ",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
177  _ObserverSet.insert(ObserverHolder(ToObserv));
178  }
179  else
180  {
181  cWarn("Subject %x, attach Observer %s %X already attached",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
182  _ObserverSet.insert(ObserverHolder(ToObserv));
183  }
184  }
185 
193  {
194  cDebug("DETACH 0x%X",ToObserv);
195  if( _running_notify )
196  {
197  ObserverSetType::iterator it = _ObserverSet.find(ObserverHolder(ToObserv));
198  if( it != _ObserverSet.end() )
199  {
200  cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
201  (*it).isAttached = false;
202  }
203 
204  auto it2 = _ObserverSet_AddedLater.find(ObserverHolder(ToObserv));
205  if( it2 != _ObserverSet_AddedLater.end() )
206  {
207  cWarn("**** Subject %x, detach Observer %s %X while running notify",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
208  (*it2).isAttached = false;
209  }
210 
211  }
212  else
213  {
214  if (_ObserverSet.find(ToObserv) != _ObserverSet.end())
215  {
216  cDebug("Subject %x, detach Observer %s %X",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
217  ToObserv->setDetached(this);
218  _ObserverSet.erase(ToObserv);
219  }
220  else
221  {
222  cWarn("Subject %x, detach Observer %s %X not found",this, ToObserv->name() ? ToObserv->name() : "No Name", ToObserv);
223  }
224  }
225 
226  }
227 
231  void detachAll()
232  {
233  auto observerSetCopy = _ObserverSet;
234  for (auto observer : observerSetCopy)
235  {
236  if( observer.isAttached )
237  observer.observerPtr->setDetached(this);
238  }
239 
240  auto observerSet_AddedLater_Copy = _ObserverSet_AddedLater;
241  for (auto observer : observerSet_AddedLater_Copy)
242  {
243  if( observer.isAttached )
244  observer.observerPtr->setDetached(this);
245  }
246 
247  _ObserverSet.clear();
248  _ObserverSet_AddedLater.clear();
249  }
250 
258  void notify_internal(_MessageType& rcReason, size_t deep)
259  {
260  if( deep > 10 )
261  {
262  cWarn("ERROR notify_internal, to deep recursion!");
263  cDebuggerBreak("ERROR notify_internal, to deep recursion!");
264  return;
265  }
266 
268  {
269  // Was detached, maybe in another observer.
270  if( !observer.isAttached )
271  continue;
272 
274  {
275  // 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
276  std::string observerName = (observer.observerPtr)->name() ? (observer.observerPtr)->name() : "<no Name>";
277 
278  Base::Timer t;
279  (observer.observerPtr)->onChange(this, rcReason); // send OnChange-signal
280  auto myt = t.elapsedMS();
281 
282  if (_observerTime.find(observerName) == _observerTime.end())
283  _observerTime[observerName] = myt;
284  else
285  _observerTime[observerName] += myt;
286 
287  if (myt > 50)
288  cWarn(" Observer (%s) need %f ms", observerName.c_str(), t.elapsedMS());
289  else if (myt > 5)
290  cDebug(" Observer (%s) need %f ms", observerName.c_str(), t.elapsedMS());
291  }
292  else
293  {
294  (observer.observerPtr)->onChange(this, rcReason); // send OnChange-signal
295  }
296 
297  }
298 
299 
300  // Is a Observer attached while notify?
301  int counter = 10;
302  while( !_ObserverSet_AddedLater.empty() )
303  {
304  auto copy_ObserverSet_AddedLater = getObserverSortedByPriority(_ObserverSet_AddedLater);
305  _ObserverSet_AddedLater.clear();
306  for (auto observer : copy_ObserverSet_AddedLater)
307  {
308  if( observer.isAttached )
309  observer.observerPtr->onChange(this, rcReason); // send OnChange-signal
310  _ObserverSet.insert(observer);
311  }
312 
313  if( (counter--) <= 0 )
314  {
315  cWarn("ERROR _ObserverSet_AddedLater, to many repeats!");
316  cDebuggerBreak("ERROR notify_internal, to deep recursion!");
317  break;
318  }
319  }
320 
321  // Now process the messages we got while running notify...
322  auto copy_messages_WhileRunningNotify = _messages_WhileRunningNotify;
324  for(auto &message : copy_messages_WhileRunningNotify )
325  {
326  notify_internal( message, deep+1 );
327  }
328 
329  }
330 
331  void notify(_MessageType& rcReason)
332  {
333  if (_running_notify)
334  {
335  _messages_WhileRunningNotify.push_back(rcReason);
336  return;
337  }
338  _running_notify = true;
339  notify_internal(rcReason, 1);
340  _running_notify = false;
341  }
342 
347  Observer<_MessageType>* get(const char* Name)
348  {
349  const char* OName;
350  for (auto observer : _ObserverSet)
351  {
352 
353  OName = observer.observerPtr->name(); // get the name
354  if (OName && strcmp(OName, Name) == 0)
355  return observer.observerPtr;
356  }
357 
358  return nullptr;
359  }
360 
361  std::vector<Observer<_MessageType>*> getAll()
362  {
363  std::vector<Observer<_MessageType>*> ret;
364  for (auto observer : _ObserverSet)
365  {
366  ret.push_back(observer.observerPtr);
367  }
368  return ret;
369 
370  }
371 
372  virtual const char* subject_name(void) { return "NO SUBJECT NAME"; }
373 
374  void resetObserverTime() { _observerTime.clear(); }
375 
376  std::map<std::string, double> getObserverTime() { return _observerTime; }
377 
378 
379 
380 
381 protected:
382 
383 
384  // Compare observers according priority. Higher priority first.
386  {
387  bool operator()(const ObserverHolder& o1, const ObserverHolder& o2) const
388  {
389  return o1.observerPtr < o2.observerPtr;
390  }
391  };
392 
393 
394  typedef std::set<ObserverHolder, CompareObservers> ObserverSetType;
395 
396  std::vector<ObserverHolder> getObserverSortedByPriority( const ObserverSetType& obs )
397  {
398  std::vector<ObserverHolder> ret( obs.begin(), obs.end() ) ;
399 
400  std::sort(ret.begin(), ret.end(), [](const ObserverHolder& a,const ObserverHolder& b)
401  { return a.observerPriority < b.observerPriority; });
402 
403  return ret;
404  }
405 
409  std::list<_MessageType> _messages_WhileRunningNotify;
410  std::map<std::string, double> _observerTime;
411 };
412 
413 
414 } // namespace Base
415 
416 
417 #endif // __OBSERVER_H__
std::map< std::string, double > _observerTime
Definition: Observer.h:410
void detach(Observer< _MessageType > *ToObserv)
Definition: Observer.h:192
ObserverHolder(ObserverType *aobserverPtr)
Definition: Observer.h:119
CORE_EXPORT Core::LogClass cWarn()
void notify(_MessageType &rcReason)
Definition: Observer.h:331
virtual ~Subject()
Definition: Observer.h:137
Observer< _MessageType > ObserverType
Definition: Observer.h:112
CORE_EXPORT void cDebuggerBreak(char *message)
void notify_internal(_MessageType &rcReason, size_t deep)
Definition: Observer.h:258
CORE_EXPORT Core::LogClass cDebug()
Definition: Observer.h:28
Observer< _MessageType > * get(const char *Name)
Definition: Observer.h:347
void attach(Observer< _MessageType > *ToObserv)
Definition: Observer.h:158
Core::PropertyText name
Definition: CoreDocument.h:143
_MessageType MessageType
Definition: Observer.h:113
void setAttached(Subject< _MessageType > *t)
Definition: Observer.h:87
std::set< ObserverHolder, CompareObservers > ObserverSetType
Definition: Observer.h:394
Definition: Observer.h:18
int getObserverPriority() const
Definition: Observer.h:85
Definition: Observer.h:116
ObserverSetType _ObserverSet_AddedLater
Set of attached observers.
Definition: Observer.h:407
std::vector< Observer< _MessageType > * > getAll()
Definition: Observer.h:361
Observer()
Definition: Observer.h:35
ObserverType * observerPtr
Definition: Observer.h:120
Definition: Log.h:26
int observerPriority
Definition: Observer.h:121
std::map< std::string, double > getObserverTime()
Definition: Observer.h:376
basic_observer< entity > observer
Alias declaration for the most common use case.
Definition: entt.hpp:3793
bool _running_notify
Set of attached observers at running notify.
Definition: Observer.h:408
Subject()
Definition: Observer.h:131
void setObserverPriority(int priority)
Definition: Observer.h:84
Subject< _MessageType > SubjectType
Definition: Observer.h:114
virtual ~Observer()
Definition: Observer.h:45
bool isAttached
Definition: Observer.h:122
Definition: Observer.h:385
Definition: AbstractXMLReader.h:8
std::list< _MessageType > _messages_WhileRunningNotify
Definition: Observer.h:409
virtual void onDestroy(Subject< _MessageType > &)
Definition: Observer.h:72
std::vector< ObserverHolder > getObserverSortedByPriority(const ObserverSetType &obs)
Definition: Observer.h:396
virtual void onChange(Subject< _MessageType > *rCaller, _MessageType rcReason)=0
void setDetached(Subject< _MessageType > *t)
Definition: Observer.h:88
CORE_EXPORT LOGLEVEL getLogLevel()
virtual const char * name(void)
Definition: Observer.h:79
ObserverSetType _ObserverSet
Definition: Observer.h:406
void resetObserverTime()
Definition: Observer.h:374
bool operator()(const ObserverHolder &o1, const ObserverHolder &o2) const
Definition: Observer.h:387
void detachAll()
Definition: Observer.h:231
virtual const char * subject_name(void)
Definition: Observer.h:372