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