1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
6Copyright (C) 2011, 2012 Ferdinando Ametrano
7Copyright (C) 2013 Chris Higgs
8Copyright (C) 2015 Klaus Spanderen
9
10
11This file is part of QuantLib, a free-software/open-source library
12for financial quantitative analysts and developers - http://quantlib.org/
13
14QuantLib is free software: you can redistribute it and/or modify it
15under the terms of the QuantLib license. You should have received a
16copy of the license along with this program; if not, please email
17<quantlib-dev@lists.sf.net>. The license is also available online at
18<http://quantlib.org/license.shtml>.
19
20This program is distributed in the hope that it will be useful, but WITHOUT
21ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22FOR A PARTICULAR PURPOSE. See the license for more details.
23*/
24
25/*! \file observable.hpp
26 \brief observer/observable pattern
27*/
28
29#ifndef quantlib_observable_hpp
30#define quantlib_observable_hpp
31
32#include <ql/errors.hpp>
33#include <ql/patterns/singleton.hpp>
34#include <ql/shared_ptr.hpp>
35#include <ql/types.hpp>
36#include <set>
37
38#if !defined(QL_USE_STD_SHARED_PTR) && BOOST_VERSION < 107400
39
40namespace std {
41
42 template<typename T>
43 struct hash<boost::shared_ptr<T>> {
44 std::size_t operator()(const boost::shared_ptr<T>& ptr) const noexcept {
45 return std::hash<typename boost::shared_ptr<T>::element_type*>()(ptr.get());
46 }
47 };
48
49}
50
51#endif
52
53#ifndef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN
54
55namespace QuantLib {
56
57 class Observer;
58 class ObservableSettings;
59
60 //! Object that notifies its changes to a set of observers
61 /*! \ingroup patterns */
62 class Observable {
63 friend class Observer;
64 friend class ObservableSettings;
65 public:
66 // constructors, assignment, destructor
67 Observable();
68 Observable(const Observable&);
69 Observable& operator=(const Observable&);
70 // delete the move operations because the semantics are not yet clear
71 Observable(Observable&&) = delete;
72 Observable& operator=(Observable&&) = delete;
73 virtual ~Observable() = default;
74 /*! This method should be called at the end of non-const methods
75 or when the programmer desires to notify any changes.
76 */
77 void notifyObservers();
78 private:
79 typedef std::set<Observer*> set_type;
80 typedef set_type::iterator iterator;
81 std::pair<iterator, bool> registerObserver(Observer*);
82 Size unregisterObserver(Observer*);
83 set_type observers_;
84 };
85
86 //! global repository for run-time library settings
87 class ObservableSettings : public Singleton<ObservableSettings> {
88 friend class Singleton<ObservableSettings>;
89 friend class Observable;
90 public:
91 void disableUpdates(bool deferred=false) {
92 updatesEnabled_ = false;
93 updatesDeferred_ = deferred;
94 }
95 void enableUpdates();
96
97 bool updatesEnabled() const { return updatesEnabled_; }
98 bool updatesDeferred() const { return updatesDeferred_; }
99
100 private:
101 ObservableSettings() = default;
102
103 typedef std::set<Observer*> set_type;
104 typedef set_type::iterator iterator;
105
106 void registerDeferredObservers(const Observable::set_type& observers);
107 void unregisterDeferredObserver(Observer*);
108
109 set_type deferredObservers_;
110
111 bool updatesEnabled_ = true, updatesDeferred_ = false;
112 };
113
114 //! Object that gets notified when a given observable changes
115 /*! \ingroup patterns */
116 class Observer { // NOLINT(cppcoreguidelines-special-member-functions)
117 private:
118 typedef std::set<ext::shared_ptr<Observable>> set_type;
119 public:
120 typedef set_type::iterator iterator;
121
122 // constructors, assignment, destructor
123 Observer() = default;
124 Observer(const Observer&);
125 Observer& operator=(const Observer&);
126 virtual ~Observer();
127
128 // observer interface
129 std::pair<iterator, bool>
130 registerWith(const ext::shared_ptr<Observable>&);
131
132 /*! register with all observables of a given observer. Note
133 that this does not include registering with the observer
134 itself.
135 */
136 void registerWithObservables(const ext::shared_ptr<Observer>&);
137
138 Size unregisterWith(const ext::shared_ptr<Observable>&);
139 void unregisterWithAll();
140
141 /*! This method must be implemented in derived classes. An
142 instance of %Observer does not call this method directly:
143 instead, it will be called by the observables the instance
144 registered with when they need to notify any changes.
145 */
146 virtual void update() = 0;
147
148 /*! This method allows to explicitly update the instance itself
149 and nested observers. If notifications are disabled a call to
150 this method ensures an update of such nested observers. It
151 should be implemented in derived classes whenever applicable */
152 virtual void deepUpdate();
153
154 private:
155 set_type observables_;
156 };
157
158
159 // inline definitions
160
161 inline Observable::Observable() = default;
162
163 inline void ObservableSettings::registerDeferredObservers(const Observable::set_type& observers) {
164 if (updatesDeferred()) {
165 deferredObservers_.insert(first: observers.begin(), last: observers.end());
166 }
167 }
168
169 inline void ObservableSettings::unregisterDeferredObserver(Observer* o) {
170 deferredObservers_.erase(x: o);
171 }
172
173 inline Observable::Observable(const Observable&) {
174 // the observer set is not copied; no observer asked to
175 // register with this object
176 }
177
178 /*! \warning notification is sent before the copy constructor has
179 a chance of actually change the data
180 members. Therefore, observers whose update() method
181 tries to use their observables will not see the
182 updated values. It is suggested that the update()
183 method just raise a flag in order to trigger
184 a later recalculation.
185 */
186 inline Observable& Observable::operator=(const Observable& o) {
187 // as above, the observer set is not copied. Moreover,
188 // observers of this object must be notified of the change
189 if (&o != this)
190 notifyObservers();
191 return *this;
192 }
193
194 inline std::pair<Observable::iterator, bool>
195 Observable::registerObserver(Observer* o) {
196 return observers_.insert(x: o);
197 }
198
199 inline Size Observable::unregisterObserver(Observer* o) {
200 if (ObservableSettings::instance().updatesDeferred())
201 ObservableSettings::instance().unregisterDeferredObserver(o);
202
203 return observers_.erase(x: o);
204 }
205
206
207 inline Observer::Observer(const Observer& o)
208 : observables_(o.observables_) {
209 for (const auto& observable : observables_)
210 observable->registerObserver(o: this);
211 }
212
213 inline Observer& Observer::operator=(const Observer& o) {
214 for (const auto& observable : observables_)
215 observable->unregisterObserver(o: this);
216 observables_ = o.observables_;
217 for (const auto& observable : observables_)
218 observable->registerObserver(o: this);
219 return *this;
220 }
221
222 inline Observer::~Observer() {
223 for (const auto& observable : observables_)
224 observable->unregisterObserver(o: this);
225 }
226
227 inline std::pair<Observer::iterator, bool>
228 Observer::registerWith(const ext::shared_ptr<Observable>& h) {
229 if (h != nullptr) {
230 h->registerObserver(o: this);
231 return observables_.insert(x: h);
232 }
233 return std::make_pair(x: observables_.end(), y: false);
234 }
235
236 inline void
237 Observer::registerWithObservables(const ext::shared_ptr<Observer> &o) {
238 if (o != nullptr) {
239 for (const auto& observable : o->observables_)
240 registerWith(h: observable);
241 }
242 }
243
244 inline
245 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
246 if (h != nullptr)
247 h->unregisterObserver(o: this);
248 return observables_.erase(x: h);
249 }
250
251 inline void Observer::unregisterWithAll() {
252 for (const auto& observable : observables_)
253 observable->unregisterObserver(o: this);
254 observables_.clear();
255 }
256
257 inline void Observer::deepUpdate() {
258 update();
259 }
260
261}
262
263#else
264
265#include <boost/smart_ptr/owner_less.hpp>
266#include <atomic>
267#include <mutex>
268#include <set>
269#include <thread>
270
271namespace QuantLib {
272
273 class Observable;
274 class ObservableSettings;
275
276 //! Object that gets notified when a given observable changes
277 /*! \ingroup patterns */
278 class Observer : public ext::enable_shared_from_this<Observer> {
279 friend class Observable;
280 friend class ObservableSettings;
281 private:
282 typedef std::set<ext::shared_ptr<Observable>> set_type;
283 public:
284 typedef set_type::iterator iterator;
285
286 // constructors, assignment, destructor
287 Observer() {}
288 Observer(const Observer&);
289 Observer& operator=(const Observer&);
290 virtual ~Observer();
291 // observer interface
292 std::pair<iterator, bool>
293 registerWith(const ext::shared_ptr<Observable>&);
294 /*! register with all observables of a given observer. Note
295 that this does not include registering with the observer
296 itself.
297 */
298 void registerWithObservables(const ext::shared_ptr<Observer>&);
299
300 Size unregisterWith(const ext::shared_ptr<Observable>&);
301 void unregisterWithAll();
302
303 /*! This method must be implemented in derived classes. An
304 instance of %Observer does not call this method directly:
305 instead, it will be called by the observables the instance
306 registered with when they need to notify any changes.
307 */
308 virtual void update() = 0;
309
310 /*! This method allows to explicitly update the instance itself
311 and nested observers. If notifications are disabled a call to
312 this method ensures an update of such nested observers. It
313 should be implemented in derived classes whenever applicable */
314 virtual void deepUpdate();
315
316 private:
317
318 class Proxy {
319 public:
320 explicit Proxy(Observer* const observer)
321 : active_ (true),
322 observer_(observer) {
323 }
324
325 void update() const {
326 std::lock_guard<std::recursive_mutex> lock(mutex_);
327 if (active_) {
328 // c++17 is required if used with std::shared_ptr<T>
329 const ext::weak_ptr<Observer> o
330 = observer_->weak_from_this();
331
332 //check for empty weak reference
333 //https://stackoverflow.com/questions/45507041/how-to-check-if-weak-ptr-is-empty-non-assigned
334 const ext::weak_ptr<Observer> empty;
335 if (o.owner_before(empty) || empty.owner_before(o)) {
336 const ext::shared_ptr<Observer> obs(o.lock());
337 if (obs)
338 obs->update();
339 }
340 else {
341 observer_->update();
342 }
343 }
344 }
345
346 void deactivate() {
347 std::lock_guard<std::recursive_mutex> lock(mutex_);
348 active_ = false;
349 }
350
351 private:
352 bool active_;
353 mutable std::recursive_mutex mutex_;
354 Observer* const observer_;
355 };
356
357 ext::shared_ptr<Proxy> proxy_;
358 mutable std::recursive_mutex mutex_;
359
360 set_type observables_;
361 };
362
363 namespace detail {
364 class Signal;
365 }
366
367 //! Object that notifies its changes to a set of observers
368 /*! \ingroup patterns */
369 class Observable {
370 friend class Observer;
371 friend class ObservableSettings;
372 private:
373 typedef std::set<ext::shared_ptr<Observer::Proxy>> set_type;
374 public:
375 typedef set_type::iterator iterator;
376
377 // constructors, assignment, destructor
378 Observable();
379 Observable(const Observable&);
380 Observable& operator=(const Observable&);
381 virtual ~Observable() {}
382 /*! This method should be called at the end of non-const methods
383 or when the programmer desires to notify any changes.
384 */
385 void notifyObservers();
386 private:
387 void registerObserver(const ext::shared_ptr<Observer::Proxy>&);
388 void unregisterObserver(
389 const ext::shared_ptr<Observer::Proxy>& proxy, bool disconnect);
390
391 ext::shared_ptr<detail::Signal> sig_;
392 set_type observers_;
393 mutable std::recursive_mutex mutex_;
394 };
395
396 //! global repository for run-time library settings
397 class ObservableSettings : public Singleton<ObservableSettings> {
398 friend class Singleton<ObservableSettings>;
399 friend class Observable;
400
401 public:
402 void disableUpdates(bool deferred=false) {
403 std::lock_guard<std::mutex> lock(mutex_);
404 updatesType_ = (deferred) ? UpdatesDeferred : 0;
405 }
406 void enableUpdates();
407
408 bool updatesEnabled() {return (updatesType_ & UpdatesEnabled) != 0; }
409 bool updatesDeferred() {return (updatesType_ & UpdatesDeferred) != 0; }
410 private:
411 ObservableSettings() : updatesType_(UpdatesEnabled) {}
412
413 typedef std::set<ext::weak_ptr<Observer::Proxy>,
414 boost::owner_less<ext::weak_ptr<Observer::Proxy> > >
415 set_type;
416
417 void registerDeferredObservers(const Observable::set_type& observers);
418 void unregisterDeferredObserver(const ext::shared_ptr<Observer::Proxy>& proxy);
419
420 set_type deferredObservers_;
421 mutable std::mutex mutex_;
422
423 enum UpdateType { UpdatesEnabled = 1, UpdatesDeferred = 2} ;
424 std::atomic<int> updatesType_;
425 };
426
427
428 // inline definitions
429
430 inline void ObservableSettings::registerDeferredObservers(const Observable::set_type& observers) {
431 deferredObservers_.insert(observers.begin(), observers.end());
432 }
433
434 inline void ObservableSettings::unregisterDeferredObserver(
435 const ext::shared_ptr<Observer::Proxy>& o) {
436 deferredObservers_.erase(o);
437 }
438
439 inline void ObservableSettings::enableUpdates() {
440 std::lock_guard<std::mutex> lock(mutex_);
441
442 // if there are outstanding deferred updates, do the notification
443 updatesType_ = UpdatesEnabled;
444
445 if (deferredObservers_.size()) {
446 bool successful = true;
447 std::string errMsg;
448
449 for (auto i=deferredObservers_.begin();
450 i!=deferredObservers_.end(); ++i) {
451 try {
452 const ext::shared_ptr<Observer::Proxy> proxy = i->lock();
453 if (proxy)
454 proxy->update();
455 } catch (std::exception& e) {
456 successful = false;
457 errMsg = e.what();
458 } catch (...) {
459 successful = false;
460 }
461 }
462
463 deferredObservers_.clear();
464
465 QL_ENSURE(successful,
466 "could not notify one or more observers: " << errMsg);
467 }
468 }
469
470
471 /*! \warning notification is sent before the copy constructor has
472 a chance of actually change the data
473 members. Therefore, observers whose update() method
474 tries to use their observables will not see the
475 updated values. It is suggested that the update()
476 method just raise a flag in order to trigger
477 a later recalculation.
478 */
479 inline Observable& Observable::operator=(const Observable& o) {
480 // as above, the observer set is not copied. Moreover,
481 // observers of this object must be notified of the change
482 if (&o != this)
483 notifyObservers();
484 return *this;
485 }
486
487 inline Observer::Observer(const Observer& o) {
488 proxy_.reset(new Proxy(this));
489
490 {
491 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
492 observables_ = o.observables_;
493 }
494
495 for (const auto& observable : observables_)
496 observable->registerObserver(proxy_);
497 }
498
499 inline Observer& Observer::operator=(const Observer& o) {
500 std::lock_guard<std::recursive_mutex> lock(mutex_);
501 if (!proxy_) {
502 proxy_.reset(new Proxy(this));
503 }
504
505 for (const auto& observable : observables_)
506 observable->unregisterObserver(proxy_, true);
507
508 {
509 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
510 observables_ = o.observables_;
511 }
512 for (const auto& observable : observables_)
513 observable->registerObserver(proxy_);
514
515 return *this;
516 }
517
518 inline Observer::~Observer() {
519 std::lock_guard<std::recursive_mutex> lock(mutex_);
520 if (proxy_)
521 proxy_->deactivate();
522
523 for (const auto& observable : observables_)
524 observable->unregisterObserver(proxy_, false);
525 }
526
527 inline std::pair<Observer::iterator, bool>
528 Observer::registerWith(const ext::shared_ptr<Observable>& h) {
529 std::lock_guard<std::recursive_mutex> lock(mutex_);
530 if (!proxy_) {
531 proxy_.reset(new Proxy(this));
532 }
533
534 if (h) {
535 h->registerObserver(proxy_);
536 return observables_.insert(h);
537 }
538 return std::make_pair(observables_.end(), false);
539 }
540
541 inline void
542 Observer::registerWithObservables(const ext::shared_ptr<Observer>& o) {
543 if (o) {
544 std::lock_guard<std::recursive_mutex> lock(o->mutex_);
545
546 for (const auto& observable : o->observables_)
547 registerWith(observable);
548 }
549 }
550
551 inline
552 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
553 std::lock_guard<std::recursive_mutex> lock(mutex_);
554
555 if (h && proxy_) {
556 h->unregisterObserver(proxy_, true);
557 }
558
559 return observables_.erase(h);
560 }
561
562 inline void Observer::unregisterWithAll() {
563 std::lock_guard<std::recursive_mutex> lock(mutex_);
564
565 for (const auto& observable : observables_)
566 observable->unregisterObserver(proxy_, true);
567
568 observables_.clear();
569 }
570
571 inline void Observer::deepUpdate() {
572 update();
573 }
574}
575#endif
576#endif
577

source code of quantlib/ql/patterns/observable.hpp