29#ifndef quantlib_observable_hpp
30#define quantlib_observable_hpp
38#if !defined(QL_USE_STD_SHARED_PTR) && BOOST_VERSION < 107400
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());
53#ifndef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN
58 class ObservableSettings;
118 typedef std::set<ext::shared_ptr<Observable>>
set_type;
129 std::pair<iterator, bool>
194 inline std::pair<Observable::iterator, bool>
208 : observables_(o.observables_) {
210 observable->registerObserver(
this);
215 observable->unregisterObserver(
this);
218 observable->registerObserver(
this);
224 observable->unregisterObserver(
this);
227 inline std::pair<Observer::iterator, bool>
230 h->registerObserver(
this);
239 for (
const auto& observable : o->observables_)
247 h->unregisterObserver(
this);
253 observable->unregisterObserver(
this);
265#ifndef QL_USE_STD_SHARED_PTR
266#include <boost/smart_ptr/owner_less.hpp>
276 class ObservableSettings;
280 class Observer :
public ext::enable_shared_from_this<Observer> {
281 friend class Observable;
282 friend class ObservableSettings;
284 typedef std::set<ext::shared_ptr<Observable>>
set_type;
286 typedef set_type::iterator
iterator;
294 std::pair<iterator, bool>
310 virtual void update() = 0;
322 explicit Proxy(Observer*
const observer)
324 observer_(observer) {
327 void update()
const {
328 std::lock_guard<std::recursive_mutex> lock(mutex_);
331 const ext::weak_ptr<Observer> o
332 = observer_->weak_from_this();
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());
349 std::lock_guard<std::recursive_mutex> lock(mutex_);
355 mutable std::recursive_mutex mutex_;
356 Observer*
const observer_;
359 ext::shared_ptr<Proxy> proxy_;
360 mutable std::recursive_mutex mutex_;
375 typedef std::set<ext::shared_ptr<Observer::Proxy>>
set_type;
377 typedef set_type::iterator
iterator;
391 const ext::shared_ptr<Observer::Proxy>& proxy,
bool disconnect);
393 ext::shared_ptr<detail::Signal> sig_;
395 mutable std::recursive_mutex mutex_;
399 class ObservableSettings :
public Singleton<ObservableSettings> {
405 std::lock_guard<std::mutex> lock(mutex_);
406 updatesType_ = (deferred) ? UpdatesDeferred : UpdatesDisabled;
410 bool updatesEnabled() {
return (updatesType_ & UpdatesEnabled) != 0; }
411 bool updatesDeferred() {
return (updatesType_ & UpdatesDeferred) != 0; }
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> > >
420 typedef std::set<ext::weak_ptr<Observer::Proxy>,
421 boost::owner_less<ext::weak_ptr<Observer::Proxy> > >
429 mutable std::mutex mutex_;
431 enum UpdateType { UpdatesDisabled = 0, UpdatesEnabled = 1, UpdatesDeferred = 2} ;
432 std::atomic<int> updatesType_;
443 const ext::shared_ptr<Observer::Proxy>& o) {
448 std::lock_guard<std::mutex> lock(mutex_);
451 updatesType_ = UpdatesEnabled;
454 bool successful =
true;
460 const ext::shared_ptr<Observer::Proxy> proxy = i->lock();
463 }
catch (std::exception& e) {
474 "could not notify one or more observers: " << errMsg);
496 proxy_.reset(
new Proxy(
this));
499 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
504 observable->registerObserver(proxy_);
508 std::lock_guard<std::recursive_mutex> lock(mutex_);
510 proxy_.reset(
new Proxy(
this));
514 observable->unregisterObserver(proxy_,
true);
517 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
521 observable->registerObserver(proxy_);
527 std::lock_guard<std::recursive_mutex> lock(mutex_);
529 proxy_->deactivate();
532 observable->unregisterObserver(proxy_,
false);
535 inline std::pair<Observer::iterator, bool>
537 std::lock_guard<std::recursive_mutex> lock(mutex_);
539 proxy_.reset(
new Proxy(
this));
543 h->registerObserver(proxy_);
552 std::lock_guard<std::recursive_mutex> lock(o->mutex_);
554 for (
const auto& observable : o->observables_)
561 std::lock_guard<std::recursive_mutex> lock(mutex_);
564 h->unregisterObserver(proxy_,
true);
571 std::lock_guard<std::recursive_mutex> lock(mutex_);
574 observable->unregisterObserver(proxy_,
true);
Object that notifies its changes to a set of observers.
Observable & operator=(Observable &&)=delete
Observable & operator=(const Observable &)
Observable(Observable &&)=delete
virtual ~Observable()=default
std::pair< iterator, bool > registerObserver(Observer *)
friend class ObservableSettings
std::set< Observer * > set_type
set_type::iterator iterator
Size unregisterObserver(Observer *)
global repository for run-time library settings
set_type deferredObservers_
void unregisterDeferredObserver(Observer *)
ObservableSettings()=default
void registerDeferredObservers(const Observable::set_type &observers)
void disableUpdates(bool deferred=false)
bool updatesEnabled() const
std::set< Observer * > set_type
bool updatesDeferred() const
set_type::iterator iterator
Object that gets notified when a given observable changes.
virtual void deepUpdate()
Size unregisterWith(const ext::shared_ptr< Observable > &)
void registerWithObservables(const ext::shared_ptr< Observer > &)
Observer & operator=(const Observer &)
std::set< ext::shared_ptr< Observable > > set_type
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
set_type::iterator iterator
Basic support for the singleton pattern.
static ObservableSettings & instance()
access to the unique instance
Classes and functions for error handling.
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
std::size_t Size
size of a container
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