source: src/Patterns/Observer.cpp@ 456e78

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 456e78 was bcf653, checked in by Frederik Heber <heber@…>, 14 years ago

Added copyright note to each .cpp file and an extensive one to builder.cpp.

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * Observer.cpp
10 *
11 * Created on: Jan 19, 2010
12 * Author: crueger
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "Helpers/MemDebug.hpp"
21
22#include "Observer.hpp"
23
24#include <iostream>
25
26#include "Helpers/Assert.hpp"
27#include "Helpers/MemDebug.hpp"
28
29using namespace std;
30
31/****************** Static stuff for the observer mechanism ************/
32
33// All infrastructure for the observer-pattern is bundled at a central place
34// this is more efficient if many objects can be observed (inherit from observable)
35// but only few are actually coupled with observers. E.g. TMV has over 500.000 Atoms,
36// which might become observable. Handling Observerable infrastructure in each of
37// these would use memory for each atom. By handling Observer-infrastructure
38// here we only need memory for objects that actually are observed.
39// See [Gamma et al, 1995] p. 297
40
41map<Observable*, int> Observable::depth; //!< Map of Observables to the depth of the DAG of Observers
42map<Observable*,multimap<int,Observer*> > Observable::callTable; //!< Table for each Observable of all its Observers
43std::map<Observable*,std::set<Notification*> > Observable::notifications;
44set<Observable*> Observable::busyObservables; //!< Set of Observables that are currently busy notifying their sign-on'ed Observers
45
46/** Attaching Sub-observables to Observables.
47 * Increases entry in Observable::depth for this \a *publisher by one.
48 *
49 * The two functions \sa start_observer_internal() and \sa finish_observer_internal()
50 * have to be used together at all time. Never use these functions directly
51 * START_OBSERVER and FINISH_OBSERVER also construct a bogus while(0) loop
52 * thus producing compiler-errors whenever only one is used.
53 * \param *publisher reference of sub-observable
54 */
55void Observable::start_observer_internal(Observable *publisher){
56 // increase the count for this observable by one
57 // if no entry for this observable is found, an new one is created
58 // by the STL and initialized to 0 (see STL documentation)
59#ifdef LOG_OBSERVER
60 observerLog().addMessage(depth[publisher]) << ">> Locking " << observerLog().getName(publisher) << endl;
61#endif
62 depth[publisher]++;
63}
64
65/** Detaching Sub-observables from Observables.
66 * Decreases entry in Observable::depth for this \a *publisher by one. If zero, we
67 * start notifying all our Observers.
68 *
69 * The two functions start_observer_internal() and finish_observer_internal()
70 * have to be used together at all time. Never use these functions directly
71 * START_OBSERVER and FINISH_OBSERVER also construct a bogus while(0) loop
72 * thus producing compiler-errors whenever only one is used.
73 * \param *publisher reference of sub-observable
74 */
75void Observable::finish_observer_internal(Observable *publisher){
76 // decrease the count for this observable
77 // if zero is reached all observed blocks are done and we can
78 // start to notify our observers
79 --depth[publisher];
80#ifdef LOG_OBSERVER
81 observerLog().addMessage(depth[publisher]) << "<< Unlocking " << observerLog().getName(publisher) << endl;
82#endif
83 if(depth[publisher]){}
84 else{
85 publisher->notifyAll();
86 // this item is done, so we don't have to keep the count with us
87 // save some memory by erasing it
88 depth.erase(publisher);
89 }
90}
91
92void Observable::enque_notification_internal(Observable *publisher, Notification_ptr notification){
93 ASSERT(notification->owner==publisher,"Some object tried to send a notification it does not own");
94 notifications[publisher].insert(notification);
95}
96
97/** Constructor for Observable Protector.
98 * Basically, calls start_observer_internal(). Hence use this class instead of
99 * calling the function directly.
100 *
101 * \param *protege Observable to be protected.
102 */
103Observable::_Observable_protector::_Observable_protector(Observable *_protege) :
104 protege(_protege)
105{
106 start_observer_internal(protege);
107}
108
109Observable::_Observable_protector::_Observable_protector(const _Observable_protector &dest) :
110 protege(dest.protege)
111{
112 start_observer_internal(protege);
113}
114
115/** Destructor for Observable Protector.
116 * Basically, calls finish_observer_internal(). Hence use this class instead of
117 * calling the function directly.
118 *
119 * \param *protege Observable to be protected.
120 */
121Observable::_Observable_protector::~_Observable_protector()
122{
123 finish_observer_internal(protege);
124}
125
126/************* Notification mechanism for observables **************/
127
128/** Notify all Observers of changes.
129 * Puts \a *this into Observable::busyObservables, calls Observer::update() for all in callee_t
130 * and removes from busy list.
131 */
132void Observable::notifyAll() {
133 // we are busy notifying others right now
134 // add ourselves to the list of busy subjects to enable circle detection
135 busyObservables.insert(this);
136 // see if anyone has signed up for observation
137 // and call all observers
138 try {
139 if(callTable.count(this)) {
140 // elements are stored sorted by keys in the multimap
141 // so iterating over it gives us a the callees sorted by
142 // the priorities
143 callees_t callees = callTable[this];
144 callees_t::iterator iter;
145 for(iter=callees.begin();iter!=callees.end();++iter){
146#ifdef LOG_OBSERVER
147 observerLog().addMessage() << "-> Sending update from " << observerLog().getName(this)
148 << " to " << observerLog().getName((*iter).second)
149 << " (priority=" << (*iter).first << ")"<< endl;
150#endif
151 (*iter).second->update(this);
152 }
153 }
154 }
155 ASSERT_NOCATCH("Exception thrown from Observer Update");
156
157 // send out all notifications that need to be done
158
159 notificationSet currentNotifications = notifications[this];
160 for(notificationSet::iterator it = currentNotifications.begin();
161 it != currentNotifications.end();++it){
162 (*it)->notifyAll();
163 }
164
165 notifications.erase(this);
166
167 // done with notification, we can leave the set of busy subjects
168 busyObservables.erase(this);
169}
170
171
172/** Handles passing on updates from sub-Observables.
173 * Mimicks basically the Observer::update() function.
174 *
175 * \param *publisher The \a *this we observe.
176 */
177void Observable::update(Observable *publisher) {
178 // circle detection
179 if(busyObservables.find(this)!=busyObservables.end()) {
180 // somehow a circle was introduced... we were busy notifying our
181 // observers, but still we are called by one of our sub-Observables
182 // we cannot be sure observation will still work at this point
183 ASSERT(0,"Circle detected in observation-graph.\n"
184 "Observation-graph always needs to be a DAG to work correctly!\n"
185 "Please check your observation code and fix this!\n");
186 return;
187 }
188 else {
189 // see if we are in the process of changing ourselves
190 // if we are changing ourselves at the same time our sub-observables change
191 // we do not need to publish all the changes at each time we are called
192 if(depth.find(this)==depth.end()) {
193#ifdef LOG_OBSERVER
194 observerLog().addMessage() << "-* Update from " << observerLog().getName(publisher)
195 << " propagated by " << observerLog().getName(this) << endl;
196#endif
197 notifyAll();
198 }
199 else{
200#ifdef LOG_OBSERVER
201 observerLog().addMessage() << "-| Update from " << observerLog().getName(publisher)
202 << " not propagated by " << observerLog().getName(this) << endl;
203#endif
204 }
205 }
206}
207
208/** Sign on an Observer to this Observable.
209 * Puts \a *target into Observable::callTable list.
210 * \param *target Observer
211 * \param priority number in [-20,20]
212 */
213void Observable::signOn(Observer *target,int priority) {
214 ASSERT(priority>=-20 && priority<=+20, "Priority out of range [-20:+20] when signing on Observer");
215#ifdef LOG_OBSERVER
216 observerLog().addMessage() << "@@ Signing on " << observerLog().getName(target) << " to " << observerLog().getName(this) << endl;
217#endif
218 bool res = false;
219 callees_t &callees = callTable[this];
220
221 callees_t::iterator iter;
222 for(iter=callees.begin();iter!=callees.end();++iter){
223 res |= ((*iter).second == target);
224 }
225 if(!res)
226 callees.insert(pair<int,Observer*>(priority,target));
227}
228
229/** Sign off an Observer from this Observable.
230 * Removes \a *target from Observable::callTable list.
231 * \param *target Observer
232 */
233void Observable::signOff(Observer *target) {
234 ASSERT(callTable.count(this),"SignOff called for an Observable without Observers.");
235#ifdef LOG_OBSERVER
236 observerLog().addMessage() << "** Signing off " << observerLog().getName(target) << " from " << observerLog().getName(this) << endl;
237#endif
238 callees_t &callees = callTable[this];
239
240 callees_t::iterator iter;
241 callees_t::iterator deliter;
242 for(iter=callees.begin();iter!=callees.end();) {
243 if((*iter).second == target) {
244 callees.erase(iter++);
245 }
246 else {
247 ++iter;
248 }
249 }
250 if(callees.empty()){
251 callTable.erase(this);
252 }
253}
254
255void Observable::signOn(Observer *target, Notification_ptr notification){
256 ASSERT(notification->owner==this,
257 "Trying to sign on for a notification that is not provided by this object");
258
259 notification->addObserver(target);
260}
261
262void Observable::signOff(Observer *target, Notification_ptr notification){
263 ASSERT(notification->owner==this,
264 "Trying to sign off from a notification that is not provided by this object");
265
266 notification->removeObserver(target);
267}
268
269bool Observable::isBlocked(){
270 return depth.count(this) > 0;
271}
272
273/** Handles sub-observables that just got killed
274 * when an sub-observerable dies we usually don't need to do anything
275 * \param *publisher Sub-Observable.
276 */
277void Observable::subjectKilled(Observable *publisher){
278}
279
280/** Constructor for class Observable.
281 */
282Observable::Observable(string name) :
283 Observer(Observer::BaseConstructor())
284{
285#ifdef LOG_OBSERVER
286 observerLog().addName(this,name);
287 observerLog().addMessage() << "++ Creating Observable " << observerLog().getName(this) << endl;
288#endif
289}
290
291/** Destructor for class Observable.
292 * When an observable is deleted, we let all our observers know. \sa Observable::subjectKilled().
293 */
294Observable::~Observable()
295{
296#ifdef LOG_OBSERVER
297 observerLog().addMessage() << "-- Destroying Observable " << observerLog().getName(this) << endl;
298#endif
299 if(callTable.count(this)) {
300 // delete all entries for this observable
301 callees_t callees = callTable[this];
302 callees_t::iterator iter;
303 for(iter=callees.begin();iter!=callees.end();++iter){
304 (*iter).second->subjectKilled(this);
305 }
306 callTable.erase(this);
307 }
308}
309
310/** Constructor for class Observer.
311 */
312Observer::Observer(string name)
313{
314#ifdef LOG_OBSERVER
315 observerLog().addName(this,name);
316 observerLog().addMessage() << "++ Creating Observer " << observerLog().getName(this) << endl;
317#endif
318}
319
320/**
321 * Base Constructor for class Observer
322 *
323 * only called from Observable Constructor
324 */
325Observer::Observer(Observer::BaseConstructor){
326#ifdef LOG_OBSERVER
327 observerLog().addObservable(this);
328#endif
329}
330
331/** Destructor for class Observer.
332 */
333Observer::~Observer()
334{
335#ifdef LOG_OBSERVER
336 if(!observerLog().isObservable(this)){
337 observerLog().addMessage() << "-- Destroying Observer " << observerLog().getName(this) << endl;
338 }
339#endif
340}
341
342/**
343 * Method for specialized notifications.
344 * Most Observers wont need or use this, so it is implemented
345 * empty in the base case;
346 */
347void Observer::recieveNotification(Observable *publisher, Notification_ptr notification){
348 ASSERT(0,"Notification received by object that did not sign on for it.");
349}
350
351Notification::Notification(Observable *_owner) :
352 owner(_owner)
353{}
354
355Notification::~Notification(){}
356
357void Notification::addObserver(Observer *target){
358 targets.insert(target);
359}
360
361void Notification::removeObserver(Observer *target){
362 targets.erase(target);
363}
364
365void Notification::notifyAll(){
366 for(std::set<Observer*>::iterator it=targets.begin();
367 it!=targets.end();++it){
368 (*it)->recieveNotification(owner,this);
369 }
370}
371
372#ifdef LOG_OBSERVER
373
374/************************* Methods to do logging of the Observer Mechanism *********/
375
376// The log needs to exist fairly early, so we make it construct on first use,
377// and never destroy it
378ObserverLog &observerLog(){
379 // yes, this memory is never freed... we need it around for the whole programm,
380 // so no freeing is possible
381 static ObserverLog *theLog = Memory::ignore(new ObserverLog());
382 return *theLog;
383}
384
385
386ObserverLog::ObserverLog() :
387 count (0)
388{}
389
390ObserverLog::~ObserverLog(){}
391
392string ObserverLog::getLog(){return log.str();}
393
394std::string ObserverLog::getName(void* obj){
395 return names[obj];
396}
397
398bool ObserverLog::isObservable(void* obj){
399 return observables.count(obj);
400}
401
402void ObserverLog::addName(void* obj , string name){
403 stringstream sstr;
404 sstr << name << "_" << count++;
405 names[obj] = sstr.str();
406}
407
408void ObserverLog::addObservable(void* obj){
409 observables.insert(obj);
410}
411
412void ObserverLog::deleteName(void* obj){
413 names.erase(obj);
414}
415
416void ObserverLog::deleteObservable(void* obj){
417 observables.erase(obj);
418}
419
420stringstream &ObserverLog::addMessage(int depth){
421 for(int i=depth;i--;)
422 log << " ";
423 return log;
424}
425
426#endif
Note: See TracBrowser for help on using the repository browser.