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 #ifdef CS_DEBUG
00123   csString *self_name;
00124 #endif
00125   csEventQueue *queue;
00126   
00127   bool SubscribeInternal (csHandlerID, csEventID);
00128   void UnsubscribeInternal (csHandlerID);
00137   bool fatNode;
00138 
00146   class FatRecordObject
00147   {
00148   private:
00149     csRef<iEventHandlerRegistry> handler_reg;
00150     csRef<iEventNameRegistry> name_reg;
00151   public:
00152     FatRecordObject(csEventTree *root,
00153                     csRef<iEventHandlerRegistry> &h_reg,
00154                     csRef<iEventNameRegistry> &n_reg,
00155                     csPartialOrder<csHandlerID> *new_sg,
00156                     csList<iEventHandler *> *new_sq) :
00157       handler_reg (h_reg), name_reg (n_reg), 
00158       SubscriberGraph (new_sg), SubscriberQueue (new_sq), 
00159       my_root (root), iterator (0), iterating_for (0)
00160     {
00161       /* If there's no SQ, mark it for creation */
00162       StaleSubscriberQueue = (SubscriberQueue==0);
00163     }
00164 
00165     ~FatRecordObject()
00166     {
00167       delete SubscriberGraph;
00168       if (SubscriberQueue)
00169         delete SubscriberQueue;
00170       CS_ASSERT (iterator == 0);
00171       CS_ASSERT (iterating_for == 0);
00172     }
00173 
00177     void RebuildQueue();
00181     csPartialOrder<csHandlerID> *SubscribeInternal(csHandlerID, csEventID);
00185     void UnsubscribeInternal(csHandlerID);
00186 
00190     csPartialOrder<csHandlerID> *SubscriberGraph;
00195     csList<iEventHandler *> *SubscriberQueue;
00201     bool StaleSubscriberQueue;
00205     csEventTree *my_root;
00211     SubscriberIterator *iterator;
00216     csEventTree *iterating_for;
00217   };
00218 
00219   FatRecordObject *fatRecord;
00220 
00227   void ForceFatCopy();
00228 
00233   void KillFatCopy();
00234 
00240   void PushFatCopy(FatRecordObject *);
00241   
00242 
00243  public:
00254   class SubscriberIterator 
00255   {
00256   public:
00261     SubscriberIterator (csRef<iEventHandlerRegistry> &r, 
00262                         csEventTree *t, csEventID bevent) : 
00263       handler_reg(r), record(t->fatRecord), 
00264       baseevent(bevent), mode(SI_LIST), qit(*t->fatRecord->SubscriberQueue,
00265         false)
00266     {
00267       CS_ASSERT(record->iterator == 0);
00268       record->iterator = this;
00269       record->iterating_for = t;
00270     }
00271 
00275     ~SubscriberIterator ()
00276     {
00277       CS_ASSERT(record->iterator == this);
00278       record->iterator = 0;
00279       record->iterating_for = 0;
00280     }
00281 
00283     inline bool HasNext () 
00284     {
00285       switch(mode) 
00286       {
00287       case SI_LIST:
00288         return qit.HasNext ();
00289         
00290       case SI_GRAPH:
00291         do 
00292         {
00293           csHandlerID id = record->SubscriberGraph->GetEnabled (
00294                 CS_HANDLER_INVALID);
00295           if (id == CS_HANDLER_INVALID)
00296             break;
00297           else if (handler_reg->IsInstance(id))
00298             return true;
00299           else
00300             record->SubscriberGraph->Mark(id);
00301         } 
00302         while (true);
00303         return false;
00304         
00305       default:
00306         CS_ASSERT((mode == SI_LIST) ||
00307                   (mode == SI_GRAPH));
00308         return false;
00309       }
00310     }
00311 
00313     inline iEventHandler *Next () 
00314     {
00315       switch(mode) 
00316       {
00317       case SI_LIST:
00318         /* DOME : see if the current element has been deleted. */
00319         return qit.Next ();
00320         
00321       case SI_GRAPH:
00322         /* see if the current element has been flagged for deletion. */
00323         do 
00324         {
00325           csHandlerID id = record->SubscriberGraph->GetEnabled (
00326                 CS_HANDLER_INVALID);
00327           if (id == CS_HANDLER_INVALID)
00328             break;
00329           else if (handler_reg->IsInstance (id)) 
00330           {
00331             record->SubscriberGraph->Mark (id);
00332             return handler_reg->GetHandler (id);
00333           } 
00334           else
00335             record->SubscriberGraph->Mark(id);
00336         } 
00337         while (true);
00338         return 0;
00339         
00340       default:
00341         CS_ASSERT((mode == SI_LIST) ||
00342                   (mode == SI_GRAPH));
00343         return 0;
00344       }
00345     }
00346     
00347     /* SI_GRAPH mode data structures and methods */
00348     void GraphMode (); // change to graph (SI_GRAPH) iterator mode.
00349     
00350   private:
00351     friend class csEventTree;
00352 
00353     csRef<iEventHandlerRegistry> handler_reg;
00354     FatRecordObject *record;
00355     csEventID baseevent;
00356     enum
00357     {
00358       SI_LIST,
00359       SI_GRAPH
00360     } mode;
00361     
00362     /* SI_LIST mode data structures */
00363     csList<iEventHandler *>::Iterator qit;
00364   };
00365   friend class SubscriberIterator;
00366   
00371   SubscriberIterator *GetIterator();
00372 
00373 };
00374 
00375 #endif // __CS_CSEVENTSUBSCRIPTION_H__

Generated for Crystal Space by doxygen 1.4.6