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