cgma
DLList.hpp
Go to the documentation of this file.
00001 //- Class: DLList
00002 //- Description: DLList is a doubly linked list class that accepts generic
00003 //-              pointers to any object.  It is controlled by a macro that
00004 //-              substitutes the specific pointer definitions in the class
00005 //-              declaration. The list is implemented as an array that is 
00006 //-              grown by a specified amount when the list becomes full.
00007 //-              Insertions and deletions at any point other than the end
00008 //-              of the list are handled inefficiently at the current time
00009 //-              since all data from that point to the end is bubbled
00010 //-              down/up to fill/create the void. Operators {+} and {+=} 
00011 //-              are provided as an efficient means of assigning one list
00012 //-              to another or appending one list onto another.
00013 //-
00014 //-              The macro {DLListdeclare(name,typePtr)} is defined to
00015 //-              create specific instances of the DLList class.
00016 //-              {name} is the name of the DLList class created, and
00017 //-              {typePtr} is the type of elements stored in the list.
00018 //-              The macro also defines the functions {push(item)} and 
00019 //-              {pop()} which allow {DLLists} to perform like stacks.
00020 //-
00021 //- Assumptions: All data are stored contiguously in the array with 
00022 //-              empty slots at the end of the array.
00023 //-
00024 //- Owner: Greg Sjaardema
00025 //- Checked by: Jim Hipp, 3/28/94
00026 //- Version: $Id: 
00027 
00028 #ifndef DLLIST_HPP
00029 #define DLLIST_HPP
00030 
00031 #include "ArrayBasedContainer.hpp"
00032 #include "CubitDefines.h"
00033 #include "CubitMessage.hpp"
00034 #include <cstring>
00035 #include <cassert>
00036 #include "CGMUtilConfigure.h"
00037 
00038 class CUBIT_UTIL_EXPORT DLList : public ArrayBasedContainer
00039 {
00040 public:
00041 
00042   DLList (int list_size);
00043   //- Constructor: Create a list with initial size {list_size}. The list
00044   //- will be grown by {list_size} each time it is filled. Memory for the
00045   //- list is not allocated until the first element is inserted using
00046   //- {insertLink}. 
00047   //- If {list_size} is zero, the default increment ({INCREMENT}) will be used
00048   //- From an efficiency standpoint, it is very important that the 
00049   //- increment be set large enough to reduce the number of list 
00050   //- growths, but small enough to not waste memory.
00051   //- It is more efficient to sligthly overestimate the size than 
00052   //- to underestimate the size.
00053   
00054   DLList(const DLList& copy_from);  //- Copy Constructor
00055   
00056   virtual ~DLList();
00057   //- Destructor: Free all resources used by this list.
00058   
00059   void step();
00060     //- Move the pointer to the next element in the list. If pointer reaches
00061   //- the end of the list, wrap around to the beginning
00062   
00063   void step(int n);
00064   //- Move the pointer {n} positions forward in the list wrapping 
00065   //- around to the beginning of the list if the end is reached
00066   //- If {n} is less than zero, move backward.
00067   
00068   void back();
00069   //- Move the pointer to the previous element in the list. If reaches
00070   //- the beginning of the list, wrap around to the end
00071   
00072   void back(int n);
00073   //- Move the pointer {n} positions backward in the list wrapping 
00074   //- around to the end of the list if the beginning is reached.
00075   //- If {n} is less than zero, move forward.
00076   
00077   void reset();     //- Set the pointer to the beginning of the list.   
00078   void last();      //- Set the pointer to the end of the list.  
00079   
00080   void clean_out();
00081   //- Delete all elements in the list, reset the pointer to zero.
00082   //- Does not release memory already allocated for the list. This
00083   //- call is more efficient creating a new list repeatadly within
00084   //- a loop.
00085   
00086   void shrink(int k);
00087   //- itemCount -= k;  Doesn't change array elements.
00088   //- Sets the index to the new end of the list if the old_index >= 
00089   //- new_itemCount
00090   
00091   CubitBoolean is_at_beginning() const;
00092   //- returns CUBIT_TRUE if list is at beginning
00093   
00094   CubitBoolean is_at_end() const;
00095   //- returns CUBIT_TRUE if list is at end
00096   
00097   int get_index();
00098   //- Returns the current index value.  This function and set_index are
00099   //- included for efficiency when one wants to return to a previous location 
00100   //- in the list when it is known that the list has not changed.  This
00101   //- is the only recommended usage for these functions.
00102   
00103   void set_index(int new_index);
00104   //- Sets the list to the given index.  If the requested index is less than
00105   //- zero or out of the scope of the number of items in the list, an assert 
00106   //- occurs.  This function and get_index are included for efficiency when 
00107   //- one wants to return to a previous location in the list when it is known 
00108   //- that the list has not changed.  This is the only recommended usage for 
00109   //- these functions.
00110   
00111   void compress();
00112   //- Remove all null (0) pointers from list. Must be called after
00113   //- {nullify_link()} is called before calling any list modification 
00114   //- function except {move_to()} or {nullify_link()}
00115   
00116   void reverse();
00117   //- Reverse the items in the list.
00118   
00119   DLList& operator=(const DLList&);
00120   //- Create a copy of a list.
00121   
00122   virtual void merge_unique(DLList& merge_list, 
00123                             int merge_list_unique = CUBIT_FALSE);
00124   //- Merges the contents of the list, merge_list, with those of "this"
00125   //- list, ensuring that items that are being added do not already
00126   //- exist in "this" list. If the items are known to appear in the
00127   //- merge_list only once, then it can be done faster.
00128 
00129   void intersect(DLList& merge_list);
00130   //- Merges the contents of the list merge_list, with those of "this"
00131   //- list, but only the items that are common to both lists are kept
00132   //- in "this" list.  This is a rather costly process I think.
00133   //- if merge_list is the same as the calling list, it just returns
00134   
00135   int append_unique(void* new_item);
00136   //- Appends the new item to the list, if it doesn't already exist
00137   //- in the list. In either case, index is not changed.
00138   //- Return CUBIT_TRUE if the item was added, else CUBIT_FALSE.
00139 
00140   SetDynamicMemoryAllocation(memoryManager)
00141   //- overloaded new and delete operators
00142     
00143     //Added by J. Kraftcheck, 5/25/99
00144     //These are not very efficient (O(n^2))
00145     //In order to maintain the correct functionality of these
00146     //operators when either list contains duplicates, it is
00147     //also necessary to create a temporary list during the check.
00148     int operator< ( const DLList& list ) const; //subset
00149     int operator<=( const DLList& list ) const; //subset or equivalent
00150     int operator> ( const DLList& list ) const; //superset
00151     int operator>=( const DLList& list ) const; //superset or equivalent
00152     int operator==( const DLList& list ) const; //non-order-dependend compare
00153     int operator!=( const DLList& list ) const; //non-order-dependend compare
00154 
00155 protected:
00156   
00157   void insert_link(void* newBody);
00158   //- put new item in list after current item and make it current
00159   
00160   void insert_link_first(void* new_item);
00161   //- put new item in list at index 0 and make it current
00162   
00163   void append_link(void* newBody);  
00164   //- put new item at end of list and keep pointer where it is.
00165   //- This call should be used to add items to a list if order 
00166   //- of items is not important.
00167   
00168   void *nullify_link();
00169   //- Change the current item to a null pointer and return a pointer
00170   //- to the item (before nulled). See the discussion for {nullItem}.
00171   
00172   void *cut_link();
00173   //- remove the item at the current location and return a pointer to it.
00174   //- The next node becomes the current node
00175   //- Returns {NULL} if there are no items in list
00176   
00177   void* extract_link();
00178   //- remove the item at the current location and return a pointer to it.
00179   //- used for efficiency in cases where preservation of list order is not
00180   //- important.  moves last list item (itemCount - 1) to current index and
00181   //- decrements itemCount.  eliminates the need to perform the list bubble
00182   //- down (i.e. cut_link) but sacrifices list order in the process.  this
00183   //- function should not be used when up-stream order from the removed node
00184   //- is important.  when processing a list using this function the user
00185   //- should reset the list to the head (index = 0) before beginning to
00186   //- ensure all list nodes are processed properly.
00187   //- Returns {NULL} if there are no items in list
00188   
00189   CubitBoolean omit_link(void*);
00190   //- Finds instance of item by matching pointer and deleting all instances
00191   //- of it from the list. The current position of the list is not changed.
00192   //- Returns CUBIT_TRUE if the item was found and deleted, CUBIT_FALSE
00193   //- if not.
00194   
00195   void *next_item(int n=1) const;
00196   //- Return a pointer to the item {n} items after the current item.
00197   //- Index is not changed.
00198   //- Returns {NULL} if there are no items in list
00199   
00200   void *prev_item(int n=1) const;
00201   //- Return a pointer to the item {n} items before the current item.
00202   //- Index is not changed.
00203   //- Returns {NULL} if there are no items in list
00204   
00205   void *get_item() const;
00206   //- Return a void pointer to the current item.
00207   //- Index is not changed.
00208   //- Returns {NULL} if there are no items in list
00209 
00210   void *change_item_to(void* newBody);
00211 
00212   void *move_to_and_remove_item(void* item);
00213   //- search for item in list and remove if found.  Function uses
00214   //- move_to_item to find item and cut_link to remove it.  If item is found
00215   //- it is returned else NULL is returned.
00216 
00217   void *get_item_and_step();
00218   //- Return a pointer to the current item and increment the index by 1.
00219   //- Returns {NULL} if there are no items in list
00220   
00221   void *step_and_get_item();
00222   //- Increment the index by 1, then return a pointer to the current item.
00223   //- Returns {NULL} if there are no items in list
00224   
00225   void *get_item_and_back();
00226   //- Return a pointer to the current item and decrement the index by 1.
00227   //- Returns {NULL} if there are no items in list
00228   
00229   CubitBoolean move_to_item(void* body);
00230   CubitBoolean move_to_nearby_item(void* body);
00231   int distance_to_nearby_item(void* body);
00232   //- Sets the index to the item in the list that matches {body}
00233   //- Returns {CUBIT_FALSE} if there are no items in list or if 
00234   //- the requested item is not in the list.
00235   //- Returns {CUBIT_TRUE} if the item is Found.
00236     //- move_to_item searches from the current item forward
00237     //- move_to_nearby_item searches from the current item both
00238     //- forward and backward.
00239   
00240   CubitBoolean move_between_items(void *body1, void *body2);
00241   //- Sets the index to the place matching one of the items, where the
00242   //- previous item is the other item (i.e. no order assumed on the
00243   //- parameters)
00244   //- Returns {CUBIT_FALSE} if there are no items in list or the items
00245   //- are not consecutive in the list.
00246   //- Returns {CUBIT_TRUE} if the consecutive items are found.
00247   
00248   //void *change_item_to(void* newBody); //commented out 8-12-98
00249   //- Sets the item at the current index value to {newBody} and
00250   //- returns the old value at that location.
00251   //- Returns {NULL} if there are no items in list
00252   
00253   void *nullItem;
00254   //- Item removed in last {nullify_link} operation. It is saved here
00255   //- only for execution speed reasons. The primary use of {nullify_link}
00256   //- is in deleting a partial mesh. After {nullify_link()} is called,
00257   //- a destructor for that item is called which does a {move_to}.
00258   //- Since we just nulled that entry, we can't {move_to()} it, so
00259   //- {move_to()} checks to see if the item matches
00260   //- {nullItem}. It it does, we return, otherwise we do a normal 
00261   //- {move_to()}.
00262   
00263   int where_is_item( void *item ) const;
00264   //- Return index of item in list, or -1 if item is not in the list.
00265   //- This information should never be passed outside the class.
00266 
00267   int  index;                  //- index of current item in {listArray}
00268   
00269 private:
00270   
00271   // int  listIsSorted;  //- This is now a bit in ArrayBasedContainer.hpp
00272   //- flag used to indicate if an ordered list is no longer ordered
00273   
00274   static const char* type() { return "DLList"; }
00275   //- declare which type of ArrayBasedContainer this is
00276   
00277   static MemoryManager memoryManager;
00278   //- memory management static objects for performing block allocation
00279 };
00280 
00281 // *** inline function definitions *******************************************
00282 
00283 inline void DLList::step()      { if (itemCount) index++; 
00284                                   if (index >= itemCount) index = 0;}
00285 
00286 inline void DLList::step(int n)  {
00287   if (itemCount) {
00288     index += n;
00289     if (index < 0)   {
00290       index = itemCount - (-index)%itemCount;
00291     }
00292     if (index >= itemCount) {
00293       index %= itemCount;
00294     }
00295   }
00296 }
00297 
00298 
00299 inline void DLList::back()      { if (itemCount) index--;
00300                           if (index < 0) index = itemCount - 1; }
00301   
00302 inline void DLList::back(int n) { step(-n); }
00303   
00304 inline void DLList::reset()     { index = 0; }
00305   
00306 inline void DLList::last()      { if (itemCount) index = itemCount - 1; }
00307   
00308 inline CubitBoolean DLList::is_at_beginning() const
00309 {if (!index) return CUBIT_TRUE;
00310  else return CUBIT_FALSE;}
00311 
00312 inline CubitBoolean DLList::is_at_end() const
00313 {
00314   if (itemCount == 0 || index == itemCount-1)
00315     return CUBIT_TRUE;
00316   else
00317     return CUBIT_FALSE;
00318 }
00319  
00320 //- Add item to end of list, do not change current index value.
00321 //- This function used to reduce time required to do an insert 
00322 //- followed by a move_to back to where we were.
00323  inline void DLList::append_link ( void* new_item )
00324 {
00325     assert(new_item != NULL);
00326     // see if the list must be lengthened
00327 
00328     if ( itemCount == listLength )
00329         lengthen_list();
00330 
00331     listArray[itemCount++] = new_item;
00332 }
00333 
00334 inline void *DLList::get_item () const
00335 {
00336     if ( !itemCount ) {
00337         PRINT_WARNING("Attempted get of empty DLList\n");
00338         return NULL;
00339     }
00340     else {
00341       assert(listArray[index] != NULL);
00342       return listArray[index];
00343     }
00344 }
00345 
00346 inline void *DLList::get_item_and_step () 
00347 {
00348 #ifndef GDSJAAR
00349     if ( !itemCount )
00350     {
00351         PRINT_WARNING("Attempted get_and_step from empty DLList\n");
00352         return NULL;
00353     }
00354     else
00355 #endif
00356     {
00357         void *temp = listArray[index++];
00358         if (index == itemCount) index=0;
00359         assert(temp != NULL);
00360         return temp;
00361     }
00362 }
00363 
00364 inline void *DLList::next_item ( int n )  const
00365 {
00366     if ( !itemCount )
00367     {
00368         PRINT_WARNING("Attempted next of empty DLList\n");
00369         return NULL;
00370     }
00371     else
00372     {
00373         // return the proper index
00374         // beware of negative n leading to negative new_index
00375         int new_index = index+n;
00376     while (new_index < 0)
00377       new_index += itemCount;
00378 
00379     new_index = new_index%itemCount;
00380 
00381         assert(listArray[new_index] != NULL);
00382         return listArray[new_index];
00383     }
00384 }
00385 
00386 inline void DLList::clean_out ()
00387 {
00388     itemCount = 0;
00389     index = 0;
00390 }
00391 
00392 
00393 class DLListIterator
00394 {
00395 public:
00396   DLListIterator() { index = 0; }
00397     // constructor
00398   virtual ~DLListIterator() {}
00399     // destructor
00400   
00401   void step( int n = 1 ) 
00402     { index += n; }
00403 
00404 protected:
00405   
00406     // data
00407   int index;
00408 };
00409 
00410 
00411 // *** macro definitions *****************************************************
00412 
00413 // Three separate derived classes are possible from DLList all of which are
00414 // defined by one of the following macros:
00415 // 
00416 //    DLListdeclare(name, typePtr)
00417 //
00418 // The first is the standard DLList declaration macro, the second provides
00419 // sorting/searching functionality, and the third provides sorting/searching
00420 // functionallity for simple intrinsic data lists.  All three are described in
00421 // more detail below.  Two support macros
00422 //
00423 //    CommonDefine(typePtr, notSorted)
00424 //    CommonSortedDefine(name, typePtr)
00425 //
00426 // are also defined but are not meant to be utilized externally.  They simply
00427 // collect class definitions that are common to the three list defintions
00428 // macros described above
00429 
00430 // The following macro defintion provides the core functionality for the
00431 // standard DLListdeclare as-well-as the sorted SDLListdeclare macros.
00432 // typePtr is still the type pointer of the data stored by the list.
00433 // notSorted is simply a semi-colon (;) for the standard list (if white space
00434 // is used for the parameter the CPP outputs a warning message that a NULL
00435 // string is being substituted for the parameter ... the proper outcome but
00436 // the excessive warning messages are a real nuisance) and a call to the
00437 // set_sort_flag function (with an argument of False) for the sorted lists.
00438 #define CommonDefine(typePtr, notSorted)                                     \
00439                                                                              \
00440     typePtr remove()         {return (typePtr) cut_link();}                  \
00441     int omit(typePtr objPtr) {return omit_link((void*) objPtr);}             \
00442     typePtr get() const      {return (typePtr) get_item();}                  \
00443     CubitBoolean set(typePtr objPtr) {return move_to_item((void*)objPtr);}   \
00444     typePtr next() const     {return (typePtr) next_item();}                 \
00445     typePtr next( int n ) const {return (typePtr) next_item(n);}             \
00446     typePtr prev() const     {return (typePtr) prev_item();}                 \
00447     typePtr prev(int n) const {return (typePtr) prev_item(n);}               \
00448     typePtr get_and_step()   {return (typePtr) get_item_and_step();}         \
00449     typePtr get_and_back()   {return (typePtr) get_item_and_back();}         \
00450     typePtr step_and_get()   {return (typePtr) step_and_get_item();}         \
00451                                                                              \
00452     CubitBoolean move_between(typePtr objPtr1, typePtr objPtr2)              \
00453     {                                                                        \
00454         if (nullItem && (((typePtr) nullItem == objPtr1) ||                  \
00455                      ((typePtr) nullItem == objPtr2) ))                \
00456       return CUBIT_FALSE;                                              \
00457         else                                                                 \
00458       return (move_between_items(((void*) objPtr1), ((void*) objPtr2))); \
00459     }                                                                        \
00460     typePtr pop()                {last(); return remove();}                  \
00461     typePtr push(typePtr objPtr)                                             \
00462         { notSorted last(); append_link((void*)objPtr); return objPtr; }     \
00463                                                                              \
00464     void insert_first(typePtr objPtr)                                        \
00465         { notSorted insert_link_first((void*) objPtr); }                     \
00466     void append(typePtr objPtr)                                              \
00467         { notSorted append_link((void*) objPtr); }                           \
00468     typePtr extract()                                                        \
00469         { notSorted return (typePtr) extract_link(); }                       \
00470     typePtr nullify()                                                        \
00471         { notSorted return (typePtr) nullify_link(); }                       \
00472     typePtr change_to(typePtr objPtr)                                        \
00473         { notSorted return (typePtr) change_item_to((void*) objPtr); }       \
00474 
00475 
00476 
00477 // The standard DLList declaration macro creates a list class that is derived
00478 // from DLList.  The class (name) stores pointers to data of type typePtr.
00479 // No list ordering capability is provided by the standard declare macro
00480 #define DLListdeclare(name, typePtr)                                         \
00481                                                                              \
00482 class name : public DLList                                                   \
00483 {                                                                            \
00484   friend class name##Iterator;                                               \
00485                                                                              \
00486   public:                                                                    \
00487                                                                              \
00488     name(int list_size=0) : DLList (list_size)                               \
00489     {                                                                        \
00490       assert(sizeof(typePtr) == sizeof(void*));                              \
00491     }                                                                        \
00492     void insert(typePtr objPtr) { insert_link((void*) objPtr); }             \
00493     typePtr remove(typePtr objPtr)                                           \
00494     {                                                                        \
00495       return (typePtr) move_to_and_remove_item((void*) objPtr);              \
00496     }                                                                        \
00497     CubitBoolean move_to(const typePtr objPtr)                               \
00498     {                                                                        \
00499       if (nullItem && (typePtr)nullItem == objPtr)                           \
00500     return CUBIT_FALSE;                                                \
00501       else                                                                   \
00502     return (move_to_item((void*) objPtr));                             \
00503     }                                                                        \
00504     CubitBoolean move_to_nearby(const typePtr objPtr)                        \
00505     {                                                                        \
00506       if (nullItem && (typePtr)nullItem == objPtr)                           \
00507     return CUBIT_FALSE;                                                \
00508       else                                                                   \
00509     return (move_to_nearby_item((void*) objPtr));                      \
00510     }                                                                        \
00511     int distance_to_nearby(const typePtr objPtr)                             \
00512     {                                                                        \
00513       if (nullItem && (typePtr)nullItem == objPtr)                           \
00514     return CUBIT_FALSE;                                                \
00515       else                                                                   \
00516     return (distance_to_nearby_item((void*) objPtr));                  \
00517     }                                                                        \
00518     CubitBoolean is_in_list(const typePtr objPtr) const                      \
00519     {                                                                        \
00520       return where_is_item((void*) objPtr) >= 0 ? CUBIT_TRUE : CUBIT_FALSE;  \
00521     }                                                                        \
00522     name& operator=(const name##Iterator & iter);                            \
00523     CommonDefine(typePtr, ;)                                                 \
00524 };                                                                           \
00525                                                                              \
00526 class name##Iterator : public DLListIterator                                 \
00527 {                                                                            \
00528   friend class name;                                                         \
00529 public:                                                                      \
00530   name##Iterator() : DLListIterator() { dlList = NULL; }                     \
00531   void watch( const name *dl_list )                                          \
00532     { dlList = dl_list; }                                                    \
00533   int size() const { return dlList ? dlList->size() : 0; }                   \
00534   typePtr get() const                                                        \
00535     {return (typePtr) get_item();}                                           \
00536   typePtr get_and_step( int n = 1 )                                          \
00537     {                                                                        \
00538       typePtr temp = (typePtr) get_item();                                   \
00539       step( n );                                                             \
00540       return temp;                                                           \
00541     }                                                                        \
00542   typePtr next( int n = 1 ) const                                            \
00543     {return (typePtr) next_item(n);}                                         \
00544   CubitBoolean is_in_list( const typePtr objPtr ) const                      \
00545     { return where_is_item( (void*) objPtr ) >= 0 ? CUBIT_TRUE :             \
00546       CUBIT_FALSE; }                                                         \
00547   CubitBoolean move_to(const typePtr objPtr )                                \
00548     { index = where_is_item( (void*) objPtr );                               \
00549       return index > 0 ? CUBIT_TRUE : CUBIT_FALSE; }                         \
00550 private:                                                                     \
00551   const name *dlList;                                                        \
00552   inline void *next_item( int n = 1 ) const;                                 \
00553   void *get_item() const  { return next_item(0); }                           \
00554   int where_is_item( void *item ) const                                      \
00555     { return dlList ? dlList->where_is_item( item ) : -1; }                  \
00556 };                                                                           \
00557                                                                              \
00558 inline void *name##Iterator::next_item( int n ) const                        \
00559 {                                                                            \
00560   int size_loc = size();                                                     \
00561   if ( size_loc == 0 )                                                       \
00562     return NULL;                                                             \
00563   int index_loc = index + n;                                                 \
00564   while ( index_loc < 0 )                                                    \
00565     index_loc += size_loc;                                                   \
00566   while ( index_loc >= size_loc )                                            \
00567     index_loc -= size_loc;                                                   \
00568  return dlList->listArray[index_loc];                                        \
00569 }                                                                            \
00570 inline name& name::operator=(const name##Iterator& iter)                     \
00571 { if ( iter.dlList ) *this = *(iter.dlList);                                 \
00572   else clean_out();                                                          \
00573   return *this; }                                                            \
00574 
00575 // Use the list iterator like so:
00576 //
00577 // DLListDeclare( DLCubitNodeList, CubitNode * );
00578 // DLCubitNodeList node_list;
00579 // DLCubitNodeListIterator node_iterator;
00580 // node_iterator.watch( node_list );
00581 // node_iterator.reset();
00582 // for (int i = node_iterator.size(); i--; )
00583 // {
00584 //    CubitNode *node = node_iterator.get_and_step();
00585 //    ...
00586 // }
00587 //
00588 
00589 #endif //- DLLIST_HPP
00590 
00591 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines