- Main Page
- Classes
- Files
- Directories
- Related Pages

# glpublisher.h

    00001 /*
    00002 Copyright (c) 2000-2003 Lee Thomason (www.grinninglizard.com)
    00003 Grinning Lizard Utilities.
    00004
    00005 This software is provided 'as-is', without any express or implied
    00006 warranty. In no event will the authors be held liable for any
    00007 damages arising from the use of this software.
    00008
    00009 Permission is granted to anyone to use this software for any
    00010 purpose, including commercial applications, and to alter it and
    00011 redistribute it freely, subject to the following restrictions:
    00012
    00013 1. The origin of this software must not be misrepresented; you must
    00014 not claim that you wrote the original software. If you use this
    00015 software in a product, an acknowledgment in the product documentation
    00016 would be appreciated but is not required.
    00017
    00018 2. Altered source versions must be plainly marked as such, and
    00019 must not be misrepresented as being the original software.
    00020
    00021 3. This notice may not be removed or altered from any source
    00022 distribution.
    00023 */
    00024
    00025
    00026 #ifndef GRINLIZ_PUBLISHER_INCLUDED
    00027 #define GRINLIZ_PUBLISHER_INCLUDED
    00028
    00029 #ifdef _MSC_VER
    00030 #pragma warning( disable : 4786 )
    00031 #endif
    00032
    00033 #include <set>
    00034
    00035 namespace grinliz {
    00036
    00052 template< class LISTENER_CLASS >
    00053 class Publisher
    00054 {
    00055   public:
    00056
    00057     typedef typename std::set<LISTENER_CLASS*>::iterator iterator;
    00059     typedef typename std::set<LISTENER_CLASS*>::const_iterator const_iterator;
    00060
    00061         Publisher() : copyValid( false )        {}
    00062
    00063         ~Publisher()
    00064         {
    00065                 for(    iterator listenerIterator = listeners.begin();
    00066                                 listenerIterator != listeners.end();
    00067                                 ++listenerIterator )
    00068                 {
    00069                         (*listenerIterator)->publishers.erase( this );
    00070                 }
    00071         }
    00072
    00074         void AddListener( LISTENER_CLASS* add )
    00075         {
    00076                 copyValid = false;
    00077                 listeners.insert( add );
    00078                 add->publishers.insert( this );
    00079         }
    00080
    00083         void RemoveListener( LISTENER_CLASS* remove )
    00084         {
    00085                 copyValid = false;
    00086                 remove->publishers.erase( this );
    00087                 listeners.erase( remove );
    00088         }
    00089
    00101     const_iterator begin()      {       if ( !copyValid )
    00102                                                                 {
    00103                                                                         listenersCopy.clear();
    00104                                                                         listenersCopy = listeners;
    00105                                                                         copyValid = true;
    00106                                                                 }
    00107                                                                 return listenersCopy.begin();
    00108                                                         }
    00109
    00111     const_iterator end()      { return listenersCopy.end(); }
    00112
    00113         bool empty() { return listeners.empty(); }
    00114
    00115   private:
    00116         std::set<LISTENER_CLASS*> listeners;
    00117         // Okay, it's very natural to want to Add/Remove while iterating
    00118         // through the set. Even with documentation, it's just too easy
    00119         // a mistake to make. Changing the set while iterating will
    00120         // crash and invalidate the     set. To overcome this, begin() makes a copy.
    00121         // But we keep a flag around so this doesn't happen unless it needs to.
    00122         bool copyValid;
    00123         std::set<LISTENER_CLASS*> listenersCopy;
    00124 };
    00125
    00126
    00149 template <class LISTENER_CLASS>
    00150 class Listener
    00151 {
    00152         friend class Publisher< LISTENER_CLASS >;
    00153
    00154   private:
    00155         std::set< Publisher<LISTENER_CLASS>* > publishers;
    00156     typedef typename std::set< Publisher<LISTENER_CLASS>* >::iterator iterator;
    00157
    00158   public:
    00159         virtual ~Listener()
    00160         {
    00161             // This a strange bit of code. The RemoveListener call
    00162             // will result the Publisher class reaching into this class
    00163             // to erase the Publisher*. Therefore, the iterator will
    00164             // continually be invalidated; hence always use begin() and
    00165             // break if end().
    00166             //
    00167             // The other odd bit of code is the back-cast to our child
    00168             // type - LISTENER_CLASS. Sleazy c++ trick.
    00169             //
    00170                 while ( true )
    00171                 {
    00172                         iterator it = publishers.begin();
    00173                         if ( it == publishers.end() ) break;
    00174                         (*it)->RemoveListener( static_cast< LISTENER_CLASS* >( this ) );
    00175                 }
    00176         }
    00177 };
    00178
    00179 };      // namespace grinliz
    00180 #endif