| Polaris: Iterator.h Source File | ||
|
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members
Iterator.hGo to the documentation of this file.00001 /// 00002 /// 00003 #ifndef _ITERATOR_H 00004 #define _ITERATOR_H 00005 /// 00006 #include <stdlib.h> 00007 /// 00008 #include "Assign.h" 00009 #include "BaseIter.h" 00010 #include "TypedCollection.h" 00011 #include "ghost_enum.h" 00012 /// 00013 #include "../macros.h" 00014 /// 00015 #define CLEAN_ITERATOR 1 /* */ 00016 /// 00017 /// \class Iterator 00018 /// \brief 00019 /// Iterator class that works on various Collection-related classes. 00020 /// 00021 /// These Iterators can operate on any structure derived from Collection 00022 /// (which doesn't violate a couple of simple rules discussed at 00023 /// the end). An Iterator declared to be of type T can iterate over 00024 /// any of Collection structure also of type T. A single Iterator 00025 /// can also be used to Iterate over multiple Collection-classes 00026 /// as long as they are all of type T. That is, an Iterator<Expression>, 00027 /// ExIter, can Iterate over a Set<Expression>, then a List<Expression> 00028 /// and then a RefList<Expression>. 00029 /// 00030 /// Note that in the following, if _last_elem_ptr comes before _first_elem_ptr 00031 /// in the list, the iteration space will be empty 00032 /// 00033 /// Declare an iterator: 00034 /// \code 00035 /// Iterator<T> Li = some_coll; 00036 /// 00037 /// (will iterate from the first to the last elements in the list. 00038 /// Note when previously declared iterators are assigned to a 00039 /// different list, they loose all of there specifications 00040 /// including the iteration space and the conditional function.) 00041 /// 00042 /// --or-- 00043 /// 00044 /// Iterator<T> Li(some_coll) 00045 /// (same as above) 00046 /// 00047 /// --or-- 00048 /// 00049 /// Iterator<T> Li(some_coll, first_elem_ptr, last_elem_ptr); 00050 /// (will iterate from first_elem_ptr to last_elem_ptr, inclusive) 00051 /// 00052 /// --or-- 00053 /// 00054 /// Iterator<T> Li(some_coll, cond_proc, extra_data); 00055 /// (will iterate only over those (in order) where the call 00056 /// (*cond_proc)(Li.current(), extra_data) returns non-zero) 00057 /// 00058 /// --or-- 00059 /// 00060 /// Iterator<T> Li(some_coll, first_elem_ptr, last_elem_ptr, 00061 /// cond_proc, extra_data); 00062 /// (will iterate only over those (in order) from first_elem_ptr to 00063 /// last_elem_ptr where the call (*cond_proc)(Li.current(), extra_data) 00064 /// returns non-zero) 00065 /// \endcode 00066 /// 00067 /// Example: 00068 /// 00069 /// \code 00070 /// Iterator<IntElem> Li(some_coll, first_ptr, last_ptr); 00071 /// 00072 /// while (!Li.end()) { /* or use valid() */ 00073 /// cout << Li.current() << ", "; 00074 /// if (f(Li.current())) 00075 /// some_coll.del(Li.current()); 00076 /// Li.next(); /* or use ++Li */ 00077 /// } 00078 /// \endcode 00079 /// 00080 /// Resetting the iterator to the start of the subrange: 00081 /// \code 00082 /// Li.reset() 00083 /// \endcode 00084 /// 00085 /// \endcode 00086 /// \section List List Modifications 00087 /// 00088 /// This implementation works with the reference counting 00089 /// scheme of Collections. Thus, it is not possible for an 00090 /// element of a Collection to be deleted out from under 00091 /// an iterator. It is possible, however, for the current() 00092 /// node to suddenly become invalid--that is for the object 00093 /// suddenly being made inaccessable, turning the current 00094 /// node into a ghost-node. It is illegal to try to access 00095 /// the current node if it is a ghost-node. This can be 00096 /// checked by calling current_valid(). 00097 /// 00098 /// Ghost nodes can only be encountered in live structures by 00099 /// loosing ownership of the current node, but they are more 00100 /// frequent in reference structures. If an object is 00101 /// deleted from a live structure, references to it will 00102 /// remain. These, too, become "ghost-nodes". 00103 /// By default, ghost-nodes are skipped over by the iterator. 00104 /// For example, all of the Iterators described above skip 00105 /// over ghost-nodes. However, if an iterator is declared as 00106 /// the default, it is still possible to check for ghost nodes 00107 /// within the iteration space 00108 /// by calling next() and prev() using the argument: 00109 /// next(STOP_ON_GHOSTS) --or-- prev(STOP_ON_GHOSTS) 00110 /// 00111 /// Also, it is possible to declare an iterator which will 00112 /// always stop on the ghost nodes. This is done by passing 00113 /// a flag in the constructor after the name of the 00114 /// list. This can be done as follows: 00115 /// 00116 /// \code 00117 /// Iterator Li<type>(some_collection, STOP_ON_GHOSTS) 00118 /// 00119 /// --or-- 00120 /// 00121 /// Iterator Li<type>(some_collection, STOP_ON_GHOSTS, 00122 /// first_elem_ptr, last_elem_ptr); 00123 /// (will iterate from first_elem_ptr to last_elem_ptr, including ghosts) 00124 /// \endcode 00125 /// 00126 /// If the iterators are declared with this flag, ++ and -- 00127 /// will automatically stop on ghost-nodes. next() and prev(), 00128 /// however, will still stop on ghost-nodes only if they have 00129 /// a positive flag. The general rule is 00130 /// that the ++ and -- operators behave according to how the 00131 /// Iterator was declared, while next and prev behave according to 00132 /// whether they have an argument. 00133 /// 00134 /// The iterator does not communicate with the collection 00135 /// which it is iterating over except in the form of 00136 /// indicating references. However, the Collection must 00137 /// adhere to some behavior rules in order for the iterators 00138 /// to work properly. Specifically, when an element is 00139 /// removed from the collection Collection::_unlink_wrapper() 00140 /// should be called to do the unlinking. The iterator 00141 /// depenends on the fact that an unlinked wrapper\'s next 00142 /// and prev fields are left untouched until the wrapper 00143 /// deletes itself (which will happen automatically when 00144 /// its ref count is 0). The iterator depends on these 00145 /// ghost-nodes maintaining their contact with the Collection. 00146 /// 00147 /// It should be noted that each Collection-based structure 00148 /// which is going to make use of iterators must have its own 00149 /// set of constructors within the ITerator class. 00150 /// 00151 template <class T> class Iterator { 00152 protected: 00153 BaseIter _iter; 00154 00155 public: 00156 INLINE Iterator( ); 00157 00158 INLINE Iterator(const TypedCollection<T> &l, 00159 const T *first_elem = 0, 00160 const T *last_elem = 0, 00161 cond_proc func = 0, 00162 void *extra_data = 0); 00163 00164 INLINE Iterator(const TypedCollection<T> &l, 00165 cond_proc func, 00166 void *extra_data = 0); 00167 00168 INLINE Iterator(const TypedCollection<T> &l, 00169 iter_option option, 00170 const T *first_elem = 0, 00171 const T *last_elem = 0); 00172 00173 INLINE Iterator(const TypedCollection<T> *l); 00174 00175 INLINE Iterator<T> & operator = (const TypedCollection<T> &list); 00176 00177 INLINE Iterator(const Iterator<T> &other); 00178 ///< This method copies the entire state (including current element) 00179 ///< of the iterator. If you don't like this, then immediately follow 00180 ///< this constructor with a call to reset() 00181 00182 ~Iterator(); 00183 00184 INLINE Iterator<T> & operator = (const Iterator<T> &other); 00185 ///< This method copies the entire state (including current element) 00186 ///< of the iterator. If you don't like this, then immediately follow 00187 ///< this constructor with a call to reset() 00188 00189 INLINE void reset(); 00190 ///< Go back to the beginning of the iteration space 00191 INLINE void set_to_last(); 00192 ///< Set the iterator to the last value 00193 ///< Useful if you need to iterator backwards 00194 00195 INLINE void next(iter_option option = STOP_ON_GHOSTS); 00196 ///< go to the next valid element, or if stop_at_ghosts 00197 ///< to the next element 00198 00199 INLINE void operator++ (); 00200 ///< go to previous element according to how Iterator was 00201 ///< defined 00202 00203 INLINE void prev(iter_option option = STOP_ON_GHOSTS); 00204 ///< go to the previous valid element, or if stop_at_ghosts 00205 ///< to the previous element 00206 00207 INLINE void operator-- (); 00208 ///< go to previous element according to how Iterator was 00209 ///< defined 00210 00211 ///< #ifdef CLEAN_ITERATOR 00212 ///< INLINE const T ¤t() const; 00213 ///< // Return a reference to the current element 00214 ///< // If there is no current, this results in an error 00215 ///< #else 00216 INLINE T ¤t(); 00217 ///< Return a reference to the current element 00218 ///< If there is no current, this results in an error 00219 ///< #endif 00220 00221 INLINE Boolean end(); 00222 ///< Return true if there no more Nodes to iterate on 00223 00224 INLINE Boolean valid(); 00225 ///< Equivalent to NOT end() 00226 00227 INLINE Boolean current_valid() const; 00228 ///< Return true iff valid() would return True AND the current node is 00229 ///< still valid. This function will return False even if valid() 00230 ///< returns True if the current node is invalid, which will happen if 00231 ///< the current node has become a ghost node by being deleted from 00232 ///< its Collection. 00233 ///< In the event that the current node is invalid, it is 00234 ///< a checked run-time error to make a call to current(). 00235 ///< However, the valid() method still returns True since 00236 ///< the end of the iteration space has not yet been reached. 00237 ///< Also, the operator++/--/prev()/next() methods 00238 ///< will all work correctly and properly find the next element in 00239 ///< the iteration space. 00240 ///< If there is any chance that the current element pointed to 00241 ///< by a BaseIter can be deleted, both valid() and 00242 ///< current_valid() must return True for a call to current() to be 00243 ///< acceptable. 00244 00245 INLINE Boolean current_invalid() const; 00246 ///< Equivalent to ( ! current_valid() ) 00247 00248 #ifndef CLEAN_ITERATOR 00249 00250 INLINE void modify( const T &el ); 00251 ///< Useful for RefMutators 00252 ///< This sets the current reference to el and results 00253 ///< in an error if called on a live collection. 00254 00255 INLINE void modify( T *el ); 00256 ///< Useful for Mutators 00257 ///< This sets current to el and results in an error 00258 ///< if called on a ref-collection. 00259 00260 INLINE void modify_in_place(modify_proc mod, 00261 void *extra_data GIV(0)); 00262 ///< Modify current in place by calling mod(obj, extra_data) where 00263 ///< obj is the pointer which owns current. The procedure 'mod' is 00264 ///< expected to do it's own garbage collection. 00265 ///< The procedure must be of the form: 00266 ///< (*mod)(T *& object, void *extra_data) 00267 ///< This results in an error if current is invalid or if it is 00268 ///< called on a ref-collection. 00269 00270 INLINE void del(); 00271 ///< Delete the current element, useful for Mutators 00272 ///< and RefMutators. This results in an error if the 00273 ///< current node has already been deleted. 00274 ///< \note current will now be invalid. 00275 00276 INLINE T *grab(); 00277 ///< Grab the current element, useful for Mutators. 00278 ///< Results in an error if called on a ref-collection. 00279 ///< \note current will now be invalid. 00280 00281 INLINE Assign<T> assign(); 00282 INLINE T *pull(); 00283 00284 ///< assign/pull is designed to allow the functionality of 00285 ///< modifying an element of a list to be some function of the old value of 00286 ///< that position. The assign() is meant to be executed first, to 00287 ///< capture the original position in the under-lying list for the element. 00288 ///< The Assign<T> object returned by assign() stores the position information 00289 ///< of the element. Then, pull() is used to remove the element from the 00290 ///< list, without losing its position in the list. 00291 ///< 00292 ///< The 'pull' method removes the specified object from its list (like 00293 ///< grab) but maintains it's 'place' in the list. Once an object has been 00294 ///< pulled, it is no longer possible to access the List using the pulled 00295 ///< object as a reference. Once an object has been pulled it can be 00296 ///< modified in any way. Once the modification is complete, the object 00297 ///< can be returned to its position by assigning to the Assign<T> object 00298 ///< (the one created by the original assign() call). 00299 ///< 00300 ///< The user, of course, is responsible for garbage collecting any 00301 ///< intermediate forms of the pulled object which may be created. A 00302 ///< complete use would be as follows: 00303 ///< 00304 ///< \code 00305 ///< { 00306 ///< Assign<Expression> a = iter.assign(); 00307 ///< a = function(iter.pull() ); 00308 ///< } // "a" is removed by leaving the scope 00309 ///< \endcode 00310 ///< 00311 ///< 'function' is simply a function which returns the modified value. If 00312 ///< the modified value is a different object than the original, function 00313 ///< is responsible for garbage collecting the original. In this case, the 00314 ///< specified object is pulled from the list, modified somehow by function 00315 ///< and the returned value takes it's place in the list. 00316 ///< 00317 00318 #endif 00319 }; 00320 00321 00322 ///< implementation 00323 00324 template <class T> 00325 INLINE 00326 Iterator<T>::Iterator( ) 00327 : _iter( ) 00328 { 00329 #ifdef MEMORY_LEAK_PRINT 00330 cout << "Iterator ctor: " << this << " : size=" << sizeof(Iterator) << endl; 00331 #endif 00332 00333 } 00334 00335 template <class T> 00336 Iterator<T>::~Iterator( ) 00337 { 00338 #ifdef MEMORY_LEAK_PRINT 00339 cout << "Iterator dtor: " << this << " : size=" << sizeof(Iterator) << endl; 00340 #endif 00341 00342 } 00343 00344 template <class T> 00345 INLINE 00346 Iterator<T>::Iterator(const TypedCollection<T> &l, 00347 const T *first_elem GIV(0), 00348 const T *last_elem GIV(0), 00349 cond_proc func GIV(0), 00350 void *extra_data GIV(0)) 00351 : _iter(l._base_collection(), first_elem, last_elem, func, extra_data) 00352 { 00353 #ifdef MEMORY_LEAK_PRINT 00354 cout << "Iterator ctor: " << this << " : size=" << sizeof(Iterator) << endl; 00355 #endif 00356 00357 } 00358 00359 template <class T> 00360 INLINE 00361 Iterator<T>::Iterator(const TypedCollection<T> &l, 00362 cond_proc func, 00363 void *extra_data GIV(0)) 00364 : _iter(l._base_collection(), func, extra_data) 00365 { 00366 #ifdef MEMORY_LEAK_PRINT 00367 cout << "Iterator ctor: " << this << " : size=" << sizeof(Iterator) << endl; 00368 #endif 00369 00370 } 00371 00372 template <class T> 00373 INLINE 00374 Iterator<T>::Iterator(const TypedCollection<T> &l, 00375 iter_option option, 00376 const T *first_elem GIV(0), 00377 const T *last_elem GIV(0)) 00378 : _iter(l._base_collection(), option, first_elem, last_elem) 00379 { 00380 #ifdef MEMORY_LEAK_PRINT 00381 cout << "Iterator ctor: " << this << " : size=" << sizeof(Iterator) << endl; 00382 #endif 00383 00384 } 00385 00386 template <class T> 00387 INLINE 00388 Iterator<T>::Iterator(const TypedCollection<T> *l) 00389 : _iter(l->_base_collection()) 00390 { 00391 #ifdef MEMORY_LEAK_PRINT 00392 cout << "Iterator ctor: " << this << " : size=" << sizeof(Iterator) << endl; 00393 #endif 00394 00395 } 00396 00397 template <class T> 00398 INLINE Iterator<T> & 00399 Iterator<T> ::operator = (const TypedCollection<T> &list) 00400 { 00401 _iter = list._base_collection(); 00402 return *this; 00403 } 00404 00405 template <class T> 00406 INLINE 00407 Iterator<T>::Iterator(const Iterator<T> &other) 00408 : _iter(other._iter) 00409 { 00410 ///< nothing else to do 00411 } 00412 00413 template <class T> 00414 INLINE Iterator<T> & 00415 Iterator<T>::operator = (const Iterator<T> &other) 00416 { 00417 _iter = other._iter; 00418 return *this; 00419 } 00420 00421 template <class T> 00422 INLINE void 00423 Iterator<T>::reset() 00424 { 00425 _iter.reset(); 00426 } 00427 00428 template <class T> 00429 INLINE void 00430 Iterator<T>::set_to_last() 00431 { 00432 _iter.set_to_last(); 00433 } 00434 00435 template <class T> 00436 INLINE void 00437 Iterator<T>::next(iter_option option GIV(STOP_ON_GHOSTS)) 00438 { 00439 _iter.next(option); 00440 } 00441 00442 template <class T> 00443 INLINE void 00444 Iterator<T>::operator++ () 00445 { 00446 _iter.next(_iter.skip_ghosts() ? SKIP_GHOSTS : STOP_ON_GHOSTS); 00447 } 00448 00449 template <class T> 00450 INLINE void 00451 Iterator<T>::prev(iter_option option GIV(STOP_ON_GHOSTS)) 00452 { 00453 _iter.prev(option); 00454 } 00455 00456 template <class T> 00457 INLINE void 00458 Iterator<T>::operator-- () 00459 { 00460 _iter.prev(_iter.skip_ghosts() ? SKIP_GHOSTS : STOP_ON_GHOSTS); 00461 } 00462 00463 00464 00465 00466 ///< #ifdef CLEAN_ITERATOR 00467 ///< 00468 ///< template <class T> 00469 ///< INLINE const T & 00470 ///< Iterator<T>::current() const 00471 ///< { 00472 ///< return (T &) _iter.current(); 00473 ///< } 00474 ///< #else 00475 ///< 00476 template <class T> 00477 INLINE T & 00478 Iterator<T>::current() 00479 { 00480 return (T &) _iter.current(); 00481 } 00482 ///< #endif 00483 00484 template <class T> 00485 INLINE Boolean 00486 Iterator<T>::end() 00487 { 00488 return _iter.end(); 00489 } 00490 00491 template <class T> 00492 INLINE Boolean 00493 Iterator<T>::valid() 00494 { 00495 return _iter.valid(); 00496 } 00497 00498 template <class T> 00499 INLINE Boolean 00500 Iterator<T>::current_valid() const 00501 { 00502 return _iter.current_valid(); 00503 } 00504 00505 template <class T> 00506 INLINE Boolean 00507 Iterator<T>::current_invalid() const 00508 { 00509 return _iter.current_invalid(); 00510 } 00511 00512 00513 00514 #ifndef CLEAN_ITERATOR 00515 00516 template <class T> 00517 INLINE void 00518 Iterator<T>::modify(const T &el) 00519 { 00520 _iter.modify(el); 00521 } 00522 00523 template <class T> 00524 INLINE void 00525 Iterator<T>::modify(T *el) 00526 { 00527 _iter.modify(el); 00528 } 00529 00530 template <class T> 00531 INLINE void 00532 Iterator<T>::modify_in_place(modify_proc mod, 00533 void *extra_data GIV(0)) 00534 { 00535 _iter.modify_in_place(mod, extra_data); 00536 } 00537 00538 template <class T> 00539 INLINE void 00540 Iterator<T>::del() 00541 { 00542 _iter.del(); 00543 } 00544 00545 00546 template <class T> 00547 INLINE T * 00548 Iterator<T>::grab() 00549 { 00550 return (T *) _iter.grab(); 00551 } 00552 00553 template <class T> 00554 INLINE Assign<T> 00555 Iterator<T>::assign() 00556 { 00557 Assign<T> a(_iter.assign()); 00558 return a; 00559 } 00560 00561 template <class T> 00562 INLINE T * 00563 Iterator<T>::pull() 00564 { 00565 return (T *) _iter.pull(); 00566 } 00567 00568 00569 #endif 00570 00571 #endif |
||
|