tesseract
3.03
|
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 }