Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

/home/pete/Work/TSE3.svn/tse3/src/tse3/Notifier.h

Go to the documentation of this file.
00001 /*
00002  * @(#)Notifier.h 3.00 13 July 2000
00003  *
00004  * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org)
00005  *
00006  * This file is part of TSE3 - the Trax Sequencer Engine version 3.00.
00007  *
00008  * This library is modifiable/redistributable under the terms of the GNU
00009  * General Public License.
00010  *
00011  * You should have received a copy of the GNU General Public License along
00012  * with this program; see the file COPYING. If not, write to the Free Software
00013  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00014  *
00015  */
00016 
00017 #ifndef TSE3_NOTIFIER_H
00018 #define TSE3_NOTIFIER_H
00019 
00020 #include <iostream>
00021 
00022 /******************************************************************************
00023  * This file contains the implementation of the TSE3 Notifier framework.
00024  * It is the TSE3 implementation of the observer design pattern (GoF book).
00025  *
00026  * The public API (the Notifier and Listener classes) for this framework can
00027  * be found in the bottom half of the file, the top half contains internal
00028  * implementation concerns.
00029  *
00030  * This implementation can cope with listener event methods with between
00031  * zero and four parameters. This can be extended, by adding extra code
00032  * at the positions marked with (*)
00033  *****************************************************************************/
00034 
00035 /*
00036  * A few annoying presentation choices have been made in this file because
00037  * KDOC (2.0.36) falls over. Notably some short classes have been spread
00038  * out, and there is a ";" at the end of the Impl namespace.
00039  *
00040  * Other namespaces in the TSE3 library have a similar problem. In each
00041  * case the trailing ";" is intentional. Sigh.
00042  */
00043 
00044 namespace TSE3
00045 {
00046     template <class interface_type> class Listener;
00047 
00048     /**************************************************************************
00049      * Notifier implementation details: ignore this bit
00050      *************************************************************************/
00051 
00069     namespace Impl
00070     {
00077         class def_type
00078         {
00079         };
00080 
00089         template <typename T>
00090         struct arg_count
00091         {
00092             enum { count=1 };
00093         };
00094         template <>
00095         struct arg_count<def_type>
00096         {
00097             enum { count=0 };
00098         };
00099 
00107         template<unsigned>
00108         class num_type
00109         {
00110         };
00111 
00125         class void_list
00126         {
00127             public:
00128 
00129                 void_list();
00130                 void_list(const void_list &);
00131                 ~void_list();
00132 
00143                 bool push_back(void *p);
00144 
00151                 bool erase(void *p);
00152 
00158                 unsigned int size() const;
00159 
00166                 void *operator[](unsigned int index);
00167 
00174                 bool contains(void *p) const;
00175 
00176             private:
00177 
00178                 void_list &operator=(const void_list &);
00179 
00180                 class impl;
00181                 impl *pimpl;
00182         };
00183 
00199         template <class interface_type, typename listener_func,
00200                   typename p1_type = def_type,
00201                   typename p2_type = def_type,
00202                   typename p3_type = def_type,
00203                   typename p4_type = def_type>                           // (*)
00204         class Event
00205         {
00206             public:
00207 
00213                 explicit Event(listener_func func,
00214                                const p1_type &p1 = p1_type(),
00215                                const p2_type &p2 = p2_type(),
00216                                const p3_type &p3 = p3_type(),
00217                                const p4_type &p4 = p4_type())            // (*)
00218                     : func(func), p1(p1), p2(p2), p3(p3), p4(p4) {}      // (*)
00219 
00227                 void callOnEvery(void_list &listeners)
00228                 {
00229                     const unsigned int argCount = arg_count<p1_type>::count
00230                                                 + arg_count<p2_type>::count
00231                                                 + arg_count<p3_type>::count
00232                                                 + arg_count<p4_type>::count;
00233                                                                          // (*)
00234                     void_list copy_list(listeners);
00235                     for (unsigned int i = 0; i < copy_list.size(); ++i)
00236                     {
00237                         if (listeners.contains(copy_list[i]))
00238                         {
00239                             typedef Listener<interface_type> listener_type;
00240                             interface_type *listener
00241                                 = static_cast<listener_type*>(copy_list[i]);
00242                             invokeImpl(listener, num_type<argCount>());
00243                         }
00244                     }
00245                 }
00246 
00247             private:
00248 
00260                 template <class T>
00261                 void invokeImpl(T *listener, num_type<0>) const
00262                 {
00263                     (void)(listener->*func)();
00264                 }
00265                 template <class T>
00266                 void invokeImpl(T *listener, num_type<1>) const
00267                 {
00268                     (void)(listener->*func)(p1);
00269                 }
00270                 template <class T>
00271                 void invokeImpl(T *listener, num_type<2>) const
00272                 {
00273                     (void)(listener->*func)(p1, p2);
00274                 }
00275                 template <class T>
00276                 void invokeImpl(T *listener, num_type<3>) const
00277                 {
00278                     (void)(listener->*func)(p1, p2, p3);
00279                 }
00280                 template <class T>
00281                 void invokeImpl(T *listener, num_type<4>) const
00282                 {
00283                     (void)(listener->*func)(p1, p2, p3, p4);
00284                 }                                                        // (*)
00285 
00286                 const listener_func  func;
00287                 const p1_type       &p1;
00288                 const p2_type       &p2;
00289                 const p3_type       &p3;
00290                 const p4_type       &p4;                                 // (*)
00291         };
00292 
00293     };
00294 
00295     /**************************************************************************
00296      * Public Notifier framework API
00297      *************************************************************************/
00298 
00360     template <class interface_type>
00361     class Notifier
00362     {
00363         public:
00364 
00368             typedef Listener<interface_type> listener_type;
00369 
00370             friend class listener_type;
00371 
00372         protected:
00373 
00381             Notifier() {}
00382 
00387             typedef typename interface_type::notifier_type c_notifier_type;
00388 
00408             template <typename func_type>
00409             void notify(func_type func)
00410             {
00411                 typedef
00412                     Impl::Event<interface_type, func_type, c_notifier_type*>
00413                     event_type;
00414                 event_type(func, static_cast<c_notifier_type*>(this))
00415                     .callOnEvery(listeners);
00416             }
00417 
00421             template <typename func_type, typename p1_type>
00422             void notify(func_type func, const p1_type &p1)
00423             {
00424                 typedef
00425                     Impl::Event<interface_type, func_type, c_notifier_type *,
00426                                 p1_type>
00427                     event_type;
00428                 event_type(func, static_cast<c_notifier_type*>(this), p1)
00429                     .callOnEvery(listeners);
00430             }
00431 
00435             template <typename func_type, typename p1_type, typename p2_type>
00436             void notify(func_type func, const p1_type &p1, const p2_type &p2)
00437             {
00438                 typedef
00439                     Impl::Event<interface_type, func_type, c_notifier_type *,
00440                                 p1_type, p2_type>
00441                     event_type;
00442                 event_type(func, static_cast<c_notifier_type*>(this), p1, p2)
00443                     .callOnEvery(listeners);
00444             }
00445 
00449             template <typename func_type, typename p1_type, typename p2_type,
00450                       typename p3_type>
00451             void notify(func_type func, const p1_type &p1, const p2_type &p2,
00452                         const p3_type &p3)
00453             {
00454                 typedef
00455                     Impl::Event<interface_type, func_type, c_notifier_type *,
00456                                 p1_type, p2_type, p3_type>
00457                     event_type;
00458                 event_type
00459                     (func, static_cast<c_notifier_type*>(this), p1, p2, p3)
00460                     .callOnEvery(listeners);
00461             }                                                            // (*)
00462 
00467             virtual ~Notifier()
00468             {
00469                 // LOCK
00470                 for (unsigned int i = 0; i < listeners.size(); ++i)
00471                 {
00472                     listener_type *l
00473                         = static_cast<listener_type*>(listeners[i]);
00474                     l->NotifierImpl_Deleted
00475                         (static_cast<c_notifier_type*>(this));
00476                 }
00477             }
00478 
00479             unsigned int numListeners() const { return listeners.size(); }
00480 
00481         private:
00482 
00499             bool attach(listener_type *listener)
00500             {
00501                 // LOCK
00502                 return listeners.push_back(listener);
00503             }
00504 
00515             void detach(listener_type *listener)
00516             {
00517                 // LOCK
00518                 listeners.erase(listener);
00519             }
00520 
00521             typedef Notifier<interface_type> self_type;
00522 
00523             Notifier(const self_type &);
00524             self_type &operator=(const self_type &);
00525 
00526             Impl::void_list listeners;
00527     };
00528 
00567     template <class interface_type>
00568     class Listener : public interface_type
00569     {
00570         public:
00571 
00575             typedef Notifier<interface_type> notifier_type;
00576 
00587             void attachTo(notifier_type *notifier)
00588             {
00589                 if (notifier->attach(this)) notifiers.push_back(notifier);
00590             }
00591 
00600             void detachFrom(notifier_type *notifier)
00601             {
00602                 if (notifiers.erase(notifier)) notifier->detach(this);
00603             }
00604 
00605             friend class notifier_type;
00606 
00607         protected:
00608 
00617             Listener() {}
00618 
00623             typedef typename interface_type::notifier_type c_notifier_type;
00624 
00638             virtual void Notifier_Deleted(c_notifier_type * /*notifier*/) {}
00639 
00648             virtual ~Listener()
00649             {
00650                 // LOCK
00651                 for (unsigned int i = 0; i < notifiers.size(); ++i)
00652                 {
00653                     notifier_type *n
00654                         = static_cast<notifier_type*>(notifiers[i]);
00655                     n->detach(this);
00656                 }
00657             }
00658 
00659         private:
00660 
00671             void NotifierImpl_Deleted(c_notifier_type *src)
00672             {
00673                 notifiers.erase(static_cast<notifier_type*>(src));
00674                 this->Notifier_Deleted(src);
00675             }
00676 
00677             typedef Listener<interface_type> self_type;
00678 
00679             Listener(const self_type &);
00680             self_type &operator=(const self_type &);
00681 
00682             Impl::void_list notifiers;
00683     };
00684 }
00685 
00686 #endif

Generated on Wed May 25 14:45:09 2005 for TSE3 by doxygen 1.3.2