tesseract 3.04.01

ccutil/elst.h

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines