/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ /*! \file handle.hpp \brief Globally accessible relinkable pointer */ #ifndef quantlib_handle_hpp #define quantlib_handle_hpp #include namespace QuantLib { //! Shared handle to an observable /*! All copies of an instance of this class refer to the same observable by means of a relinkable smart pointer. When such pointer is relinked to another observable, the change will be propagated to all the copies. \pre Class T must inherit from Observable */ template class Handle { protected: class Link : public Observable, public Observer { public: explicit Link(const boost::shared_ptr& h, bool registerAsObserver); void linkTo(const boost::shared_ptr&, bool registerAsObserver); bool empty() const { return !h_; } const boost::shared_ptr& currentLink() const { return h_; } void update() { notifyObservers(); } private: boost::shared_ptr h_; bool isObserver_; }; boost::shared_ptr link_; public: /*! \warning registerAsObserver is left as a backdoor in case the programmer cannot guarantee that the object pointed to will remain alive for the whole lifetime of the handle---namely, it should be set to false when the passed shared pointer does not own the pointee (this should only happen in a controlled environment, so that the programmer is aware of it). Failure to do so can very likely result in a program crash. If the programmer does want the handle to register as observer of such a shared pointer, it is his responsibility to ensure that the handle gets destroyed before the pointed object does. */ explicit Handle( const boost::shared_ptr& h = boost::shared_ptr(), bool registerAsObserver = true); //! dereferencing const boost::shared_ptr& currentLink() const; const boost::shared_ptr& operator->() const; //! checks if the contained shared pointer points to anything bool empty() const; //! allows registration as observable operator boost::shared_ptr() const; //! equality test template bool operator==(const Handle& other) { return link_ == other.link_; } //! disequality test template bool operator!=(const Handle& other) { return link_ != other.link_; } //! strict weak ordering template bool operator<(const Handle& other) { return link_ < other.link_; } }; //! Relinkable handle to an observable /*! An instance of this class can be relinked so that it points to another observable. The change will be propagated to all handles that were created as copies of such instance. \pre Class T must inherit from Observable */ template class RelinkableHandle : public Handle { public: /*! \warning see the Handle documentation for issues relatives to registerAsObserver. */ explicit RelinkableHandle( const boost::shared_ptr& h = boost::shared_ptr(), bool registerAsObserver = true); /*! \warning see the Handle documentation for issues relatives to registerAsObserver. */ void linkTo(const boost::shared_ptr&, bool registerAsObserver = true); }; // inline definitions template inline Handle::Link::Link(const boost::shared_ptr& h, bool registerAsObserver) : isObserver_(false) { linkTo(h,registerAsObserver); } template inline void Handle::Link::linkTo(const boost::shared_ptr& h, bool registerAsObserver) { if ((h != h_) || (isObserver_ != registerAsObserver)) { if (h_ && isObserver_) unregisterWith(h_); h_ = h; isObserver_ = registerAsObserver; if (h_ && isObserver_) registerWith(h_); notifyObservers(); } } template inline Handle::Handle(const boost::shared_ptr& h, bool registerAsObserver) : link_(new Link(h,registerAsObserver)) {} template inline const boost::shared_ptr& Handle::currentLink() const { QL_REQUIRE(!empty(), "empty Handle cannot be dereferenced"); return link_->currentLink(); } template inline const boost::shared_ptr& Handle::operator->() const { QL_REQUIRE(!empty(), "empty Handle cannot be dereferenced"); return link_->currentLink(); } template inline bool Handle::empty() const { return link_->empty(); } template inline Handle::operator boost::shared_ptr() const { return link_; } template inline RelinkableHandle::RelinkableHandle(const boost::shared_ptr& h, bool registerAsObserver) : Handle(h,registerAsObserver) {} template inline void RelinkableHandle::linkTo(const boost::shared_ptr& h, bool registerAsObserver) { this->link_->linkTo(h,registerAsObserver); } } #endif