014
29.08.2006, 23:50 Uhr
(un)wissender
Niveauwart
|
Observable.cpp
C++: |
#include <boost/bind.hpp> #include <stdexcept> #include <algorithm> #include <utility>
#include <iostream>
namespace obs { namespace { template<bool init, bool exit> class BoolGuard { public: inline BoolGuard(bool & mybool); inline ~BoolGuard(); inline bool isBoolValue() const; inline void setBoolValue(bool value);
private: bool & _bool; }; template<class T, class V> class ObserverUpdater { public: inline ObserverUpdater(T &observerToUpdate, V const& updater); inline ~ObserverUpdater(); private: T & _observerToUpdate; V const& _updater; }; }
template<class T> Observable<T>::Observable() : _notify(false) { }
template<class T> Observable<T>::~Observable() { }
template<class T> void Observable<T>::registerObserver(T const& observer) { std::pair<std::set<T>::iterator, bool> res; if(_notify) { //Nur einmal merken! res = _observerToInsert.insert(observer); //Wenn vorhanden, das wieder löschen verhindern. if(res.second) { _observerToErase.erase(observer); } } else { res = _observer.insert(observer); } if(!res.second) { throw std::logic_error( "Observer ist already registered."); } }
template<class T> void Observable<T>::unregisterObserver(T const& observer) { if(_notify) { //Nur einmal merken! _observerToErase.insert(observer); //Wenn vorhanden, das wieder einfügen verhindern. _observerToInsert.erase(observer); } else { _observer.erase(observer); } } template<class T> template<class U> void Observable<T>::notify(U const& u, bool allowRecursiveNotify) { if(_notify) { if(!allowRecursiveNotify) { throw std::runtime_error( "runtime_error: Recursive call of notify."); } else { _recursive = true; return; } } BoolGuard<false, false> recursiveGuard(_recursive); BoolGuard<true, false> notifyGuard(_notify);
std::for_each(_observer.begin(), _observer.end(), u); typedef std::set<TestObserver *>::size_type (std::set<TestObserver *>::*Eraser) (typename std::set<TestObserver *>::key_type const&); Eraser eraser = &std::set<T>::erase; makeObserverUpdater(_observerToErase, boost::bind(eraser, &_observer, _1));
typedef std::pair<typename std::set<T>::iterator, bool> (std::set<TestObserver *>::*Inserter) (typename std::set<TestObserver *>::key_type const&); Inserter inserter = &std::set<T>::insert; makeObserverUpdater(_observerToInsert, boost::bind(inserter, &_observer, _1)); if(recursiveGuard.isBoolValue()) { notifyGuard.setBoolValue(false); if(!allowRecursiveNotify) { throw std::runtime_error( "runtime_error: Recursive call of notify."); } notify(u, allowRecursiveNotify); } } template<class T> bool Observable<T>::hasObserver(T const& observer) const { bool found = _observer.end() != _observer.find(observer); if(_notify) { return (found && //vorhanden und nicht zu löschen //und nicht hinzuzufügen _observerToErase.end() == _observerToErase.find(observer)) || (!found && //nicht gefunden, wird ab hinzugefügt _observerToInsert.end() != _observerToInsert.find(observer)); } return found; }
template<class T> template<class Y, class X> void Observable<T>::makeObserverUpdater(Y & toUpdate, X const& x) { ObserverUpdater<Y, X>(toUpdate, x); }
namespace { template<bool init, bool exit> BoolGuard<init, exit>::BoolGuard(bool & mybool) : _bool(mybool) { _bool = init; }
template<bool init, bool exit> BoolGuard<init, exit>::~BoolGuard() { _bool = exit; }
template<bool init, bool exit> bool BoolGuard<init, exit>::isBoolValue() const { return _bool; }
template<bool init, bool exit> void BoolGuard<init, exit>::setBoolValue(bool value) { _bool = value; }
template<class T, class V> ObserverUpdater<T, V>::ObserverUpdater( T &observerToUpdate, V const& updater) : _observerToUpdate(observerToUpdate), _updater(updater) { }
template<class T, class V> ObserverUpdater<T, V>::~ObserverUpdater() { try { std::for_each(_observerToUpdate.begin(), _observerToUpdate.end(), _updater); _observerToUpdate.clear(); } catch(...) { _observerToUpdate.clear(); } } } };
|
-- Wer früher stirbt ist länger tot. |