csutil/cssubscription.h
00001 /* 00002 Crystal Space 3D engine - Event Subscription internals 00003 Copyright (C) 2005 by Adam D. Bradley <[email protected]> 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 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 by doxygen 1.4.7