QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
observable.cpp
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) 2013 Chris Higgs
5Copyright (C) 2015 Klaus Spanderen
6
7This file is part of QuantLib, a free-software/open-source library
8for financial quantitative analysts and developers - http://quantlib.org/
9
10QuantLib is free software: you can redistribute it and/or modify it
11under the terms of the QuantLib license. You should have received a
12copy of the license along with this program; if not, please email
13<quantlib-dev@lists.sf.net>. The license is also available online at
14<http://quantlib.org/license.shtml>.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
21
23
24#ifndef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN
25
26namespace QuantLib {
27
29 updatesEnabled_ = true;
30 updatesDeferred_ = false;
31
32 // if there are outstanding deferred updates, do the notification
33 if (!deferredObservers_.empty()) {
34 bool successful = true;
35 std::string errMsg;
36
37 for (auto* deferredObserver : deferredObservers_) {
38 try {
39 deferredObserver->update();
40 } catch (std::exception& e) {
41 successful = false;
42 errMsg = e.what();
43 } catch (...) {
44 successful = false;
45 }
46 }
47
48 deferredObservers_.clear();
49
50 QL_ENSURE(successful,
51 "could not notify one or more observers: " << errMsg);
52 }
53 }
54
55
57 if (!ObservableSettings::instance().updatesEnabled()) {
58 // if updates are only deferred, flag this for later notification
59 // these are held centrally by the settings singleton
61 } else if (!observers_.empty()) {
62 bool successful = true;
63 std::string errMsg;
64 for (auto* observer : observers_) {
65 try {
66 observer->update();
67 } catch (std::exception& e) {
68 // quite a dilemma. If we don't catch the exception,
69 // other observers will not receive the notification
70 // and might be left in an incorrect state. If we do
71 // catch it and continue the loop (as we do here) we
72 // lose the exception. The least evil might be to try
73 // and notify all observers, while raising an
74 // exception if something bad happened.
75 successful = false;
76 errMsg = e.what();
77 } catch (...) {
78 successful = false;
79 }
80 }
81 QL_ENSURE(successful,
82 "could not notify one or more observers: " << errMsg);
83 }
84 }
85
86}
87
88#else
89
90#include <boost/signals2/signal_type.hpp>
91
92namespace QuantLib {
93
94 namespace detail {
95
96 class Signal {
97 public:
98 typedef boost::signals2::signal_type<
99 void(),
100 boost::signals2::keywords::mutex_type<std::recursive_mutex> >
101 ::type signal_type;
102
103 void connect(const signal_type::slot_type& slot) {
104 sig_.connect(slot);
105 }
106
107 template <class T>
108 void disconnect(const T& slot) {
109 sig_.disconnect(slot);
110 }
111
112 void operator()() const {
113 sig_();
114 }
115 private:
116 signal_type sig_;
117 };
118
119 template <class T>
120 class ProxyUpdater {
121 T* proxy_;
122 public:
123 explicit ProxyUpdater(const ext::shared_ptr<T>& observerProxy)
124 : proxy_(observerProxy.get()) {}
125
126 void operator()() const {
127 proxy_->update();
128 }
129
130 bool operator==(const ProxyUpdater<T>& other) const {
131 return proxy_ == other.proxy_;
132 }
133
134 bool operator!=(const ProxyUpdater<T>& other) const {
135 return proxy_ != other.proxy_;
136 }
137 };
138
139 }
140
141 void Observable::registerObserver(const ext::shared_ptr<Observer::Proxy>& observerProxy) {
142 {
143 std::lock_guard<std::recursive_mutex> lock(mutex_);
144 observers_.insert(observerProxy);
145 }
146
147 detail::Signal::signal_type::slot_type slot {detail::ProxyUpdater<Observer::Proxy>(observerProxy)};
148 #if defined(QL_USE_STD_SHARED_PTR)
149 sig_->connect(slot.track_foreign(observerProxy));
150 #else
151 sig_->connect(slot.track(observerProxy));
152 #endif
153 }
154
155 void Observable::unregisterObserver(const ext::shared_ptr<Observer::Proxy>& observerProxy,
156 bool disconnect) {
157 {
158 std::lock_guard<std::recursive_mutex> lock(mutex_);
159 observers_.erase(observerProxy);
160 }
161
162 if (ObservableSettings::instance().updatesDeferred()) {
163 std::lock_guard<std::mutex> sLock(ObservableSettings::instance().mutex_);
164 if (ObservableSettings::instance().updatesDeferred())
166 }
167
168 if (disconnect) {
169 sig_->disconnect(detail::ProxyUpdater<Observer::Proxy>(observerProxy));
170 }
171 }
172
174 if (ObservableSettings::instance().updatesEnabled()) {
175 sig_->operator()();
176 }
177 else {
178 bool updatesEnabled = false;
179 {
180 std::lock_guard<std::mutex> sLock(ObservableSettings::instance().mutex_);
181 updatesEnabled = ObservableSettings::instance().updatesEnabled();
182
183 if (ObservableSettings::instance().updatesDeferred()) {
184 std::lock_guard<std::recursive_mutex> lock(mutex_);
186 }
187 }
188
189 if (updatesEnabled)
190 sig_->operator()();
191 }
192 }
193
195 : sig_(new detail::Signal()) { }
196
197 Observable::Observable(const Observable&)
198 : sig_(new detail::Signal()) {
199 // the observer set is not copied; no observer asked to
200 // register with this object
201 }
202
203}
204
205#endif
std::pair< iterator, bool > registerObserver(Observer *)
Definition: observable.hpp:195
Size unregisterObserver(Observer *)
Definition: observable.hpp:199
void unregisterDeferredObserver(Observer *)
Definition: observable.hpp:169
void registerDeferredObservers(const Observable::set_type &observers)
Definition: observable.hpp:163
static ObservableSettings & instance()
access to the unique instance
Definition: singleton.hpp:104
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
Definition: errors.hpp:130
T get(const std::vector< T > &v, Size i, U defaultValue)
Definition: vectors.hpp:35
Definition: any.hpp:35
bool operator==(const Currency &c1, const Currency &c2)
Definition: currency.hpp:231
bool operator!=(const Currency &c1, const Currency &c2)
Definition: currency.hpp:236
observer/observable pattern