| #pragma once |
| |
| #ifndef TCG_OBSERVER_NOTIFIER_H |
| #define TCG_OBSERVER_NOTIFIER_H |
| |
| |
| #include "base.h" |
| |
| |
| #include <set> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace tcg |
| { |
| |
| |
| |
| |
| |
| class observer_base; |
| class notifier_base; |
| |
| |
| |
| class observer_base |
| { |
| public: |
| virtual ~observer_base() {} |
| |
| virtual void attach(notifier_base *notifier) = 0; |
| virtual void detach(notifier_base *notifier) = 0; |
| }; |
| |
| |
| |
| class notifier_base |
| { |
| public: |
| virtual ~notifier_base() {} |
| |
| virtual void attach(observer_base *observer) = 0; |
| virtual void detach(observer_base *observer) = 0; |
| }; |
| |
| |
| |
| |
| |
| template <typename Notifier = notifier_base, typename Base = observer_base> |
| class observer_single : public noncopyable<Base> |
| { |
| Notifier *m_notifier; |
| |
| public: |
| typedef Notifier notifier_type; |
| |
| public: |
| observer_single() : m_notifier() {} |
| ~observer_single() |
| { |
| if (m_notifier) |
| static_cast<notifier_base *>(m_notifier)->detach(this); |
| } |
| |
| notifier_type *notifier() const { return m_notifier; } |
| |
| private: |
| void attach(notifier_base *notifier) |
| { |
| assert(notifier && !m_notifier); |
| m_notifier = static_cast<Notifier *>(notifier); |
| } |
| |
| void detach(notifier_base *notifier) |
| { |
| assert(m_notifier && m_notifier == static_cast<Notifier *>(notifier)); |
| m_notifier = 0; |
| } |
| }; |
| |
| |
| |
| template <typename Observer = observer_base, typename Base = notifier_base> |
| class notifier_single : public noncopyable<Base> |
| { |
| Observer *m_observer; |
| |
| public: |
| typedef Observer observer_type; |
| |
| public: |
| notifier_single() : m_observer() {} |
| ~notifier_single() |
| { |
| if (m_observer) |
| static_cast<observer_base *>(m_observer)->detach(this); |
| } |
| |
| observer_type *observer() const { return m_observer; } |
| |
| void addObserver(observer_type *observer) |
| { |
| notifier_single::attach(observer); |
| static_cast<observer_base *>(observer)->attach(this); |
| } |
| |
| void removeObserver(observer_type *observer) |
| { |
| static_cast<observer_base *>(observer)->detach(this); |
| notifier_single::detach(observer); |
| } |
| |
| private: |
| void attach(observer_base *observer) |
| { |
| assert(observer && !m_observer); |
| m_observer = static_cast<Observer *>(observer); |
| } |
| |
| void detach(observer_base *observer) |
| { |
| assert(m_observer && m_observer == static_cast<Observer *>(observer)); |
| m_observer = 0; |
| } |
| }; |
| |
| |
| |
| |
| |
| template <typename Notifier = notifier_base, typename Base = observer_base, |
| typename Set = std::set<Notifier *>> |
| class observer : public noncopyable<Base> |
| { |
| Set m_notifiers; |
| |
| public: |
| typedef Notifier notifier_type; |
| typedef Set notifiers_container; |
| |
| public: |
| ~observer() |
| { |
| typename Set::iterator nt, nEnd = m_notifiers.end(); |
| for (nt = m_notifiers.begin(); nt != nEnd; ++nt) |
| static_cast<notifier_base *>(*nt)->detach(this); |
| } |
| |
| const notifiers_container ¬ifiers() const |
| { |
| return m_notifiers; |
| } |
| |
| private: |
| void attach(notifier_base *notifier) |
| { |
| assert(notifier); |
| m_notifiers.insert(static_cast<Notifier *>(notifier)); |
| } |
| |
| void detach(notifier_base *notifier) |
| { |
| assert(!m_notifiers.empty()); |
| m_notifiers.erase(static_cast<Notifier *>(notifier)); |
| } |
| }; |
| |
| |
| |
| template <typename Observer = observer_base, typename Base = notifier_base, |
| typename Set = std::set<Observer *>> |
| class notifier : public noncopyable<Base> |
| { |
| Set m_observers; |
| |
| public: |
| typedef Observer observer_type; |
| typedef Set observers_container; |
| |
| public: |
| ~notifier() |
| { |
| typename Set::iterator ot, oEnd = m_observers.end(); |
| for (ot = m_observers.begin(); ot != oEnd; ++ot) |
| static_cast<observer_base *>(*ot)->detach(this); |
| } |
| |
| const observers_container &observers() const |
| { |
| return m_observers; |
| } |
| |
| void addObserver(observer_type *observer) |
| { |
| notifier::attach(observer); |
| static_cast<observer_base *>(observer)->attach(this); |
| } |
| |
| void removeObserver(observer_type *observer) |
| { |
| static_cast<observer_base *>(observer)->detach(this); |
| notifier::detach(observer); |
| } |
| |
| private: |
| void attach(observer_base *observer) |
| { |
| assert(observer); |
| m_observers.insert(static_cast<Observer *>(observer)); |
| } |
| |
| void detach(observer_base *observer) |
| { |
| assert(!m_observers.empty()); |
| m_observers.erase(static_cast<Observer *>(observer)); |
| } |
| }; |
| |
| } |
| |
| #endif |