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