tesseract 3.04.01

ccutil/clst.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        clst.c  (Formerly clist.c)
00003  * Description: CONS cell list handling code which is not in the include file.
00004  * Author:      Phil Cheatle
00005  * Created:     Mon Jan 28 08:33:13 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 #include <stdlib.h>
00021 #include "clst.h"
00022 
00023 /***********************************************************************
00024  *  MEMBER FUNCTIONS OF CLASS: CLIST
00025  *  ================================
00026  **********************************************************************/
00027 
00028 /***********************************************************************
00029  *                                                      CLIST::internal_deep_clear
00030  *
00031  *  Used by the "deep_clear" member function of derived list
00032  *  classes to destroy all the elements on the list.
00033  *  The calling function passes a "zapper" function which can be called to
00034  *  delete each data element of the list, regardless of its class.  This
00035  *  technique permits a generic clear function to destroy elements of
00036  *  different derived types correctly, without requiring virtual functions and
00037  *  the consequential memory overhead.
00038  **********************************************************************/
00039 
00040 void
00041 CLIST::internal_deep_clear (     //destroy all links
00042 void (*zapper) (void *)) {       //ptr to zapper functn
00043   CLIST_LINK *ptr;
00044   CLIST_LINK *next;
00045 
00046   if (!empty ()) {
00047     ptr = last->next;            //set to first
00048     last->next = NULL;           //break circle
00049     last = NULL;                 //set list empty
00050     while (ptr) {
00051       next = ptr->next;
00052       zapper (ptr->data);
00053       delete(ptr);
00054       ptr = next;
00055     }
00056   }
00057 }
00058 
00059 
00060 /***********************************************************************
00061  *                                                      CLIST::shallow_clear
00062  *
00063  *  Used by the destructor and the "shallow_clear" member function of derived
00064  *  list classes to destroy the list.
00065  *  The data elements are NOT destroyed.
00066  *
00067  **********************************************************************/
00068 
00069 void CLIST::shallow_clear() {  //destroy all links
00070   CLIST_LINK *ptr;
00071   CLIST_LINK *next;
00072 
00073   if (!empty ()) {
00074     ptr = last->next;            //set to first
00075     last->next = NULL;           //break circle
00076     last = NULL;                 //set list empty
00077     while (ptr) {
00078       next = ptr->next;
00079       delete(ptr);
00080       ptr = next;
00081     }
00082   }
00083 }
00084 
00085 /***********************************************************************
00086  *                                                      CLIST::assign_to_sublist
00087  *
00088  *  The list is set to a sublist of another list.  "This" list must be empty
00089  *  before this function is invoked.  The two iterators passed must refer to
00090  *  the same list, different from "this" one.  The sublist removed is the
00091  *  inclusive list from start_it's current position to end_it's current
00092  *  position.  If this range passes over the end of the source list then the
00093  *  source list has its end set to the previous element of start_it.  The
00094  *  extracted sublist is unaffected by the end point of the source list, its
00095  *  end point is always the end_it position.
00096  **********************************************************************/
00097 
00098 void CLIST::assign_to_sublist(                           //to this list
00099                               CLIST_ITERATOR *start_it,  //from list start
00100                               CLIST_ITERATOR *end_it) {  //from list end
00101   const ERRCODE LIST_NOT_EMPTY =
00102     "Destination list must be empty before extracting a sublist";
00103 
00104   if (!empty ())
00105     LIST_NOT_EMPTY.error ("CLIST.assign_to_sublist", ABORT, NULL);
00106 
00107   last = start_it->extract_sublist (end_it);
00108 }
00109 
00110 
00111 /***********************************************************************
00112  *                                                      CLIST::length
00113  *
00114  *  Return count of elements on list
00115  **********************************************************************/
00116 
00117 inT32 CLIST::length() const {  //count elements
00118   CLIST_ITERATOR it(const_cast<CLIST*>(this));
00119   inT32 count = 0;
00120 
00121   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward())
00122     count++;
00123   return count;
00124 }
00125 
00126 
00127 /***********************************************************************
00128  *                                                      CLIST::sort
00129  *
00130  *  Sort elements on list
00131  **********************************************************************/
00132 
00133 void
00134 CLIST::sort (                    //sort elements
00135 int comparator (                 //comparison routine
00136 const void *, const void *)) {
00137   CLIST_ITERATOR it(this);
00138   inT32 count;
00139   void **base;                   //ptr array to sort
00140   void **current;
00141   inT32 i;
00142 
00143   /* Allocate an array of pointers, one per list element */
00144   count = length ();
00145   base = (void **) malloc (count * sizeof (void *));
00146 
00147   /* Extract all elements, putting the pointers in the array */
00148   current = base;
00149   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00150     *current = it.extract ();
00151     current++;
00152   }
00153 
00154   /* Sort the pointer array */
00155   qsort ((char *) base, count, sizeof (*base), comparator);
00156 
00157   /* Rebuild the list from the sorted pointers */
00158   current = base;
00159   for (i = 0; i < count; i++) {
00160     it.add_to_end (*current);
00161     current++;
00162   }
00163   free(base);
00164 }
00165 
00166 // Assuming list has been sorted already, insert new_data to
00167 // keep the list sorted according to the same comparison function.
00168 // Comparison function is the same as used by sort, i.e. uses double
00169 // indirection. Time is O(1) to add to beginning or end.
00170 // Time is linear to add pre-sorted items to an empty list.
00171 // If unique, then don't add duplicate entries.
00172 // Returns true if the element was added to the list.
00173 bool CLIST::add_sorted(int comparator(const void*, const void*),
00174                        bool unique, void* new_data) {
00175   // Check for adding at the end.
00176   if (last == NULL || comparator(&last->data, &new_data) < 0) {
00177     CLIST_LINK* new_element = new CLIST_LINK;
00178     new_element->data = new_data;
00179     if (last == NULL) {
00180       new_element->next = new_element;
00181     } else {
00182       new_element->next = last->next;
00183       last->next = new_element;
00184     }
00185     last = new_element;
00186     return true;
00187   } else if (!unique || last->data != new_data) {
00188     // Need to use an iterator.
00189     CLIST_ITERATOR it(this);
00190     for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00191       void* data = it.data();
00192       if (data == new_data && unique)
00193         return false;
00194       if (comparator(&data, &new_data) > 0)
00195         break;
00196     }
00197     if (it.cycled_list())
00198       it.add_to_end(new_data);
00199     else
00200       it.add_before_then_move(new_data);
00201     return true;
00202   }
00203   return false;
00204 }
00205 
00206 // Assuming that the minuend and subtrahend are already sorted with
00207 // the same comparison function, shallow clears this and then copies
00208 // the set difference minuend - subtrahend to this, being the elements
00209 // of minuend that do not compare equal to anything in subtrahend.
00210 // If unique is true, any duplicates in minuend are also eliminated.
00211 void CLIST::set_subtract(int comparator(const void*, const void*),
00212                          bool unique,
00213                          CLIST* minuend, CLIST* subtrahend) {
00214   shallow_clear();
00215   CLIST_ITERATOR m_it(minuend);
00216   CLIST_ITERATOR s_it(subtrahend);
00217   // Since both lists are sorted, finding the subtras that are not
00218   // minus is a case of a parallel iteration.
00219   for (m_it.mark_cycle_pt(); !m_it.cycled_list(); m_it.forward()) {
00220     void* minu = m_it.data();
00221     void* subtra = NULL;
00222     if (!s_it.empty()) {
00223       subtra = s_it.data();
00224       while (!s_it.at_last() &&
00225              comparator(&subtra, &minu) < 0) {
00226         s_it.forward();
00227         subtra = s_it.data();
00228       }
00229     }
00230     if (subtra == NULL || comparator(&subtra, &minu) != 0)
00231       add_sorted(comparator, unique, minu);
00232   }
00233 }
00234 
00235 
00236 /***********************************************************************
00237  *  MEMBER FUNCTIONS OF CLASS: CLIST_ITERATOR
00238  *  =========================================
00239  **********************************************************************/
00240 
00241 /***********************************************************************
00242  *                                                      CLIST_ITERATOR::forward
00243  *
00244  *  Move the iterator to the next element of the list.
00245  *  REMEMBER: ALL LISTS ARE CIRCULAR.
00246  **********************************************************************/
00247 
00248 void *CLIST_ITERATOR::forward() {
00249   #ifndef NDEBUG
00250   if (!list)
00251     NO_LIST.error ("CLIST_ITERATOR::forward", ABORT, NULL);
00252   #endif
00253   if (list->empty ())
00254     return NULL;
00255 
00256   if (current) {                 //not removed so
00257                                  //set previous
00258     prev = current;
00259     started_cycling = TRUE;
00260     // In case next is deleted by another iterator, get next from current.
00261     current = current->next;
00262   } else {
00263     if (ex_current_was_cycle_pt)
00264       cycle_pt = next;
00265     current = next;
00266   }
00267   next = current->next;
00268 
00269   #ifndef NDEBUG
00270   if (!current)
00271     NULL_DATA.error ("CLIST_ITERATOR::forward", ABORT, NULL);
00272   if (!next)
00273     NULL_NEXT.error ("CLIST_ITERATOR::forward", ABORT,
00274                      "This is: %p  Current is: %p", this, current);
00275   #endif
00276   return current->data;
00277 }
00278 
00279 
00280 /***********************************************************************
00281  *                                                      CLIST_ITERATOR::data_relative
00282  *
00283  *  Return the data pointer to the element "offset" elements from current.
00284  *  "offset" must not be less than -1.
00285  *  (This function can't be INLINEd because it contains a loop)
00286  **********************************************************************/
00287 
00288 void *CLIST_ITERATOR::data_relative(                //get data + or - ...
00289                                     inT8 offset) {  //offset from current
00290   CLIST_LINK *ptr;
00291 
00292   #ifndef NDEBUG
00293   if (!list)
00294     NO_LIST.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
00295   if (list->empty ())
00296     EMPTY_LIST.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
00297   if (offset < -1)
00298     BAD_PARAMETER.error ("CLIST_ITERATOR::data_relative", ABORT,
00299       "offset < -l");
00300   #endif
00301 
00302   if (offset == -1)
00303     ptr = prev;
00304   else
00305     for (ptr = current ? current : prev; offset-- > 0; ptr = ptr->next);
00306 
00307   #ifndef NDEBUG
00308   if (!ptr)
00309     NULL_DATA.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
00310   #endif
00311 
00312   return ptr->data;
00313 }
00314 
00315 
00316 /***********************************************************************
00317  *                                                      CLIST_ITERATOR::move_to_last()
00318  *
00319  *  Move current so that it is set to the end of the list.
00320  *  Return data just in case anyone wants it.
00321  *  (This function can't be INLINEd because it contains a loop)
00322  **********************************************************************/
00323 
00324 void *CLIST_ITERATOR::move_to_last() {
00325   #ifndef NDEBUG
00326   if (!list)
00327     NO_LIST.error ("CLIST_ITERATOR::move_to_last", ABORT, NULL);
00328   #endif
00329 
00330   while (current != list->last)
00331     forward();
00332 
00333   if (current == NULL)
00334     return NULL;
00335   else
00336     return current->data;
00337 }
00338 
00339 
00340 /***********************************************************************
00341  *                                                      CLIST_ITERATOR::exchange()
00342  *
00343  *  Given another iterator, whose current element is a different element on
00344  *  the same list list OR an element of another list, exchange the two current
00345  *  elements.  On return, each iterator points to the element which was the
00346  *  other iterators current on entry.
00347  *  (This function hasn't been in-lined because its a bit big!)
00348  **********************************************************************/
00349 
00350 void CLIST_ITERATOR::exchange(                             //positions of 2 links
00351                               CLIST_ITERATOR *other_it) {  //other iterator
00352   const ERRCODE DONT_EXCHANGE_DELETED =
00353     "Can't exchange deleted elements of lists";
00354 
00355   CLIST_LINK *old_current;
00356 
00357   #ifndef NDEBUG
00358   if (!list)
00359     NO_LIST.error ("CLIST_ITERATOR::exchange", ABORT, NULL);
00360   if (!other_it)
00361     BAD_PARAMETER.error ("CLIST_ITERATOR::exchange", ABORT, "other_it NULL");
00362   if (!(other_it->list))
00363     NO_LIST.error ("CLIST_ITERATOR::exchange", ABORT, "other_it");
00364   #endif
00365 
00366   /* Do nothing if either list is empty or if both iterators reference the same
00367   link */
00368 
00369   if ((list->empty ()) ||
00370     (other_it->list->empty ()) || (current == other_it->current))
00371     return;
00372 
00373   /* Error if either current element is deleted */
00374 
00375   if (!current || !other_it->current)
00376     DONT_EXCHANGE_DELETED.error ("CLIST_ITERATOR.exchange", ABORT, NULL);
00377 
00378   /* Now handle the 4 cases: doubleton list; non-doubleton adjacent elements
00379   (other before this); non-doubleton adjacent elements (this before other);
00380   non-adjacent elements. */
00381 
00382                                  //adjacent links
00383   if ((next == other_it->current) ||
00384   (other_it->next == current)) {
00385                                  //doubleton list
00386     if ((next == other_it->current) &&
00387     (other_it->next == current)) {
00388       prev = next = current;
00389       other_it->prev = other_it->next = other_it->current;
00390     }
00391     else {                       //non-doubleton with
00392                                  //adjacent links
00393                                  //other before this
00394       if (other_it->next == current) {
00395         other_it->prev->next = current;
00396         other_it->current->next = next;
00397         current->next = other_it->current;
00398         other_it->next = other_it->current;
00399         prev = current;
00400       }
00401       else {                     //this before other
00402         prev->next = other_it->current;
00403         current->next = other_it->next;
00404         other_it->current->next = current;
00405         next = current;
00406         other_it->prev = other_it->current;
00407       }
00408     }
00409   }
00410   else {                         //no overlap
00411     prev->next = other_it->current;
00412     current->next = other_it->next;
00413     other_it->prev->next = current;
00414     other_it->current->next = next;
00415   }
00416 
00417   /* update end of list pointer when necessary (remember that the 2 iterators
00418     may iterate over different lists!) */
00419 
00420   if (list->last == current)
00421     list->last = other_it->current;
00422   if (other_it->list->last == other_it->current)
00423     other_it->list->last = current;
00424 
00425   if (current == cycle_pt)
00426     cycle_pt = other_it->cycle_pt;
00427   if (other_it->current == other_it->cycle_pt)
00428     other_it->cycle_pt = cycle_pt;
00429 
00430   /* The actual exchange - in all cases*/
00431 
00432   old_current = current;
00433   current = other_it->current;
00434   other_it->current = old_current;
00435 }
00436 
00437 
00438 /***********************************************************************
00439  *                                                      CLIST_ITERATOR::extract_sublist()
00440  *
00441  *  This is a private member, used only by CLIST::assign_to_sublist.
00442  *  Given another iterator for the same list, extract the links from THIS to
00443  *  OTHER inclusive, link them into a new circular list, and return a
00444  *  pointer to the last element.
00445  *  (Can't inline this function because it contains a loop)
00446  **********************************************************************/
00447 
00448 CLIST_LINK *CLIST_ITERATOR::extract_sublist(                             //from this current
00449                                             CLIST_ITERATOR *other_it) {  //to other current
00450   CLIST_ITERATOR temp_it = *this;
00451   CLIST_LINK *end_of_new_list;
00452 
00453   const ERRCODE BAD_SUBLIST = "Can't find sublist end point in original list";
00454   #ifndef NDEBUG
00455   const ERRCODE BAD_EXTRACTION_PTS =
00456     "Can't extract sublist from points on different lists";
00457   const ERRCODE DONT_EXTRACT_DELETED =
00458     "Can't extract a sublist marked by deleted points";
00459 
00460   if (!other_it)
00461     BAD_PARAMETER.error ("CLIST_ITERATOR::extract_sublist", ABORT,
00462       "other_it NULL");
00463   if (!list)
00464     NO_LIST.error ("CLIST_ITERATOR::extract_sublist", ABORT, NULL);
00465   if (list != other_it->list)
00466     BAD_EXTRACTION_PTS.error ("CLIST_ITERATOR.extract_sublist", ABORT, NULL);
00467   if (list->empty ())
00468     EMPTY_LIST.error ("CLIST_ITERATOR::extract_sublist", ABORT, NULL);
00469 
00470   if (!current || !other_it->current)
00471     DONT_EXTRACT_DELETED.error ("CLIST_ITERATOR.extract_sublist", ABORT,
00472       NULL);
00473   #endif
00474 
00475   ex_current_was_last = other_it->ex_current_was_last = FALSE;
00476   ex_current_was_cycle_pt = FALSE;
00477   other_it->ex_current_was_cycle_pt = FALSE;
00478 
00479   temp_it.mark_cycle_pt ();
00480   do {                           //walk sublist
00481     if (temp_it.cycled_list ())  //can't find end pt
00482       BAD_SUBLIST.error ("CLIST_ITERATOR.extract_sublist", ABORT, NULL);
00483 
00484     if (temp_it.at_last ()) {
00485       list->last = prev;
00486       ex_current_was_last = other_it->ex_current_was_last = TRUE;
00487     }
00488 
00489     if (temp_it.current == cycle_pt)
00490       ex_current_was_cycle_pt = TRUE;
00491 
00492     if (temp_it.current == other_it->cycle_pt)
00493       other_it->ex_current_was_cycle_pt = TRUE;
00494 
00495     temp_it.forward ();
00496   }
00497   while (temp_it.prev != other_it->current);
00498 
00499                                  //circularise sublist
00500   other_it->current->next = current;
00501   end_of_new_list = other_it->current;
00502 
00503                                  //sublist = whole list
00504   if (prev == other_it->current) {
00505     list->last = NULL;
00506     prev = current = next = NULL;
00507     other_it->prev = other_it->current = other_it->next = NULL;
00508   }
00509   else {
00510     prev->next = other_it->next;
00511     current = other_it->current = NULL;
00512     next = other_it->next;
00513     other_it->prev = prev;
00514   }
00515   return end_of_new_list;
00516 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines