Polaris: Iterator.h Source File

Iterator.h

Go 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 &current() 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       &current();
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
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:57 2005