QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
observable.hpp
Go to the documentation of this file.
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>
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
68 Observable(const Observable&);
70 // delete the move operations because the semantics are not yet clear
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*);
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:
102
103 typedef std::set<Observer*> set_type;
104 typedef set_type::iterator iterator;
105
106 void registerDeferredObservers(const Observable::set_type& observers);
108
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:
156 };
157
158
159 // inline definitions
160
161 inline Observable::Observable() = default;
162
164 if (updatesDeferred()) {
165 deferredObservers_.insert(observers.begin(), observers.end());
166 }
167 }
168
170 deferredObservers_.erase(o);
171 }
172
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 */
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)
191 return *this;
192 }
193
194 inline std::pair<Observable::iterator, bool>
196 return observers_.insert(o);
197 }
198
200 if (ObservableSettings::instance().updatesDeferred())
202
203 return observers_.erase(o);
204 }
205
206
208 : observables_(o.observables_) {
209 for (const auto& observable : observables_)
210 observable->registerObserver(this);
211 }
212
214 for (const auto& observable : observables_)
215 observable->unregisterObserver(this);
217 for (const auto& observable : observables_)
218 observable->registerObserver(this);
219 return *this;
220 }
221
223 for (const auto& observable : observables_)
224 observable->unregisterObserver(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(this);
231 return observables_.insert(h);
232 }
233 return std::make_pair(observables_.end(), 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(observable);
241 }
242 }
243
244 inline
245 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
246 if (h != nullptr)
247 h->unregisterObserver(this);
248 return observables_.erase(h);
249 }
250
252 for (const auto& observable : observables_)
253 observable->unregisterObserver(this);
254 observables_.clear();
255 }
256
257 inline void Observer::deepUpdate() {
258 update();
259 }
260
261}
262
263#else
264
265#ifndef QL_USE_STD_SHARED_PTR
266#include <boost/smart_ptr/owner_less.hpp>
267#endif
268#include <atomic>
269#include <mutex>
270#include <set>
271#include <thread>
272
273namespace QuantLib {
274
275 class Observable;
276 class ObservableSettings;
277
278 //! Object that gets notified when a given observable changes
279 /*! \ingroup patterns */
280 class Observer : public ext::enable_shared_from_this<Observer> {
281 friend class Observable;
282 friend class ObservableSettings;
283 private:
284 typedef std::set<ext::shared_ptr<Observable>> set_type;
285 public:
286 typedef set_type::iterator iterator;
287
288 // constructors, assignment, destructor
289 Observer() {}
290 Observer(const Observer&);
291 Observer& operator=(const Observer&);
292 virtual ~Observer();
293 // observer interface
294 std::pair<iterator, bool>
295 registerWith(const ext::shared_ptr<Observable>&);
296 /*! register with all observables of a given observer. Note
297 that this does not include registering with the observer
298 itself.
299 */
300 void registerWithObservables(const ext::shared_ptr<Observer>&);
301
302 Size unregisterWith(const ext::shared_ptr<Observable>&);
303 void unregisterWithAll();
304
305 /*! This method must be implemented in derived classes. An
306 instance of %Observer does not call this method directly:
307 instead, it will be called by the observables the instance
308 registered with when they need to notify any changes.
309 */
310 virtual void update() = 0;
311
312 /*! This method allows to explicitly update the instance itself
313 and nested observers. If notifications are disabled a call to
314 this method ensures an update of such nested observers. It
315 should be implemented in derived classes whenever applicable */
316 virtual void deepUpdate();
317
318 private:
319
320 class Proxy {
321 public:
322 explicit Proxy(Observer* const observer)
323 : active_ (true),
324 observer_(observer) {
325 }
326
327 void update() const {
328 std::lock_guard<std::recursive_mutex> lock(mutex_);
329 if (active_) {
330 // c++17 is required if used with std::shared_ptr<T>
331 const ext::weak_ptr<Observer> o
332 = observer_->weak_from_this();
333
334 //check for empty weak reference
335 //https://stackoverflow.com/questions/45507041/how-to-check-if-weak-ptr-is-empty-non-assigned
336 const ext::weak_ptr<Observer> empty;
337 if (o.owner_before(empty) || empty.owner_before(o)) {
338 const ext::shared_ptr<Observer> obs(o.lock());
339 if (obs)
340 obs->update();
341 }
342 else {
343 observer_->update();
344 }
345 }
346 }
347
348 void deactivate() {
349 std::lock_guard<std::recursive_mutex> lock(mutex_);
350 active_ = false;
351 }
352
353 private:
354 bool active_;
355 mutable std::recursive_mutex mutex_;
356 Observer* const observer_;
357 };
358
359 ext::shared_ptr<Proxy> proxy_;
360 mutable std::recursive_mutex mutex_;
361
363 };
364
365 namespace detail {
366 class Signal;
367 }
368
369 //! Object that notifies its changes to a set of observers
370 /*! \ingroup patterns */
371 class Observable {
372 friend class Observer;
373 friend class ObservableSettings;
374 private:
375 typedef std::set<ext::shared_ptr<Observer::Proxy>> set_type;
376 public:
377 typedef set_type::iterator iterator;
378
379 // constructors, assignment, destructor
380 Observable();
381 Observable(const Observable&);
383 virtual ~Observable() {}
384 /*! This method should be called at the end of non-const methods
385 or when the programmer desires to notify any changes.
386 */
387 void notifyObservers();
388 private:
389 void registerObserver(const ext::shared_ptr<Observer::Proxy>&);
391 const ext::shared_ptr<Observer::Proxy>& proxy, bool disconnect);
392
393 ext::shared_ptr<detail::Signal> sig_;
395 mutable std::recursive_mutex mutex_;
396 };
397
398 //! global repository for run-time library settings
399 class ObservableSettings : public Singleton<ObservableSettings> {
400 friend class Singleton<ObservableSettings>;
401 friend class Observable;
402
403 public:
404 void disableUpdates(bool deferred=false) {
405 std::lock_guard<std::mutex> lock(mutex_);
406 updatesType_ = (deferred) ? UpdatesDeferred : UpdatesDisabled;
407 }
408 void enableUpdates();
409
410 bool updatesEnabled() {return (updatesType_ & UpdatesEnabled) != 0; }
411 bool updatesDeferred() {return (updatesType_ & UpdatesDeferred) != 0; }
412 private:
413 ObservableSettings() : updatesType_(UpdatesEnabled) {}
414
415#if defined(QL_USE_STD_SHARED_PTR)
416 typedef std::set<ext::weak_ptr<Observer::Proxy>,
417 std::owner_less<ext::weak_ptr<Observer::Proxy> > >
418 set_type;
419#else
420 typedef std::set<ext::weak_ptr<Observer::Proxy>,
421 boost::owner_less<ext::weak_ptr<Observer::Proxy> > >
422 set_type;
423#endif
424
425 void registerDeferredObservers(const Observable::set_type& observers);
426 void unregisterDeferredObserver(const ext::shared_ptr<Observer::Proxy>& proxy);
427
429 mutable std::mutex mutex_;
430
431 enum UpdateType { UpdatesDisabled = 0, UpdatesEnabled = 1, UpdatesDeferred = 2} ;
432 std::atomic<int> updatesType_;
433 };
434
435
436 // inline definitions
437
439 deferredObservers_.insert(observers.begin(), observers.end());
440 }
441
443 const ext::shared_ptr<Observer::Proxy>& o) {
444 deferredObservers_.erase(o);
445 }
446
448 std::lock_guard<std::mutex> lock(mutex_);
449
450 // if there are outstanding deferred updates, do the notification
451 updatesType_ = UpdatesEnabled;
452
453 if (deferredObservers_.size()) {
454 bool successful = true;
455 std::string errMsg;
456
457 for (auto i=deferredObservers_.begin();
458 i!=deferredObservers_.end(); ++i) {
459 try {
460 const ext::shared_ptr<Observer::Proxy> proxy = i->lock();
461 if (proxy)
462 proxy->update();
463 } catch (std::exception& e) {
464 successful = false;
465 errMsg = e.what();
466 } catch (...) {
467 successful = false;
468 }
469 }
470
471 deferredObservers_.clear();
472
473 QL_ENSURE(successful,
474 "could not notify one or more observers: " << errMsg);
475 }
476 }
477
478
479 /*! \warning notification is sent before the copy constructor has
480 a chance of actually change the data
481 members. Therefore, observers whose update() method
482 tries to use their observables will not see the
483 updated values. It is suggested that the update()
484 method just raise a flag in order to trigger
485 a later recalculation.
486 */
487 inline Observable& Observable::operator=(const Observable& o) {
488 // as above, the observer set is not copied. Moreover,
489 // observers of this object must be notified of the change
490 if (&o != this)
492 return *this;
493 }
494
495 inline Observer::Observer(const Observer& o) {
496 proxy_.reset(new Proxy(this));
497
498 {
499 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
500 observables_ = o.observables_;
501 }
502
503 for (const auto& observable : observables_)
504 observable->registerObserver(proxy_);
505 }
506
507 inline Observer& Observer::operator=(const Observer& o) {
508 std::lock_guard<std::recursive_mutex> lock(mutex_);
509 if (!proxy_) {
510 proxy_.reset(new Proxy(this));
511 }
512
513 for (const auto& observable : observables_)
514 observable->unregisterObserver(proxy_, true);
515
516 {
517 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
518 observables_ = o.observables_;
519 }
520 for (const auto& observable : observables_)
521 observable->registerObserver(proxy_);
522
523 return *this;
524 }
525
526 inline Observer::~Observer() {
527 std::lock_guard<std::recursive_mutex> lock(mutex_);
528 if (proxy_)
529 proxy_->deactivate();
530
531 for (const auto& observable : observables_)
532 observable->unregisterObserver(proxy_, false);
533 }
534
535 inline std::pair<Observer::iterator, bool>
536 Observer::registerWith(const ext::shared_ptr<Observable>& h) {
537 std::lock_guard<std::recursive_mutex> lock(mutex_);
538 if (!proxy_) {
539 proxy_.reset(new Proxy(this));
540 }
541
542 if (h) {
543 h->registerObserver(proxy_);
544 return observables_.insert(h);
545 }
546 return std::make_pair(observables_.end(), false);
547 }
548
549 inline void
550 Observer::registerWithObservables(const ext::shared_ptr<Observer>& o) {
551 if (o) {
552 std::lock_guard<std::recursive_mutex> lock(o->mutex_);
553
554 for (const auto& observable : o->observables_)
555 registerWith(observable);
556 }
557 }
558
559 inline
560 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
561 std::lock_guard<std::recursive_mutex> lock(mutex_);
562
563 if (h && proxy_) {
564 h->unregisterObserver(proxy_, true);
565 }
566
567 return observables_.erase(h);
568 }
569
570 inline void Observer::unregisterWithAll() {
571 std::lock_guard<std::recursive_mutex> lock(mutex_);
572
573 for (const auto& observable : observables_)
574 observable->unregisterObserver(proxy_, true);
575
576 observables_.clear();
577 }
578
579 inline void Observer::deepUpdate() {
580 update();
581 }
582}
583#endif
584#endif
Object that notifies its changes to a set of observers.
Definition: observable.hpp:62
friend class Observer
Definition: observable.hpp:63
Observable & operator=(Observable &&)=delete
Observable & operator=(const Observable &)
Definition: observable.hpp:186
Observable(Observable &&)=delete
virtual ~Observable()=default
std::pair< iterator, bool > registerObserver(Observer *)
Definition: observable.hpp:195
friend class ObservableSettings
Definition: observable.hpp:64
std::set< Observer * > set_type
Definition: observable.hpp:79
set_type::iterator iterator
Definition: observable.hpp:80
Size unregisterObserver(Observer *)
Definition: observable.hpp:199
global repository for run-time library settings
Definition: observable.hpp:87
void unregisterDeferredObserver(Observer *)
Definition: observable.hpp:169
void registerDeferredObservers(const Observable::set_type &observers)
Definition: observable.hpp:163
void disableUpdates(bool deferred=false)
Definition: observable.hpp:91
std::set< Observer * > set_type
Definition: observable.hpp:103
set_type::iterator iterator
Definition: observable.hpp:104
Object that gets notified when a given observable changes.
Definition: observable.hpp:116
virtual void deepUpdate()
Definition: observable.hpp:257
Size unregisterWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:245
void registerWithObservables(const ext::shared_ptr< Observer > &)
Definition: observable.hpp:237
Observer & operator=(const Observer &)
Definition: observable.hpp:213
virtual void update()=0
std::set< ext::shared_ptr< Observable > > set_type
Definition: observable.hpp:118
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
set_type::iterator iterator
Definition: observable.hpp:120
Basic support for the singleton pattern.
Definition: singleton.hpp:58
static ObservableSettings & instance()
access to the unique instance
Definition: singleton.hpp:104
Classes and functions for error handling.
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
Definition: errors.hpp:130
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
Definition: errors.cpp:70
STL namespace.
Maps shared_ptr to either the boost or std implementation.
basic support for the singleton pattern
std::size_t operator()(const boost::shared_ptr< T > &ptr) const noexcept
Definition: observable.hpp:44
Custom types.