Shinya Kitaoka 810553
#pragma once
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_OBSERVER_NOTIFIER_H
Toshihiro Shimizu 890ddd
#define TCG_OBSERVER_NOTIFIER_H
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "base.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  \file     tcg_observer_notifier.h
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \brief    This file contains the barebone of an elementary, classical
Toshihiro Shimizu 890ddd
            implementation of the Observer pattern requiring derivation.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \details  This is intended as a convenient and lightweight predefined
Toshihiro Shimizu 890ddd
            implementation when hardwiring the Observer pattern in a
Toshihiro Shimizu 890ddd
            known class using derivation.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            Observe that this implementation does not deal with the
Toshihiro Shimizu 890ddd
            actual notifications forwarding - it just manages the
Toshihiro Shimizu 890ddd
            set of observers/notifiers in a notifier/observer instance.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            No multithreading is taken into consideration.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \remark   See elsewhere for more advanced implementations.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace tcg {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Observer/notifier  base polymorphic classes
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class observer_base;
Toshihiro Shimizu 890ddd
class notifier_base;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class observer_base {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  virtual ~observer_base() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  virtual void attach(notifier_base *notifier) = 0;  //!< Adds the specified
Shinya Kitaoka 38fd86
  //! notifier to the internal
Shinya Kitaoka 38fd86
  //! set of notifiers.
Shinya Kitaoka 120a6e
  virtual void detach(notifier_base *notifier) = 0;  //!< Removes the specified
Shinya Kitaoka 38fd86
                                                     //! notifier from the
Shinya Kitaoka 38fd86
  //! internal set of
Shinya Kitaoka 38fd86
  //! notifiers.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class notifier_base {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  virtual ~notifier_base() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  virtual void attach(observer_base *observer) = 0;  //!< Adds the specified
Shinya Kitaoka 38fd86
  //! observer to the internal
Shinya Kitaoka 38fd86
  //! set of observers.
Shinya Kitaoka 120a6e
  virtual void detach(observer_base *observer) = 0;  //!< Removes the specified
Shinya Kitaoka 38fd86
                                                     //! observer from the
Shinya Kitaoka 38fd86
  //! internal set of
Shinya Kitaoka 38fd86
  //! observers.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Observer/notifier  with a single interacting object
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename base="observer_base" notifier="notifier_base," typename=""></typename>
Shinya Kitaoka 120a6e
class observer_single : public noncopyable<base> {
Shinya Kitaoka 120a6e
  Notifier *m_notifier;  // Not owned
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef Notifier notifier_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  observer_single() : m_notifier() {}
Shinya Kitaoka 120a6e
  ~observer_single() {
Shinya Kitaoka 120a6e
    if (m_notifier)
Shinya Kitaoka 120a6e
      static_cast<notifier_base *="">(m_notifier)</notifier_base>
Shinya Kitaoka 120a6e
          ->detach(
Shinya Kitaoka 120a6e
              this);  // The detaching function is most probably \a private in
Shinya Kitaoka 120a6e
  }                   // reimplemented notifier classes (like in this observer).
Shinya Kitaoka 120a6e
                      // Besides, it would be a virtual function call anyway.
Shinya Kitaoka 120a6e
  notifier_type *notifier() const { return m_notifier; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void attach(notifier_base *notifier) {
Shinya Kitaoka 120a6e
    assert(notifier && !m_notifier);
Shinya Kitaoka 120a6e
    m_notifier = static_cast<notifier *="">(notifier);</notifier>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void detach(notifier_base *notifier) {
Shinya Kitaoka 120a6e
    assert(m_notifier && m_notifier == static_cast<notifier *="">(notifier));</notifier>
Shinya Kitaoka 120a6e
    m_notifier = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename base="notifier_base" observer="observer_base," typename=""></typename>
Shinya Kitaoka 120a6e
class notifier_single : public noncopyable<base> {
Shinya Kitaoka 120a6e
  Observer *m_observer;  // Not owned
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef Observer observer_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  notifier_single() : m_observer() {}
Shinya Kitaoka 120a6e
  ~notifier_single() {
Shinya Kitaoka 120a6e
    if (m_observer) static_cast<observer_base *="">(m_observer)->detach(this);</observer_base>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  observer_type *observer() const { return m_observer; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addObserver(observer_type *observer) {
Shinya Kitaoka 120a6e
    notifier_single::attach(
Shinya Kitaoka 120a6e
        observer);  // No reason to go polymorphic here - it's this very class.
Shinya Kitaoka 120a6e
    static_cast<observer_base *="">(observer)->attach(</observer_base>
Shinya Kitaoka 120a6e
        this);  // However, here it's necessary - like above, downcast to
Shinya Kitaoka 120a6e
  }             // the very base.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void removeObserver(observer_type *observer) {
Shinya Kitaoka 120a6e
    static_cast<observer_base *="">(observer)->detach(this);</observer_base>
Shinya Kitaoka 120a6e
    notifier_single::detach(observer);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void attach(observer_base *observer) {
Shinya Kitaoka 120a6e
    assert(observer && !m_observer);
Shinya Kitaoka 120a6e
    m_observer = static_cast<observer *="">(observer);</observer>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void detach(observer_base *observer) {
Shinya Kitaoka 120a6e
    assert(m_observer && m_observer == static_cast<observer *="">(observer));</observer>
Shinya Kitaoka 120a6e
    m_observer = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Observer/notifier  with multiple interacting objects
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template 
Shinya Kitaoka 120a6e
          typename Set = std::set<notifier *="">></notifier>
Shinya Kitaoka 120a6e
class observer : public noncopyable<base> {
Shinya Kitaoka 120a6e
  Set m_notifiers;  // Not owned
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef Notifier notifier_type;
Shinya Kitaoka 120a6e
  typedef Set notifiers_container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ~observer() {
Shinya Kitaoka 120a6e
    typename Set::iterator nt, nEnd = m_notifiers.end();
Shinya Kitaoka 120a6e
    for (nt = m_notifiers.begin(); nt != nEnd; ++nt)
Shinya Kitaoka 120a6e
      static_cast<notifier_base *="">(*nt)->detach(this);</notifier_base>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const notifiers_container ¬ifiers() const { return m_notifiers; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void attach(notifier_base *notifier) {
Shinya Kitaoka 120a6e
    assert(notifier);
Shinya Kitaoka 120a6e
    m_notifiers.insert(static_cast<notifier *="">(notifier));</notifier>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void detach(notifier_base *notifier) {
Shinya Kitaoka 120a6e
    assert(!m_notifiers.empty());
Shinya Kitaoka 120a6e
    m_notifiers.erase(static_cast<notifier *="">(notifier));</notifier>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template 
Shinya Kitaoka 120a6e
          typename Set = std::set<observer *="">></observer>
Shinya Kitaoka 120a6e
class notifier : public noncopyable<base> {
Shinya Kitaoka 120a6e
  Set m_observers;  // Not owned
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef Observer observer_type;
Shinya Kitaoka 120a6e
  typedef Set observers_container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ~notifier() {
Shinya Kitaoka 120a6e
    typename Set::iterator ot, oEnd = m_observers.end();
Shinya Kitaoka 120a6e
    for (ot = m_observers.begin(); ot != oEnd; ++ot)
Shinya Kitaoka 120a6e
      static_cast<observer_base *="">(*ot)->detach(this);</observer_base>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const observers_container &observers() const { return m_observers; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addObserver(observer_type *observer) {
Shinya Kitaoka 120a6e
    notifier::attach(observer);
Shinya Kitaoka 120a6e
    static_cast<observer_base *="">(observer)->attach(this);</observer_base>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void removeObserver(observer_type *observer) {
Shinya Kitaoka 120a6e
    static_cast<observer_base *="">(observer)->detach(this);</observer_base>
Shinya Kitaoka 120a6e
    notifier::detach(observer);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void attach(observer_base *observer) {
Shinya Kitaoka 120a6e
    assert(observer);
Shinya Kitaoka 120a6e
    m_observers.insert(static_cast<observer *="">(observer));</observer>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void detach(observer_base *observer) {
Shinya Kitaoka 120a6e
    assert(!m_observers.empty());
Shinya Kitaoka 120a6e
    m_observers.erase(static_cast<observer *="">(observer));</observer>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace tcg
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#endif  // TCG_OBSERVER_NOTIFIER_H