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