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>
192 inline std::pair<Observable::iterator, bool>
206 : observables_(o.observables_) {
208 observable->registerObserver(
this);
213 observable->unregisterObserver(
this);
216 observable->registerObserver(
this);
222 observable->unregisterObserver(
this);
225 inline std::pair<Observer::iterator, bool>
228 h->registerObserver(
this);
237 for (
const auto& observable : o->observables_)
245 h->unregisterObserver(
this);
251 observable->unregisterObserver(
this);
263#ifndef QL_USE_STD_SHARED_PTR
264#include <boost/smart_ptr/owner_less.hpp>
274 class ObservableSettings;
278 class Observer :
public ext::enable_shared_from_this<Observer> {
279 friend class Observable;
280 friend class ObservableSettings;
282 typedef std::set<ext::shared_ptr<Observable>>
set_type;
284 typedef set_type::iterator
iterator;
292 std::pair<iterator, bool>
308 virtual void update() = 0;
320 explicit Proxy(Observer*
const observer)
322 observer_(observer) {
325 void update()
const {
326 std::lock_guard<std::recursive_mutex> lock(mutex_);
329 const ext::weak_ptr<Observer> o
330 = observer_->weak_from_this();
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());
347 std::lock_guard<std::recursive_mutex> lock(mutex_);
353 mutable std::recursive_mutex mutex_;
354 Observer*
const observer_;
357 ext::shared_ptr<Proxy> proxy_;
358 mutable std::recursive_mutex mutex_;
373 typedef std::set<ext::shared_ptr<Observer::Proxy>>
set_type;
375 typedef set_type::iterator
iterator;
389 const ext::shared_ptr<Observer::Proxy>& proxy,
bool disconnect);
391 ext::shared_ptr<detail::Signal> sig_;
393 mutable std::recursive_mutex mutex_;
397 class ObservableSettings :
public Singleton<ObservableSettings> {
403 std::lock_guard<std::mutex> lock(mutex_);
404 updatesType_ = (deferred) ? UpdatesDeferred : UpdatesDisabled;
408 bool updatesEnabled() {
return (updatesType_ & UpdatesEnabled) != 0; }
409 bool updatesDeferred() {
return (updatesType_ & UpdatesDeferred) != 0; }
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> > >
418 typedef std::set<ext::weak_ptr<Observer::Proxy>,
419 boost::owner_less<ext::weak_ptr<Observer::Proxy> > >
427 mutable std::mutex mutex_;
429 enum UpdateType { UpdatesDisabled = 0, UpdatesEnabled = 1, UpdatesDeferred = 2} ;
430 std::atomic<int> updatesType_;
441 const ext::shared_ptr<Observer::Proxy>& o) {
446 std::lock_guard<std::mutex> lock(mutex_);
449 updatesType_ = UpdatesEnabled;
452 bool successful =
true;
458 const ext::shared_ptr<Observer::Proxy> proxy = i->lock();
461 }
catch (std::exception& e) {
472 "could not notify one or more observers: " << errMsg);
494 proxy_.reset(
new Proxy(
this));
497 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
502 observable->registerObserver(proxy_);
506 std::lock_guard<std::recursive_mutex> lock(mutex_);
508 proxy_.reset(
new Proxy(
this));
512 observable->unregisterObserver(proxy_,
true);
515 std::lock_guard<std::recursive_mutex> lock(o.mutex_);
519 observable->registerObserver(proxy_);
525 std::lock_guard<std::recursive_mutex> lock(mutex_);
527 proxy_->deactivate();
530 observable->unregisterObserver(proxy_,
false);
533 inline std::pair<Observer::iterator, bool>
535 std::lock_guard<std::recursive_mutex> lock(mutex_);
537 proxy_.reset(
new Proxy(
this));
541 h->registerObserver(proxy_);
550 std::lock_guard<std::recursive_mutex> lock(o->mutex_);
552 for (
const auto& observable : o->observables_)
559 std::lock_guard<std::recursive_mutex> lock(mutex_);
562 h->unregisterObserver(proxy_,
true);
569 std::lock_guard<std::recursive_mutex> lock(mutex_);
572 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