QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
lazyobject.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2003 RiskMap srl
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
24#ifndef quantlib_lazy_object_h
25#define quantlib_lazy_object_h
26
27#include <ql/patterns/observable.hpp>
28#include <ql/shared_ptr.hpp>
29
30namespace QuantLib {
31
33
34 class LazyObject : public virtual Observable,
35 public virtual Observer {
36 public:
37 LazyObject();
38 ~LazyObject() override = default;
40
41 void update() override;
43
44 bool isCalculated() const;
63 void recalculate();
68 void freeze();
72 void unfreeze();
73
74 protected:
91 virtual void calculate() const;
95 virtual void performCalculations() const = 0;
97
98 public:
100
101
115
127
128 protected:
129 mutable bool calculated_ = false, frozen_ = false, alwaysForward_;
130 private:
131 bool updating_ = false;
132 class UpdateChecker { // NOLINT(cppcoreguidelines-special-member-functions)
134 public:
135 explicit UpdateChecker(LazyObject* subject) : subject_(subject) {
136 subject_->updating_ = true;
137 }
139 subject_->updating_ = false;
140 }
141 };
142 public:
143 class Defaults;
144 };
145
147 class LazyObject::Defaults : public Singleton<LazyObject::Defaults> {
148 friend class Singleton<LazyObject::Defaults>;
149 private:
150 Defaults() = default;
151
152 public:
159 forwardsAllNotifications_ = false;
160 }
161
168 }
169
173 }
174
175 private:
176 #ifdef QL_FASTER_LAZY_OBJECTS
177 bool forwardsAllNotifications_ = false;
178 #else
180 #endif
181 };
182
183 // inline definitions
184
186 : alwaysForward_(LazyObject::Defaults::instance().forwardsAllNotifications()) {}
187
188 inline void LazyObject::update() {
189 if (updating_) {
190 #ifdef QL_THROW_IN_CYCLES
191 QL_FAIL("recursive notification loop detected; you probably created an object cycle");
192 #else
193 return;
194 #endif
195 }
196
197 // This sets updating to true (so the above check breaks the
198 // infinite loop if we enter this method recursively) and will
199 // set it back to false when we exit this scope, either
200 // successfully or because of an exception.
201 UpdateChecker checker(this);
202
203 // forwards notifications only the first time
205 // set to false early
206 // 1) to prevent infinite recursion
207 // 2) otherways non-lazy observers would be served obsolete
208 // data because of calculated_ being still true
209 calculated_ = false;
210 // observers don't expect notifications from frozen objects
211 if (!frozen_)
213 // exiting notifyObservers() calculated_ could be
214 // already true because of non-lazy observers
215 }
216 }
217
219 bool wasFrozen = frozen_;
220 calculated_ = frozen_ = false;
221 try {
222 calculate();
223 } catch (...) {
224 frozen_ = wasFrozen;
226 throw;
227 }
228 frozen_ = wasFrozen;
230 }
231
232 inline void LazyObject::freeze() {
233 frozen_ = true;
234 }
235
236 inline void LazyObject::unfreeze() {
237 // send notifications, just in case we lost any,
238 // but only once, i.e. if it was frozen
239 if (frozen_) {
240 frozen_ = false;
242 }
243 }
244
246 alwaysForward_ = false;
247 }
248
250 alwaysForward_ = true;
251 }
252
253 inline void LazyObject::calculate() const {
254 if (!calculated_ && !frozen_) {
255 calculated_ = true; // prevent infinite recursion in
256 // case of bootstrapping
257 try {
259 } catch (...) {
260 calculated_ = false;
261 throw;
262 }
263 }
264 }
265
266 inline bool LazyObject::isCalculated() const {
267 return calculated_;
268 }
269}
270
271#endif
Per-session settings for the LazyObject class.
Definition: lazyobject.hpp:147
bool forwardsAllNotifications() const
returns the current default
Definition: lazyobject.hpp:171
UpdateChecker(LazyObject *subject)
Definition: lazyobject.hpp:135
Framework for calculation on demand and result caching.
Definition: lazyobject.hpp:35
virtual void calculate() const
Definition: lazyobject.hpp:253
void alwaysForwardNotifications()
Definition: lazyobject.hpp:249
void forwardFirstNotificationOnly()
Definition: lazyobject.hpp:245
void update() override
Definition: lazyobject.hpp:188
virtual void performCalculations() const =0
bool isCalculated() const
Definition: lazyobject.hpp:266
~LazyObject() override=default
Object that notifies its changes to a set of observers.
Definition: observable.hpp:62
Object that gets notified when a given observable changes.
Definition: observable.hpp:116
Basic support for the singleton pattern.
Definition: singleton.hpp:58
Definition: any.hpp:35