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