cgma
|
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