QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
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
67 Observable() = default;
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
162 if (updatesDeferred()) {
163 deferredObservers_.insert(observers.begin(), observers.end());
164 }
165 }
166
168 deferredObservers_.erase(o);
169 }
170
172 // the observer set is not copied; no observer asked to
173 // register with this object
174 }
175
176 /*! \warning notification is sent before the copy constructor has
177 a chance of actually change the data
178 members. Therefore, observers whose update() method
179 tries to use their observables will not see the
180 updated values. It is suggested that the update()
181 method just raise a flag in order to trigger
182 a later recalculation.
183 */
185 // as above, the observer set is not copied. Moreover,
186 // observers of this object must be notified of the change
187 if (&o != this)
189 return *this;
190 }
191
192 inline std::pair<Observable::iterator, bool>
194 return observers_.insert(o);
195 }
196
198 if (ObservableSettings::instance().updatesDeferred())
200
201 return observers_.erase(o);
202 }
203
204
206 : observables_(o.observables_) {
207 for (const auto& observable : observables_)
208 observable->registerObserver(this);
209 }
210
212 for (const auto& observable : observables_)
213 observable->unregisterObserver(this);
215 for (const auto& observable : observables_)
216 observable->registerObserver(this);
217 return *this;
218 }
219
221 for (const auto& observable : observables_)
222 observable->unregisterObserver(this);
223 }
224
225 inline std::pair<Observer::iterator, bool>
226 Observer::registerWith(const ext::shared_ptr<Observable>& h) {
227 if (h != nullptr) {
228 h->registerObserver(this);
229 return observables_.insert(h);
230 }
231 return std::make_pair(observables_.end(), false);
232 }
233
234 inline void
235 Observer::registerWithObservables(const ext::shared_ptr<Observer> &o) {
236 if (o != nullptr) {
237 for (const auto& observable : o->observables_)
238 registerWith(observable);
239 }
240 }
241
242 inline
243 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
244 if (h != nullptr)
245 h->unregisterObserver(this);
246 return observables_.erase(h);
247 }
248
250 for (const auto& observable : observables_)
251 observable->unregisterObserver(this);
252 observables_.clear();
253 }
254
255 inline void Observer::deepUpdate() {
256 update();
257 }
258
259}
260
261#else
262
263#ifndef QL_USE_STD_SHARED_PTR
264#include <boost/smart_ptr/owner_less.hpp>
265#endif
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
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&);
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>&);
389 const ext::shared_ptr<Observer::Proxy>& proxy, bool disconnect);
390
391 ext::shared_ptr<detail::Signal> sig_;
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 : UpdatesDisabled;
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#if defined(QL_USE_STD_SHARED_PTR)
414 typedef std::set<ext::weak_ptr<Observer::Proxy>,
415 std::owner_less<ext::weak_ptr<Observer::Proxy> > >
416 set_type;
417#else
418 typedef std::set<ext::weak_ptr<Observer::Proxy>,
419 boost::owner_less<ext::weak_ptr<Observer::Proxy> > >
420 set_type;
421#endif
422
423 void registerDeferredObservers(const Observable::set_type& observers);
424 void unregisterDeferredObserver(const ext::shared_ptr<Observer::Proxy>& proxy);
425
427 mutable std::mutex mutex_;
428
429 enum UpdateType { UpdatesDisabled = 0, UpdatesEnabled = 1, UpdatesDeferred = 2} ;
430 std::atomic<int> updatesType_;
431 };
432
433
434 // inline definitions
435
437 deferredObservers_.insert(observers.begin(), observers.end());
438 }
439
441 const ext::shared_ptr<Observer::Proxy>& o) {
442 deferredObservers_.erase(o);
443 }
444
446 std::lock_guard<std::mutex> lock(mutex_);
447
448 // if there are outstanding deferred updates, do the notification
449 updatesType_ = UpdatesEnabled;
450
451 if (deferredObservers_.size()) {
452 bool successful = true;
453 std::string errMsg;
454
455 for (auto i=deferredObservers_.begin();
456 i!=deferredObservers_.end(); ++i) {
457 try {
458 const ext::shared_ptr<Observer::Proxy> proxy = i->lock();
459 if (proxy)
460 proxy->update();
461 } catch (std::exception& e) {
462 successful = false;
463 errMsg = e.what();
464 } catch (...) {
465 successful = false;
466 }
467 }
468
469 deferredObservers_.clear();
470
471 QL_ENSURE(successful,
472 "could not notify one or more observers: " << errMsg);
473 }
474 }
475
476
477 /*! \warning notification is sent before the copy constructor has
478 a chance of actually change the data
479 members. Therefore, observers whose update() method
480 tries to use their observables will not see the
481 updated values. It is suggested that the update()
482 method just raise a flag in order to trigger
483 a later recalculation.
484 */
485 inline Observable& Observable::operator=(const Observable& o) {
486 // as above, the observer set is not copied. Moreover,
487 // observers of this object must be notified of the change
488 if (&o != this)
490 return *this;
491 }
492
493 inline Observer::Observer(const Observer& o) {
494 proxy_.reset(new Proxy(this));
495
496 {
497 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
498 observables_ = o.observables_;
499 }
500
501 for (const auto& observable : observables_)
502 observable->registerObserver(proxy_);
503 }
504
505 inline Observer& Observer::operator=(const Observer& o) {
506 std::lock_guard<std::recursive_mutex> lock(mutex_);
507 if (!proxy_) {
508 proxy_.reset(new Proxy(this));
509 }
510
511 for (const auto& observable : observables_)
512 observable->unregisterObserver(proxy_, true);
513
514 {
515 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
516 observables_ = o.observables_;
517 }
518 for (const auto& observable : observables_)
519 observable->registerObserver(proxy_);
520
521 return *this;
522 }
523
524 inline Observer::~Observer() {
525 std::lock_guard<std::recursive_mutex> lock(mutex_);
526 if (proxy_)
527 proxy_->deactivate();
528
529 for (const auto& observable : observables_)
530 observable->unregisterObserver(proxy_, false);
531 }
532
533 inline std::pair<Observer::iterator, bool>
534 Observer::registerWith(const ext::shared_ptr<Observable>& h) {
535 std::lock_guard<std::recursive_mutex> lock(mutex_);
536 if (!proxy_) {
537 proxy_.reset(new Proxy(this));
538 }
539
540 if (h) {
541 h->registerObserver(proxy_);
542 return observables_.insert(h);
543 }
544 return std::make_pair(observables_.end(), false);
545 }
546
547 inline void
548 Observer::registerWithObservables(const ext::shared_ptr<Observer>& o) {
549 if (o) {
550 std::lock_guard<std::recursive_mutex> lock(o->mutex_);
551
552 for (const auto& observable : o->observables_)
553 registerWith(observable);
554 }
555 }
556
557 inline
558 Size Observer::unregisterWith(const ext::shared_ptr<Observable>& h) {
559 std::lock_guard<std::recursive_mutex> lock(mutex_);
560
561 if (h && proxy_) {
562 h->unregisterObserver(proxy_, true);
563 }
564
565 return observables_.erase(h);
566 }
567
568 inline void Observer::unregisterWithAll() {
569 std::lock_guard<std::recursive_mutex> lock(mutex_);
570
571 for (const auto& observable : observables_)
572 observable->unregisterObserver(proxy_, true);
573
574 observables_.clear();
575 }
576
577 inline void Observer::deepUpdate() {
578 update();
579 }
580}
581#endif
582#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:184
Observable(Observable &&)=delete
virtual ~Observable()=default
std::pair< iterator, bool > registerObserver(Observer *)
Definition: observable.hpp:193
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:197
global repository for run-time library settings
Definition: observable.hpp:87
void unregisterDeferredObserver(Observer *)
Definition: observable.hpp:167
void registerDeferredObservers(const Observable::set_type &observers)
Definition: observable.hpp:161
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:255
Size unregisterWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:243
void registerWithObservables(const ext::shared_ptr< Observer > &)
Definition: observable.hpp:235
Observer & operator=(const Observer &)
Definition: observable.hpp:211
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:226
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:37
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.