CrystalSpace

Public API Reference

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__

Generated for Crystal Space 1.0.2 by doxygen 1.4.7