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> ®1, 00088 csRef<iEventNameRegistry> ®2, 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