## Public API Reference

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# csutil/cssubscription.h

    00001 /*
    00002   Crystal Space 3D engine - Event Subscription internals
    00003   Copyright (C) 2005 by Adam D. Bradley <artdodge@cs.bu.edu>
    00004
    00005   This library is free software; you can redistribute it and/or
    00006   modify it under the terms of the GNU Library General Public
    00007   License as published by the Free Software Foundation; either
    00008   version 2 of the License, or (at your option) any later version.
    00009
    00010   This library is distributed in the hope that it will be useful,
    00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013   Library General Public License for more details.
    00014
    00015   You should have received a copy of the GNU Library General Public
    00016   License along with this library; if not, write to the Free
    00017   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    00018 */
    00019
    00020 #ifndef __CS_CSEVENTSUBSCRIPTION_H__
    00021 #define __CS_CSEVENTSUBSCRIPTION_H__
    00022
    00023 #include "csutil/partialorder.h"
    00024 #include "csutil/tree.h"
    00025 #include "csutil/list.h"
    00026 #include "csutil/eventhandlers.h"
    00027 #include "iutil/eventh.h"
    00028
    00029 class csEventQueue;
    00030
    00031
    00041 class csEventTree : public csTreeNode
    00042 {
    00043 public:
    00044   // forward declarator
    00045   class SubscriberIterator;
    00046
    00052   csEventTree *FindNode (csEventID name, csEventQueue *q);
    00059   bool Subscribe (csHandlerID, csEventID, csEventQueue *q);
    00069   void Unsubscribe(csHandlerID, csEventID, csEventQueue *q);
    00070
    00075   void Notify();
    00080   void Dispatch(iEvent &e);
    00081
    00082 #ifdef ADB_DEBUG
    00083   // Dump the event tree and subscriptions to stderr.
    00084   void Dump();
    00085 #endif
    00086
    00087   static inline csEventTree *CreateRootNode(csRef<iEventHandlerRegistry> &reg1,
    00088                                             csRef<iEventNameRegistry> &reg2,
    00089                                             csEventQueue *q)
    00090   {
    00091     return new csEventTree (reg1, reg2, reg2->GetID(""), 0, q);
    00092   }
    00093
    00094   static inline void DeleteRootNode(csEventTree *node)
    00095   {
    00096     CS_ASSERT(node);
    00097     CS_ASSERT(node->self == node->name_reg->GetID(""));
    00098     delete node;
    00099   }
    00100
    00101 private:
    00102   csRef<iEventHandlerRegistry> handler_reg;
    00103   csRef<iEventNameRegistry> name_reg;
    00104 #ifdef ADB_DEBUG
    00105   void Dump(int depth);
    00106 #endif
    00107
    00108   csEventTree *FindNodeInternal(csEventID &name, csEventQueue *q);
    00109
    00116   csEventTree (csRef<iEventHandlerRegistry> &,
    00117                csRef<iEventNameRegistry> &,
    00118                csEventID name, csEventTree *parent, csEventQueue *q);
    00119   ~csEventTree ();
    00120
    00121   csEventID self;
    00122   csEventQueue *queue;
    00123
    00124   bool SubscribeInternal (csHandlerID, csEventID);
    00125   void UnsubscribeInternal (csHandlerID);
    00134   bool fatNode;
    00135
    00143   class FatRecordObject
    00144   {
    00145   private:
    00146     csRef<iEventHandlerRegistry> handler_reg;
    00147     csRef<iEventNameRegistry> name_reg;
    00148   public:
    00149     FatRecordObject(csEventTree *root,
    00150                     csRef<iEventHandlerRegistry> &h_reg,
    00151                     csRef<iEventNameRegistry> &n_reg,
    00152                     csPartialOrder<csHandlerID> *new_sg,
    00153                     csList<iEventHandler *> *new_sq) :
    00154       handler_reg (h_reg), name_reg (n_reg),
    00155       SubscriberGraph (new_sg), SubscriberQueue (new_sq),
    00156       my_root (root), iterator (0), iterating_for (0)
    00157     {
    00158       /* If there's no SQ, mark it for creation */
    00159       StaleSubscriberQueue = (SubscriberQueue==0);
    00160     }
    00161
    00162     ~FatRecordObject()
    00163     {
    00164       delete SubscriberGraph;
    00165       if (SubscriberQueue)
    00166         delete SubscriberQueue;
    00167       CS_ASSERT (iterator == 0);
    00168       CS_ASSERT (iterating_for == 0);
    00169     }
    00170
    00174     void RebuildQueue();
    00178     csPartialOrder<csHandlerID> *SubscribeInternal(csHandlerID, csEventID);
    00182     void UnsubscribeInternal(csHandlerID);
    00183
    00187     csPartialOrder<csHandlerID> *SubscriberGraph;
    00192     csList<iEventHandler *> *SubscriberQueue;
    00198     bool StaleSubscriberQueue;
    00202     csEventTree *my_root;
    00208     SubscriberIterator *iterator;
    00213     csEventTree *iterating_for;
    00214   };
    00215
    00216   FatRecordObject *fatRecord;
    00217
    00224   void ForceFatCopy();
    00225
    00230   void KillFatCopy();
    00231
    00237   void PushFatCopy(FatRecordObject *);
    00238
    00239
    00240  public:
    00251   class SubscriberIterator
    00252   {
    00253   public:
    00258     SubscriberIterator (iEventHandlerRegistry* r, csEventTree *t,
    00259       csEventID bevent) : handler_reg(r), record(t->fatRecord),
    00260         baseevent(bevent), mode(SI_LIST), qit(0)
    00261     {
    00262       CS_ASSERT(record->iterator == 0);
    00263       record->iterator = this;
    00264       record->iterating_for = t;
    00265       if (t->fatRecord->SubscriberQueue)
    00266         qit = new csList<iEventHandler *>::Iterator (
    00267           *t->fatRecord->SubscriberQueue);
    00268       else
    00269         GraphMode();
    00270     }
    00271
    00275     ~SubscriberIterator ()
    00276     {
    00277       CS_ASSERT(record->iterator == this);
    00278       record->iterator = 0;
    00279       record->iterating_for = 0;
    00280       delete qit;
    00281     }
    00282
    00284     inline bool HasNext ()
    00285     {
    00286       switch(mode)
    00287       {
    00288       case SI_LIST:
    00289         return qit->HasNext ();
    00290
    00291       case SI_GRAPH:
    00292         do
    00293         {
    00294           csHandlerID id = record->SubscriberGraph->GetEnabled (
    00295                 CS_HANDLER_INVALID);
    00296           if (id == CS_HANDLER_INVALID)
    00297             break;
    00298           else if (handler_reg->IsInstance(id))
    00299             return true;
    00300           else
    00301             record->SubscriberGraph->Mark(id);
    00302         }
    00303         while (true);
    00304         return false;
    00305
    00306       default:
    00307         CS_ASSERT((mode == SI_LIST) ||
    00308                   (mode == SI_GRAPH));
    00309         return false;
    00310       }
    00311     }
    00312
    00314     inline iEventHandler *Next ()
    00315     {
    00316       switch(mode)
    00317       {
    00318       case SI_LIST:
    00319         /* DOME : see if the current element has been deleted. */
    00320         return qit->Next ();
    00321
    00322       case SI_GRAPH:
    00323         /* see if the current element has been flagged for deletion. */
    00324         do
    00325         {
    00326           csHandlerID id = record->SubscriberGraph->GetEnabled (
    00327                 CS_HANDLER_INVALID);
    00328           if (id == CS_HANDLER_INVALID)
    00329             break;
    00330           else if (handler_reg->IsInstance (id))
    00331           {
    00332             record->SubscriberGraph->Mark (id);
    00333             return handler_reg->GetHandler (id);
    00334           }
    00335           else
    00336             record->SubscriberGraph->Mark(id);
    00337         }
    00338         while (true);
    00339         return 0;
    00340
    00341       default:
    00342         CS_ASSERT((mode == SI_LIST) ||
    00343                   (mode == SI_GRAPH));
    00344         return 0;
    00345       }
    00346     }
    00347
    00348     /* SI_GRAPH mode data structures and methods */
    00349     void GraphMode (); // change to graph (SI_GRAPH) iterator mode.
    00350
    00351   private:
    00352     friend class csEventTree;
    00353     friend class csEventQueueTest;
    00354
    00355     csRef<iEventHandlerRegistry> handler_reg;
    00356     FatRecordObject *record;
    00357     csEventID baseevent;
    00358     enum
    00359     {
    00360       SI_LIST,
    00361       SI_GRAPH
    00362     } mode;
    00363
    00364     /* SI_LIST mode data structures */
    00365     csList<iEventHandler *>::Iterator* qit;
    00366   };
    00367   friend class SubscriberIterator;
    00368   friend class csEventQueueTest;
    00369
    00374   SubscriberIterator *GetIterator();
    00375
    00376 };
    00377
    00378 #endif // __CS_CSEVENTSUBSCRIPTION_H__