|
tesseract 3.04.01
|
00001 /********************************************************************** 00002 * File: elst.h (Formerly elist.h) 00003 * Description: Embedded list module include file. 00004 * Author: Phil Cheatle 00005 * Created: Mon Jan 07 08:35:34 GMT 1991 00006 * 00007 * (C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #ifndef ELST_H 00021 #define ELST_H 00022 00023 #include <stdio.h> 00024 #include "host.h" 00025 #include "serialis.h" 00026 #include "lsterr.h" 00027 00028 class ELIST_ITERATOR; 00029 00030 /********************************************************************** 00031 This module implements list classes and iterators. 00032 The following list types and iterators are provided: 00033 00034 List type List Class Iterator Class Element Class 00035 --------- ---------- -------------- ------------- 00036 00037 Embedded list ELIST 00038 ELIST_ITERATOR 00039 ELIST_LINK 00040 (Single linked) 00041 00042 Embedded list ELIST2 00043 ELIST2_ITERATOR 00044 ELIST2_LINK 00045 (Double linked) 00046 00047 Cons List CLIST 00048 CLIST_ITERATOR 00049 CLIST_LINK 00050 (Single linked) 00051 00052 Cons List CLIST2 00053 CLIST2_ITERATOR 00054 CLIST2_LINK 00055 (Double linked) 00056 00057 An embedded list is where the list pointers are provided by a generic class. 00058 Data types to be listed inherit from the generic class. Data is thus linked 00059 in only ONE list at any one time. 00060 00061 A cons list has a separate structure for a "cons cell". This contains the 00062 list pointer(s) AND a pointer to the data structure held on the list. A 00063 structure can be on many cons lists at the same time, and the structure does 00064 not need to inherit from any generic class in order to be on the list. 00065 00066 The implementation of lists is very careful about space and speed overheads. 00067 This is why many embedded lists are provided. The same concerns mean that 00068 in-line type coercion is done, rather than use virtual functions. This is 00069 cumbersome in that each data type to be listed requires its own iterator and 00070 list class - though macros can gererate these. It also prevents heterogeneous 00071 lists. 00072 **********************************************************************/ 00073 00074 /********************************************************************** 00075 * CLASS - ELIST_LINK 00076 * 00077 * Generic link class for singly linked lists with embedded links 00078 * 00079 * Note: No destructor - elements are assumed to be destroyed EITHER after 00080 * they have been extracted from a list OR by the ELIST destructor which 00081 * walks the list. 00082 **********************************************************************/ 00083 00084 class DLLSYM ELIST_LINK 00085 { 00086 friend class ELIST_ITERATOR; 00087 friend class ELIST; 00088 00089 ELIST_LINK *next; 00090 00091 public: 00092 ELIST_LINK() { 00093 next = NULL; 00094 } 00095 //constructor 00096 00097 ELIST_LINK(const ELIST_LINK &) { // don't copy link. 00098 next = NULL; 00099 } 00100 00101 void operator= ( //don't copy links 00102 const ELIST_LINK &) { 00103 next = NULL; 00104 } 00105 }; 00106 00107 /********************************************************************** 00108 * CLASS - ELIST 00109 * 00110 * Generic list class for singly linked lists with embedded links 00111 **********************************************************************/ 00112 00113 class DLLSYM ELIST 00114 { 00115 friend class ELIST_ITERATOR; 00116 00117 ELIST_LINK *last; //End of list 00118 //(Points to head) 00119 ELIST_LINK *First() { // return first 00120 return last ? last->next : NULL; 00121 } 00122 00123 public: 00124 ELIST() { //constructor 00125 last = NULL; 00126 } 00127 00128 void internal_clear ( //destroy all links 00129 //ptr to zapper functn 00130 void (*zapper) (ELIST_LINK *)); 00131 00132 bool empty() const { //is list empty? 00133 return !last; 00134 } 00135 00136 bool singleton() const { 00137 return last ? (last == last->next) : false; 00138 } 00139 00140 void shallow_copy( //dangerous!! 00141 ELIST *from_list) { //beware destructors!! 00142 last = from_list->last; 00143 } 00144 00145 //ptr to copier functn 00146 void internal_deep_copy (ELIST_LINK * (*copier) (ELIST_LINK *), 00147 const ELIST * list); //list being copied 00148 00149 void assign_to_sublist( //to this list 00150 ELIST_ITERATOR *start_it, //from list start 00151 ELIST_ITERATOR *end_it); //from list end 00152 00153 inT32 length() const; // # elements in list 00154 00155 void sort ( //sort elements 00156 int comparator ( //comparison routine 00157 const void *, const void *)); 00158 00159 // Assuming list has been sorted already, insert new_link to 00160 // keep the list sorted according to the same comparison function. 00161 // Comparison function is the same as used by sort, i.e. uses double 00162 // indirection. Time is O(1) to add to beginning or end. 00163 // Time is linear to add pre-sorted items to an empty list. 00164 // If unique is set to true and comparator() returns 0 (an entry with the 00165 // same information as the one contained in new_link is already in the 00166 // list) - new_link is not added to the list and the function returns the 00167 // pointer to the identical entry that already exists in the list 00168 // (otherwise the function returns new_link). 00169 ELIST_LINK *add_sorted_and_find(int comparator(const void*, const void*), 00170 bool unique, ELIST_LINK* new_link); 00171 00172 // Same as above, but returns true if the new entry was inserted, false 00173 // if the identical entry already existed in the list. 00174 bool add_sorted(int comparator(const void*, const void*), 00175 bool unique, ELIST_LINK* new_link) { 00176 return (add_sorted_and_find(comparator, unique, new_link) == new_link); 00177 } 00178 00179 }; 00180 00181 /*********************************************************************** 00182 * CLASS - ELIST_ITERATOR 00183 * 00184 * Generic iterator class for singly linked lists with embedded links 00185 **********************************************************************/ 00186 00187 class DLLSYM ELIST_ITERATOR 00188 { 00189 friend void ELIST::assign_to_sublist(ELIST_ITERATOR *, ELIST_ITERATOR *); 00190 00191 ELIST *list; //List being iterated 00192 ELIST_LINK *prev; //prev element 00193 ELIST_LINK *current; //current element 00194 ELIST_LINK *next; //next element 00195 bool ex_current_was_last; //current extracted 00196 //was end of list 00197 bool ex_current_was_cycle_pt; //current extracted 00198 //was cycle point 00199 ELIST_LINK *cycle_pt; //point we are cycling 00200 //the list to. 00201 bool started_cycling; //Have we moved off 00202 //the start? 00203 00204 ELIST_LINK *extract_sublist( //from this current... 00205 ELIST_ITERATOR *other_it); //to other current 00206 00207 public: 00208 ELIST_ITERATOR() { //constructor 00209 list = NULL; 00210 } //unassigned list 00211 00212 explicit ELIST_ITERATOR(ELIST *list_to_iterate); 00213 00214 void set_to_list( //change list 00215 ELIST *list_to_iterate); 00216 00217 void add_after_then_move( //add after current & 00218 ELIST_LINK *new_link); //move to new 00219 00220 void add_after_stay_put( //add after current & 00221 ELIST_LINK *new_link); //stay at current 00222 00223 void add_before_then_move( //add before current & 00224 ELIST_LINK *new_link); //move to new 00225 00226 void add_before_stay_put( //add before current & 00227 ELIST_LINK *new_link); //stay at current 00228 00229 void add_list_after( //add a list & 00230 ELIST *list_to_add); //stay at current 00231 00232 void add_list_before( //add a list & 00233 ELIST *list_to_add); //move to it 1st item 00234 00235 ELIST_LINK *data() { //get current data 00236 #ifndef NDEBUG 00237 if (!list) 00238 NO_LIST.error ("ELIST_ITERATOR::data", ABORT, NULL); 00239 if (!current) 00240 NULL_DATA.error ("ELIST_ITERATOR::data", ABORT, NULL); 00241 #endif 00242 return current; 00243 } 00244 00245 ELIST_LINK *data_relative( //get data + or - ... 00246 inT8 offset); //offset from current 00247 00248 ELIST_LINK *forward(); //move to next element 00249 00250 ELIST_LINK *extract(); //remove from list 00251 00252 ELIST_LINK *move_to_first(); //go to start of list 00253 00254 ELIST_LINK *move_to_last(); //go to end of list 00255 00256 void mark_cycle_pt(); //remember current 00257 00258 bool empty() { //is list empty? 00259 #ifndef NDEBUG 00260 if (!list) 00261 NO_LIST.error ("ELIST_ITERATOR::empty", ABORT, NULL); 00262 #endif 00263 return list->empty (); 00264 } 00265 00266 bool current_extracted() { //current extracted? 00267 return !current; 00268 } 00269 00270 bool at_first(); //Current is first? 00271 00272 bool at_last(); //Current is last? 00273 00274 bool cycled_list(); //Completed a cycle? 00275 00276 void add_to_end( //add at end & 00277 ELIST_LINK *new_link); //don't move 00278 00279 void exchange( //positions of 2 links 00280 ELIST_ITERATOR *other_it); //other iterator 00281 00282 inT32 length(); //# elements in list 00283 00284 void sort ( //sort elements 00285 int comparator ( //comparison routine 00286 const void *, const void *)); 00287 00288 }; 00289 00290 /*********************************************************************** 00291 * ELIST_ITERATOR::set_to_list 00292 * 00293 * (Re-)initialise the iterator to point to the start of the list_to_iterate 00294 * over. 00295 **********************************************************************/ 00296 00297 inline void ELIST_ITERATOR::set_to_list( //change list 00298 ELIST *list_to_iterate) { 00299 #ifndef NDEBUG 00300 if (!list_to_iterate) 00301 BAD_PARAMETER.error ("ELIST_ITERATOR::set_to_list", ABORT, 00302 "list_to_iterate is NULL"); 00303 #endif 00304 00305 list = list_to_iterate; 00306 prev = list->last; 00307 current = list->First (); 00308 next = current ? current->next : NULL; 00309 cycle_pt = NULL; //await explicit set 00310 started_cycling = FALSE; 00311 ex_current_was_last = FALSE; 00312 ex_current_was_cycle_pt = FALSE; 00313 } 00314 00315 00316 /*********************************************************************** 00317 * ELIST_ITERATOR::ELIST_ITERATOR 00318 * 00319 * CONSTRUCTOR - set iterator to specified list; 00320 **********************************************************************/ 00321 00322 inline ELIST_ITERATOR::ELIST_ITERATOR(ELIST *list_to_iterate) { 00323 set_to_list(list_to_iterate); 00324 } 00325 00326 00327 /*********************************************************************** 00328 * ELIST_ITERATOR::add_after_then_move 00329 * 00330 * Add a new element to the list after the current element and move the 00331 * iterator to the new element. 00332 **********************************************************************/ 00333 00334 inline void ELIST_ITERATOR::add_after_then_move( // element to add 00335 ELIST_LINK *new_element) { 00336 #ifndef NDEBUG 00337 if (!list) 00338 NO_LIST.error ("ELIST_ITERATOR::add_after_then_move", ABORT, NULL); 00339 if (!new_element) 00340 BAD_PARAMETER.error ("ELIST_ITERATOR::add_after_then_move", ABORT, 00341 "new_element is NULL"); 00342 if (new_element->next) 00343 STILL_LINKED.error ("ELIST_ITERATOR::add_after_then_move", ABORT, NULL); 00344 #endif 00345 00346 if (list->empty ()) { 00347 new_element->next = new_element; 00348 list->last = new_element; 00349 prev = next = new_element; 00350 } 00351 else { 00352 new_element->next = next; 00353 00354 if (current) { //not extracted 00355 current->next = new_element; 00356 prev = current; 00357 if (current == list->last) 00358 list->last = new_element; 00359 } 00360 else { //current extracted 00361 prev->next = new_element; 00362 if (ex_current_was_last) 00363 list->last = new_element; 00364 if (ex_current_was_cycle_pt) 00365 cycle_pt = new_element; 00366 } 00367 } 00368 current = new_element; 00369 } 00370 00371 00372 /*********************************************************************** 00373 * ELIST_ITERATOR::add_after_stay_put 00374 * 00375 * Add a new element to the list after the current element but do not move 00376 * the iterator to the new element. 00377 **********************************************************************/ 00378 00379 inline void ELIST_ITERATOR::add_after_stay_put( // element to add 00380 ELIST_LINK *new_element) { 00381 #ifndef NDEBUG 00382 if (!list) 00383 NO_LIST.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, NULL); 00384 if (!new_element) 00385 BAD_PARAMETER.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, 00386 "new_element is NULL"); 00387 if (new_element->next) 00388 STILL_LINKED.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, NULL); 00389 #endif 00390 00391 if (list->empty ()) { 00392 new_element->next = new_element; 00393 list->last = new_element; 00394 prev = next = new_element; 00395 ex_current_was_last = FALSE; 00396 current = NULL; 00397 } 00398 else { 00399 new_element->next = next; 00400 00401 if (current) { //not extracted 00402 current->next = new_element; 00403 if (prev == current) 00404 prev = new_element; 00405 if (current == list->last) 00406 list->last = new_element; 00407 } 00408 else { //current extracted 00409 prev->next = new_element; 00410 if (ex_current_was_last) { 00411 list->last = new_element; 00412 ex_current_was_last = FALSE; 00413 } 00414 } 00415 next = new_element; 00416 } 00417 } 00418 00419 00420 /*********************************************************************** 00421 * ELIST_ITERATOR::add_before_then_move 00422 * 00423 * Add a new element to the list before the current element and move the 00424 * iterator to the new element. 00425 **********************************************************************/ 00426 00427 inline void ELIST_ITERATOR::add_before_then_move( // element to add 00428 ELIST_LINK *new_element) { 00429 #ifndef NDEBUG 00430 if (!list) 00431 NO_LIST.error ("ELIST_ITERATOR::add_before_then_move", ABORT, NULL); 00432 if (!new_element) 00433 BAD_PARAMETER.error ("ELIST_ITERATOR::add_before_then_move", ABORT, 00434 "new_element is NULL"); 00435 if (new_element->next) 00436 STILL_LINKED.error ("ELIST_ITERATOR::add_before_then_move", ABORT, NULL); 00437 #endif 00438 00439 if (list->empty ()) { 00440 new_element->next = new_element; 00441 list->last = new_element; 00442 prev = next = new_element; 00443 } 00444 else { 00445 prev->next = new_element; 00446 if (current) { //not extracted 00447 new_element->next = current; 00448 next = current; 00449 } 00450 else { //current extracted 00451 new_element->next = next; 00452 if (ex_current_was_last) 00453 list->last = new_element; 00454 if (ex_current_was_cycle_pt) 00455 cycle_pt = new_element; 00456 } 00457 } 00458 current = new_element; 00459 } 00460 00461 00462 /*********************************************************************** 00463 * ELIST_ITERATOR::add_before_stay_put 00464 * 00465 * Add a new element to the list before the current element but don't move the 00466 * iterator to the new element. 00467 **********************************************************************/ 00468 00469 inline void ELIST_ITERATOR::add_before_stay_put( // element to add 00470 ELIST_LINK *new_element) { 00471 #ifndef NDEBUG 00472 if (!list) 00473 NO_LIST.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, NULL); 00474 if (!new_element) 00475 BAD_PARAMETER.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, 00476 "new_element is NULL"); 00477 if (new_element->next) 00478 STILL_LINKED.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, NULL); 00479 #endif 00480 00481 if (list->empty ()) { 00482 new_element->next = new_element; 00483 list->last = new_element; 00484 prev = next = new_element; 00485 ex_current_was_last = TRUE; 00486 current = NULL; 00487 } 00488 else { 00489 prev->next = new_element; 00490 if (current) { //not extracted 00491 new_element->next = current; 00492 if (next == current) 00493 next = new_element; 00494 } 00495 else { //current extracted 00496 new_element->next = next; 00497 if (ex_current_was_last) 00498 list->last = new_element; 00499 } 00500 prev = new_element; 00501 } 00502 } 00503 00504 00505 /*********************************************************************** 00506 * ELIST_ITERATOR::add_list_after 00507 * 00508 * Insert another list to this list after the current element but don't move the 00509 * iterator. 00510 **********************************************************************/ 00511 00512 inline void ELIST_ITERATOR::add_list_after(ELIST *list_to_add) { 00513 #ifndef NDEBUG 00514 if (!list) 00515 NO_LIST.error ("ELIST_ITERATOR::add_list_after", ABORT, NULL); 00516 if (!list_to_add) 00517 BAD_PARAMETER.error ("ELIST_ITERATOR::add_list_after", ABORT, 00518 "list_to_add is NULL"); 00519 #endif 00520 00521 if (!list_to_add->empty ()) { 00522 if (list->empty ()) { 00523 list->last = list_to_add->last; 00524 prev = list->last; 00525 next = list->First (); 00526 ex_current_was_last = TRUE; 00527 current = NULL; 00528 } 00529 else { 00530 if (current) { //not extracted 00531 current->next = list_to_add->First (); 00532 if (current == list->last) 00533 list->last = list_to_add->last; 00534 list_to_add->last->next = next; 00535 next = current->next; 00536 } 00537 else { //current extracted 00538 prev->next = list_to_add->First (); 00539 if (ex_current_was_last) { 00540 list->last = list_to_add->last; 00541 ex_current_was_last = FALSE; 00542 } 00543 list_to_add->last->next = next; 00544 next = prev->next; 00545 } 00546 } 00547 list_to_add->last = NULL; 00548 } 00549 } 00550 00551 00552 /*********************************************************************** 00553 * ELIST_ITERATOR::add_list_before 00554 * 00555 * Insert another list to this list before the current element. Move the 00556 * iterator to the start of the inserted elements 00557 * iterator. 00558 **********************************************************************/ 00559 00560 inline void ELIST_ITERATOR::add_list_before(ELIST *list_to_add) { 00561 #ifndef NDEBUG 00562 if (!list) 00563 NO_LIST.error ("ELIST_ITERATOR::add_list_before", ABORT, NULL); 00564 if (!list_to_add) 00565 BAD_PARAMETER.error ("ELIST_ITERATOR::add_list_before", ABORT, 00566 "list_to_add is NULL"); 00567 #endif 00568 00569 if (!list_to_add->empty ()) { 00570 if (list->empty ()) { 00571 list->last = list_to_add->last; 00572 prev = list->last; 00573 current = list->First (); 00574 next = current->next; 00575 ex_current_was_last = FALSE; 00576 } 00577 else { 00578 prev->next = list_to_add->First (); 00579 if (current) { //not extracted 00580 list_to_add->last->next = current; 00581 } 00582 else { //current extracted 00583 list_to_add->last->next = next; 00584 if (ex_current_was_last) 00585 list->last = list_to_add->last; 00586 if (ex_current_was_cycle_pt) 00587 cycle_pt = prev->next; 00588 } 00589 current = prev->next; 00590 next = current->next; 00591 } 00592 list_to_add->last = NULL; 00593 } 00594 } 00595 00596 00597 /*********************************************************************** 00598 * ELIST_ITERATOR::extract 00599 * 00600 * Do extraction by removing current from the list, returning it to the 00601 * caller, but NOT updating the iterator. (So that any calling loop can do 00602 * this.) The iterator's current points to NULL. If the extracted element 00603 * is to be deleted, this is the callers responsibility. 00604 **********************************************************************/ 00605 00606 inline ELIST_LINK *ELIST_ITERATOR::extract() { 00607 ELIST_LINK *extracted_link; 00608 00609 #ifndef NDEBUG 00610 if (!list) 00611 NO_LIST.error ("ELIST_ITERATOR::extract", ABORT, NULL); 00612 if (!current) //list empty or 00613 //element extracted 00614 NULL_CURRENT.error ("ELIST_ITERATOR::extract", 00615 ABORT, NULL); 00616 #endif 00617 00618 if (list->singleton()) { 00619 // Special case where we do need to change the iterator. 00620 prev = next = list->last = NULL; 00621 } else { 00622 prev->next = next; //remove from list 00623 00624 if (current == list->last) { 00625 list->last = prev; 00626 ex_current_was_last = TRUE; 00627 } else { 00628 ex_current_was_last = FALSE; 00629 } 00630 } 00631 // Always set ex_current_was_cycle_pt so an add/forward will work in a loop. 00632 ex_current_was_cycle_pt = (current == cycle_pt) ? TRUE : FALSE; 00633 extracted_link = current; 00634 extracted_link->next = NULL; //for safety 00635 current = NULL; 00636 return extracted_link; 00637 } 00638 00639 00640 /*********************************************************************** 00641 * ELIST_ITERATOR::move_to_first() 00642 * 00643 * Move current so that it is set to the start of the list. 00644 * Return data just in case anyone wants it. 00645 **********************************************************************/ 00646 00647 inline ELIST_LINK *ELIST_ITERATOR::move_to_first() { 00648 #ifndef NDEBUG 00649 if (!list) 00650 NO_LIST.error ("ELIST_ITERATOR::move_to_first", ABORT, NULL); 00651 #endif 00652 00653 current = list->First (); 00654 prev = list->last; 00655 next = current ? current->next : NULL; 00656 return current; 00657 } 00658 00659 00660 /*********************************************************************** 00661 * ELIST_ITERATOR::mark_cycle_pt() 00662 * 00663 * Remember the current location so that we can tell whether we've returned 00664 * to this point later. 00665 * 00666 * If the current point is deleted either now, or in the future, the cycle 00667 * point will be set to the next item which is set to current. This could be 00668 * by a forward, add_after_then_move or add_after_then_move. 00669 **********************************************************************/ 00670 00671 inline void ELIST_ITERATOR::mark_cycle_pt() { 00672 #ifndef NDEBUG 00673 if (!list) 00674 NO_LIST.error ("ELIST_ITERATOR::mark_cycle_pt", ABORT, NULL); 00675 #endif 00676 00677 if (current) 00678 cycle_pt = current; 00679 else 00680 ex_current_was_cycle_pt = TRUE; 00681 started_cycling = FALSE; 00682 } 00683 00684 00685 /*********************************************************************** 00686 * ELIST_ITERATOR::at_first() 00687 * 00688 * Are we at the start of the list? 00689 * 00690 **********************************************************************/ 00691 00692 inline bool ELIST_ITERATOR::at_first() { 00693 #ifndef NDEBUG 00694 if (!list) 00695 NO_LIST.error ("ELIST_ITERATOR::at_first", ABORT, NULL); 00696 #endif 00697 00698 //we're at a deleted 00699 return ((list->empty ()) || (current == list->First ()) || ((current == NULL) && 00700 (prev == list->last) && //NON-last pt between 00701 !ex_current_was_last)); //first and last 00702 } 00703 00704 00705 /*********************************************************************** 00706 * ELIST_ITERATOR::at_last() 00707 * 00708 * Are we at the end of the list? 00709 * 00710 **********************************************************************/ 00711 00712 inline bool ELIST_ITERATOR::at_last() { 00713 #ifndef NDEBUG 00714 if (!list) 00715 NO_LIST.error ("ELIST_ITERATOR::at_last", ABORT, NULL); 00716 #endif 00717 00718 //we're at a deleted 00719 return ((list->empty ()) || (current == list->last) || ((current == NULL) && 00720 (prev == list->last) && //last point between 00721 ex_current_was_last)); //first and last 00722 } 00723 00724 00725 /*********************************************************************** 00726 * ELIST_ITERATOR::cycled_list() 00727 * 00728 * Have we returned to the cycle_pt since it was set? 00729 * 00730 **********************************************************************/ 00731 00732 inline bool ELIST_ITERATOR::cycled_list() { 00733 #ifndef NDEBUG 00734 if (!list) 00735 NO_LIST.error ("ELIST_ITERATOR::cycled_list", ABORT, NULL); 00736 #endif 00737 00738 return ((list->empty ()) || ((current == cycle_pt) && started_cycling)); 00739 00740 } 00741 00742 00743 /*********************************************************************** 00744 * ELIST_ITERATOR::length() 00745 * 00746 * Return the length of the list 00747 * 00748 **********************************************************************/ 00749 00750 inline inT32 ELIST_ITERATOR::length() { 00751 #ifndef NDEBUG 00752 if (!list) 00753 NO_LIST.error ("ELIST_ITERATOR::length", ABORT, NULL); 00754 #endif 00755 00756 return list->length (); 00757 } 00758 00759 00760 /*********************************************************************** 00761 * ELIST_ITERATOR::sort() 00762 * 00763 * Sort the elements of the list, then reposition at the start. 00764 * 00765 **********************************************************************/ 00766 00767 inline void 00768 ELIST_ITERATOR::sort ( //sort elements 00769 int comparator ( //comparison routine 00770 const void *, const void *)) { 00771 #ifndef NDEBUG 00772 if (!list) 00773 NO_LIST.error ("ELIST_ITERATOR::sort", ABORT, NULL); 00774 #endif 00775 00776 list->sort (comparator); 00777 move_to_first(); 00778 } 00779 00780 00781 /*********************************************************************** 00782 * ELIST_ITERATOR::add_to_end 00783 * 00784 * Add a new element to the end of the list without moving the iterator. 00785 * This is provided because a single linked list cannot move to the last as 00786 * the iterator couldn't set its prev pointer. Adding to the end is 00787 * essential for implementing 00788 queues. 00789 **********************************************************************/ 00790 00791 inline void ELIST_ITERATOR::add_to_end( // element to add 00792 ELIST_LINK *new_element) { 00793 #ifndef NDEBUG 00794 if (!list) 00795 NO_LIST.error ("ELIST_ITERATOR::add_to_end", ABORT, NULL); 00796 if (!new_element) 00797 BAD_PARAMETER.error ("ELIST_ITERATOR::add_to_end", ABORT, 00798 "new_element is NULL"); 00799 if (new_element->next) 00800 STILL_LINKED.error ("ELIST_ITERATOR::add_to_end", ABORT, NULL); 00801 #endif 00802 00803 if (this->at_last ()) { 00804 this->add_after_stay_put (new_element); 00805 } 00806 else { 00807 if (this->at_first ()) { 00808 this->add_before_stay_put (new_element); 00809 list->last = new_element; 00810 } 00811 else { //Iteratr is elsewhere 00812 new_element->next = list->last->next; 00813 list->last->next = new_element; 00814 list->last = new_element; 00815 } 00816 } 00817 } 00818 00819 00820 /*********************************************************************** 00821 ******************** MACROS ************************************** 00822 ***********************************************************************/ 00823 00824 /*********************************************************************** 00825 QUOTE_IT MACRO DEFINITION 00826 =========================== 00827 Replace <parm> with "<parm>". <parm> may be an arbitrary number of tokens 00828 ***********************************************************************/ 00829 00830 #define QUOTE_IT( parm ) #parm 00831 00832 /*********************************************************************** 00833 ELISTIZE( CLASSNAME ) MACRO 00834 ============================ 00835 00836 CLASSNAME is assumed to be the name of a class which has a baseclass of 00837 ELIST_LINK. 00838 00839 NOTE: Because we don't use virtual functions in the list code, the list code 00840 will NOT work correctly for classes derived from this. 00841 00842 The macros generate: 00843 - An element deletion function: CLASSNAME##_zapper 00844 - An E_LIST subclass: CLASSNAME##_LIST 00845 - An E_LIST_ITERATOR subclass: CLASSNAME##_IT 00846 00847 NOTE: Generated names are DELIBERATELY designed to clash with those for 00848 ELIST2IZE but NOT with those for CLISTIZE and CLIST2IZE 00849 00850 Two macros are provided: ELISTIZE and ELISTIZEH. 00851 The ...IZEH macros just define the class names for use in .h files 00852 The ...IZE macros define the code use in .c files 00853 ***********************************************************************/ 00854 00855 /*********************************************************************** 00856 ELISTIZEH( CLASSNAME ) MACRO 00857 00858 ELISTIZEH is a concatenation of 3 fragments ELISTIZEH_A, ELISTIZEH_B and 00859 ELISTIZEH_C. 00860 ***********************************************************************/ 00861 00862 #define ELISTIZEH_A(CLASSNAME) \ 00863 \ 00864 extern DLLSYM void CLASSNAME##_zapper(ELIST_LINK* link); 00865 00866 #define ELISTIZEH_B(CLASSNAME) \ 00867 \ 00868 /*********************************************************************** \ 00869 * CLASS - CLASSNAME##_LIST \ 00870 * \ 00871 * List class for class CLASSNAME \ 00872 * \ 00873 **********************************************************************/ \ 00874 \ 00875 class DLLSYM CLASSNAME##_LIST : public ELIST { \ 00876 public: \ 00877 CLASSNAME##_LIST():ELIST() {} \ 00878 \ 00879 void clear() { /* delete elements */\ 00880 ELIST::internal_clear(&CLASSNAME##_zapper); \ 00881 } \ 00882 \ 00883 ~CLASSNAME##_LIST() { \ 00884 clear(); \ 00885 } \ 00886 \ 00887 /* Become a deep copy of src_list*/ \ 00888 void deep_copy(const CLASSNAME##_LIST* src_list, \ 00889 CLASSNAME* (*copier)(const CLASSNAME*)); \ 00890 \ 00891 private: \ 00892 /* Prevent assign and copy construction. */ \ 00893 CLASSNAME##_LIST(const CLASSNAME##_LIST&) { \ 00894 DONT_CONSTRUCT_LIST_BY_COPY.error(QUOTE_IT(CLASSNAME##_LIST), ABORT, NULL);\ 00895 } \ 00896 void operator=(const CLASSNAME##_LIST&) { \ 00897 DONT_ASSIGN_LISTS.error(QUOTE_IT(CLASSNAME##_LIST), ABORT, NULL ); \ 00898 } \ 00899 00900 #define ELISTIZEH_C( CLASSNAME ) \ 00901 }; \ 00902 \ 00903 \ 00904 \ 00905 /*********************************************************************** \ 00906 * CLASS - CLASSNAME##_IT \ 00907 * \ 00908 * Iterator class for class CLASSNAME##_LIST \ 00909 * \ 00910 * Note: We don't need to coerce pointers to member functions input \ 00911 * parameters as these are automatically converted to the type of the base \ 00912 * type. ("A ptr to a class may be converted to a pointer to a public base \ 00913 * class of that class") \ 00914 **********************************************************************/ \ 00915 \ 00916 class DLLSYM CLASSNAME##_IT : public ELIST_ITERATOR { \ 00917 public: \ 00918 CLASSNAME##_IT():ELIST_ITERATOR(){} \ 00919 \ 00920 /* TODO(rays) This constructor should be explicit, but that means changing \ 00921 hundreds of incorrect initializations of iterators that use = over () */ \ 00922 CLASSNAME##_IT(CLASSNAME##_LIST* list) : ELIST_ITERATOR(list) {} \ 00923 \ 00924 CLASSNAME* data() { \ 00925 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::data()); \ 00926 } \ 00927 \ 00928 CLASSNAME* data_relative(inT8 offset) { \ 00929 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::data_relative(offset));\ 00930 } \ 00931 \ 00932 CLASSNAME* forward() { \ 00933 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::forward()); \ 00934 } \ 00935 \ 00936 CLASSNAME* extract() { \ 00937 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::extract()); \ 00938 } \ 00939 \ 00940 CLASSNAME* move_to_first() { \ 00941 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::move_to_first()); \ 00942 } \ 00943 \ 00944 CLASSNAME* move_to_last() { \ 00945 return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::move_to_last()); \ 00946 } \ 00947 }; 00948 00949 #define ELISTIZEH( CLASSNAME ) \ 00950 \ 00951 ELISTIZEH_A( CLASSNAME ) \ 00952 \ 00953 ELISTIZEH_B( CLASSNAME ) \ 00954 \ 00955 ELISTIZEH_C( CLASSNAME ) 00956 00957 00958 /*********************************************************************** 00959 ELISTIZE( CLASSNAME ) MACRO 00960 ***********************************************************************/ 00961 00962 #define ELISTIZE(CLASSNAME) \ 00963 \ 00964 /*********************************************************************** \ 00965 * CLASSNAME##_zapper \ 00966 * \ 00967 * A function which can delete a CLASSNAME element. This is passed to the \ 00968 * generic clear list member function so that when a list is cleared the \ 00969 * elements on the list are properly destroyed from the base class, even \ 00970 * though we don't use a virtual destructor function. \ 00971 **********************************************************************/ \ 00972 \ 00973 DLLSYM void CLASSNAME##_zapper(ELIST_LINK* link) { \ 00974 delete reinterpret_cast<CLASSNAME*>(link); \ 00975 } \ 00976 \ 00977 /* Become a deep copy of src_list*/ \ 00978 void CLASSNAME##_LIST::deep_copy(const CLASSNAME##_LIST* src_list, \ 00979 CLASSNAME* (*copier)(const CLASSNAME*)) { \ 00980 \ 00981 CLASSNAME##_IT from_it(const_cast<CLASSNAME##_LIST*>(src_list)); \ 00982 CLASSNAME##_IT to_it(this); \ 00983 \ 00984 for (from_it.mark_cycle_pt(); !from_it.cycled_list(); from_it.forward()) \ 00985 to_it.add_after_then_move((*copier)(from_it.data())); \ 00986 } 00987 00988 #endif