tesseract  4.00.00dev
elst2.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: elst2.c (Formerly elist2.c)
3  * Description: Doubly linked embedded list code not in the include file.
4  * Author: Phil Cheatle
5  * Created: Wed Jan 23 11:04:47 GMT 1991
6  *
7  * (C) Copyright 1991, Hewlett-Packard Ltd.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include <stdlib.h>
21 #include "host.h"
22 #include "elst2.h"
23 
24 /***********************************************************************
25  * MEMBER FUNCTIONS OF CLASS: ELIST2
26  * =================================
27  **********************************************************************/
28 
29 /***********************************************************************
30  * ELIST2::internal_clear
31  *
32  * Used by the destructor and the "clear" member function of derived list
33  * classes to destroy all the elements on the list.
34  * The calling function passes a "zapper" function which can be called to
35  * delete each element of the list, regardless of its derived type. This
36  * technique permits a generic clear function to destroy elements of
37  * different derived types correctly, without requiring virtual functions and
38  * the consequential memory overhead.
39  **********************************************************************/
40 
41 void
42 ELIST2::internal_clear ( //destroy all links
43 void (*zapper) (ELIST2_LINK *)) {
44  //ptr to zapper functn
45  ELIST2_LINK *ptr;
46  ELIST2_LINK *next;
47 
48  if (!empty ()) {
49  ptr = last->next; //set to first
50  last->next = NULL; //break circle
51  last = NULL; //set list empty
52  while (ptr) {
53  next = ptr->next;
54  zapper(ptr);
55  ptr = next;
56  }
57  }
58 }
59 
60 /***********************************************************************
61  * ELIST2::assign_to_sublist
62  *
63  * The list is set to a sublist of another list. "This" list must be empty
64  * before this function is invoked. The two iterators passed must refer to
65  * the same list, different from "this" one. The sublist removed is the
66  * inclusive list from start_it's current position to end_it's current
67  * position. If this range passes over the end of the source list then the
68  * source list has its end set to the previous element of start_it. The
69  * extracted sublist is unaffected by the end point of the source list, its
70  * end point is always the end_it position.
71  **********************************************************************/
72 
73 void ELIST2::assign_to_sublist( //to this list
74  ELIST2_ITERATOR *start_it, //from list start
75  ELIST2_ITERATOR *end_it) { //from list end
76  const ERRCODE LIST_NOT_EMPTY =
77  "Destination list must be empty before extracting a sublist";
78 
79  if (!empty ())
80  LIST_NOT_EMPTY.error ("ELIST2.assign_to_sublist", ABORT, NULL);
81 
82  last = start_it->extract_sublist (end_it);
83 }
84 
85 /***********************************************************************
86  * ELIST2::length
87  *
88  * Return count of elements on list
89  **********************************************************************/
90 
91 inT32 ELIST2::length() const { // count elements
92  ELIST2_ITERATOR it(const_cast<ELIST2*>(this));
93  inT32 count = 0;
94 
95  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
96  count++;
97  return count;
98 }
99 
100 /***********************************************************************
101  * ELIST2::sort
102  *
103  * Sort elements on list
104  * NB If you don't like the const declarations in the comparator, coerce yours:
105  * ( int (*)(const void *, const void *)
106  **********************************************************************/
107 
108 void
109 ELIST2::sort ( //sort elements
110 int comparator ( //comparison routine
111 const void *, const void *)) {
112  ELIST2_ITERATOR it(this);
113  inT32 count;
114  ELIST2_LINK **base; //ptr array to sort
115  ELIST2_LINK **current;
116  inT32 i;
117 
118  /* Allocate an array of pointers, one per list element */
119  count = length ();
120  base = (ELIST2_LINK **) malloc (count * sizeof (ELIST2_LINK *));
121 
122  /* Extract all elements, putting the pointers in the array */
123  current = base;
124  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
125  *current = it.extract ();
126  current++;
127  }
128 
129  /* Sort the pointer array */
130  qsort ((char *) base, count, sizeof (*base), comparator);
131 
132  /* Rebuild the list from the sorted pointers */
133  current = base;
134  for (i = 0; i < count; i++) {
135  it.add_to_end (*current);
136  current++;
137  }
138  free(base);
139 }
140 
141 // Assuming list has been sorted already, insert new_link to
142 // keep the list sorted according to the same comparison function.
143 // Comparison function is the same as used by sort, i.e. uses double
144 // indirection. Time is O(1) to add to beginning or end.
145 // Time is linear to add pre-sorted items to an empty list.
146 void ELIST2::add_sorted(int comparator(const void*, const void*),
147  ELIST2_LINK* new_link) {
148  // Check for adding at the end.
149  if (last == NULL || comparator(&last, &new_link) < 0) {
150  if (last == NULL) {
151  new_link->next = new_link;
152  new_link->prev = new_link;
153  } else {
154  new_link->next = last->next;
155  new_link->prev = last;
156  last->next = new_link;
157  new_link->next->prev = new_link;
158  }
159  last = new_link;
160  } else {
161  // Need to use an iterator.
162  ELIST2_ITERATOR it(this);
163  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
164  ELIST2_LINK* link = it.data();
165  if (comparator(&link, &new_link) > 0)
166  break;
167  }
168  if (it.cycled_list())
169  it.add_to_end(new_link);
170  else
171  it.add_before_then_move(new_link);
172  }
173 }
174 
175 /***********************************************************************
176  * MEMBER FUNCTIONS OF CLASS: ELIST2_ITERATOR
177  * ==========================================
178  **********************************************************************/
179 
180 /***********************************************************************
181  * ELIST2_ITERATOR::forward
182  *
183  * Move the iterator to the next element of the list.
184  * REMEMBER: ALL LISTS ARE CIRCULAR.
185  **********************************************************************/
186 
188  #ifndef NDEBUG
189  if (!list)
190  NO_LIST.error ("ELIST2_ITERATOR::forward", ABORT, NULL);
191  #endif
192  if (list->empty ())
193  return NULL;
194 
195  if (current) { //not removed so
196  //set previous
197  prev = current;
198  started_cycling = TRUE;
199  // In case next is deleted by another iterator, get it from the current.
200  current = current->next;
201  }
202  else {
203  if (ex_current_was_cycle_pt)
204  cycle_pt = next;
205  current = next;
206  }
207  next = current->next;
208 
209  #ifndef NDEBUG
210  if (!current)
211  NULL_DATA.error ("ELIST2_ITERATOR::forward", ABORT, NULL);
212  if (!next)
213  NULL_NEXT.error ("ELIST2_ITERATOR::forward", ABORT,
214  "This is: %p Current is: %p", this, current);
215  #endif
216  return current;
217 }
218 
219 /***********************************************************************
220  * ELIST2_ITERATOR::backward
221  *
222  * Move the iterator to the previous element of the list.
223  * REMEMBER: ALL LISTS ARE CIRCULAR.
224  **********************************************************************/
225 
227  #ifndef NDEBUG
228  if (!list)
229  NO_LIST.error ("ELIST2_ITERATOR::backward", ABORT, NULL);
230  #endif
231  if (list->empty ())
232  return NULL;
233 
234  if (current) { //not removed so
235  //set previous
236  next = current;
237  started_cycling = TRUE;
238  // In case prev is deleted by another iterator, get it from current.
239  current = current->prev;
240  } else {
241  if (ex_current_was_cycle_pt)
242  cycle_pt = prev;
243  current = prev;
244  }
245  prev = current->prev;
246 
247  #ifndef NDEBUG
248  if (!current)
249  NULL_DATA.error ("ELIST2_ITERATOR::backward", ABORT, NULL);
250  if (!prev)
251  NULL_PREV.error ("ELIST2_ITERATOR::backward", ABORT,
252  "This is: %p Current is: %p", this, current);
253  #endif
254  return current;
255 }
256 
257 /***********************************************************************
258  * ELIST2_ITERATOR::data_relative
259  *
260  * Return the data pointer to the element "offset" elements from current.
261  * (This function can't be INLINEd because it contains a loop)
262  **********************************************************************/
263 
265  inT8 offset) { //offset from current
266  ELIST2_LINK *ptr;
267 
268  #ifndef NDEBUG
269  if (!list)
270  NO_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
271  if (list->empty ())
272  EMPTY_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
273  #endif
274 
275  if (offset < 0)
276  for (ptr = current ? current : next; offset++ < 0; ptr = ptr->prev);
277  else
278  for (ptr = current ? current : prev; offset-- > 0; ptr = ptr->next);
279 
280  #ifndef NDEBUG
281  if (!ptr)
282  NULL_DATA.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
283  #endif
284 
285  return ptr;
286 }
287 
288 /***********************************************************************
289  * ELIST2_ITERATOR::exchange()
290  *
291  * Given another iterator, whose current element is a different element on
292  * the same list list OR an element of another list, exchange the two current
293  * elements. On return, each iterator points to the element which was the
294  * other iterators current on entry.
295  * (This function hasn't been in-lined because its a bit big!)
296  **********************************************************************/
297 
298 void ELIST2_ITERATOR::exchange( //positions of 2 links
299  ELIST2_ITERATOR *other_it) { //other iterator
300  const ERRCODE DONT_EXCHANGE_DELETED =
301  "Can't exchange deleted elements of lists";
302 
303  ELIST2_LINK *old_current;
304 
305  #ifndef NDEBUG
306  if (!list)
307  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, NULL);
308  if (!other_it)
309  BAD_PARAMETER.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it NULL");
310  if (!(other_it->list))
311  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it");
312  #endif
313 
314  /* Do nothing if either list is empty or if both iterators reference the same
315  link */
316 
317  if ((list->empty ()) ||
318  (other_it->list->empty ()) || (current == other_it->current))
319  return;
320 
321  /* Error if either current element is deleted */
322 
323  if (!current || !other_it->current)
324  DONT_EXCHANGE_DELETED.error ("ELIST2_ITERATOR.exchange", ABORT, NULL);
325 
326  /* Now handle the 4 cases: doubleton list; non-doubleton adjacent elements
327  (other before this); non-doubleton adjacent elements (this before other);
328  non-adjacent elements. */
329 
330  //adjacent links
331  if ((next == other_it->current) ||
332  (other_it->next == current)) {
333  //doubleton list
334  if ((next == other_it->current) &&
335  (other_it->next == current)) {
336  prev = next = current;
337  other_it->prev = other_it->next = other_it->current;
338  }
339  else { //non-doubleton with
340  //adjacent links
341  //other before this
342  if (other_it->next == current) {
343  other_it->prev->next = current;
344  other_it->current->next = next;
345  other_it->current->prev = current;
346  current->next = other_it->current;
347  current->prev = other_it->prev;
348  next->prev = other_it->current;
349 
350  other_it->next = other_it->current;
351  prev = current;
352  }
353  else { //this before other
354  prev->next = other_it->current;
355  current->next = other_it->next;
356  current->prev = other_it->current;
357  other_it->current->next = current;
358  other_it->current->prev = prev;
359  other_it->next->prev = current;
360 
361  next = current;
362  other_it->prev = other_it->current;
363  }
364  }
365  }
366  else { //no overlap
367  prev->next = other_it->current;
368  current->next = other_it->next;
369  current->prev = other_it->prev;
370  next->prev = other_it->current;
371  other_it->prev->next = current;
372  other_it->current->next = next;
373  other_it->current->prev = prev;
374  other_it->next->prev = current;
375  }
376 
377  /* update end of list pointer when necessary (remember that the 2 iterators
378  may iterate over different lists!) */
379 
380  if (list->last == current)
381  list->last = other_it->current;
382  if (other_it->list->last == other_it->current)
383  other_it->list->last = current;
384 
385  if (current == cycle_pt)
386  cycle_pt = other_it->cycle_pt;
387  if (other_it->current == other_it->cycle_pt)
388  other_it->cycle_pt = cycle_pt;
389 
390  /* The actual exchange - in all cases*/
391 
392  old_current = current;
393  current = other_it->current;
394  other_it->current = old_current;
395 }
396 
397 /***********************************************************************
398  * ELIST2_ITERATOR::extract_sublist()
399  *
400  * This is a private member, used only by ELIST2::assign_to_sublist.
401  * Given another iterator for the same list, extract the links from THIS to
402  * OTHER inclusive, link them into a new circular list, and return a
403  * pointer to the last element.
404  * (Can't inline this function because it contains a loop)
405  **********************************************************************/
406 
407 ELIST2_LINK *ELIST2_ITERATOR::extract_sublist( //from this current
408  ELIST2_ITERATOR *other_it) { //to other current
409  #ifndef NDEBUG
410  const ERRCODE BAD_EXTRACTION_PTS =
411  "Can't extract sublist from points on different lists";
412  const ERRCODE DONT_EXTRACT_DELETED =
413  "Can't extract a sublist marked by deleted points";
414  #endif
415  const ERRCODE BAD_SUBLIST = "Can't find sublist end point in original list";
416 
417  ELIST2_ITERATOR temp_it = *this;
418  ELIST2_LINK *end_of_new_list;
419 
420  #ifndef NDEBUG
421  if (!other_it)
422  BAD_PARAMETER.error ("ELIST2_ITERATOR::extract_sublist", ABORT,
423  "other_it NULL");
424  if (!list)
425  NO_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, NULL);
426  if (list != other_it->list)
427  BAD_EXTRACTION_PTS.error ("ELIST2_ITERATOR.extract_sublist", ABORT, NULL);
428  if (list->empty ())
429  EMPTY_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, NULL);
430 
431  if (!current || !other_it->current)
432  DONT_EXTRACT_DELETED.error ("ELIST2_ITERATOR.extract_sublist", ABORT,
433  NULL);
434  #endif
435 
436  ex_current_was_last = other_it->ex_current_was_last = FALSE;
437  ex_current_was_cycle_pt = FALSE;
438  other_it->ex_current_was_cycle_pt = FALSE;
439 
440  temp_it.mark_cycle_pt ();
441  do { //walk sublist
442  if (temp_it.cycled_list()) // can't find end pt
443  BAD_SUBLIST.error ("ELIST2_ITERATOR.extract_sublist", ABORT, NULL);
444 
445  if (temp_it.at_last ()) {
446  list->last = prev;
447  ex_current_was_last = other_it->ex_current_was_last = TRUE;
448  }
449 
450  if (temp_it.current == cycle_pt)
451  ex_current_was_cycle_pt = TRUE;
452 
453  if (temp_it.current == other_it->cycle_pt)
454  other_it->ex_current_was_cycle_pt = TRUE;
455 
456  temp_it.forward ();
457  }
458  //do INCLUSIVE list
459  while (temp_it.prev != other_it->current);
460 
461  //circularise sublist
462  other_it->current->next = current;
463  //circularise sublist
464  current->prev = other_it->current;
465  end_of_new_list = other_it->current;
466 
467  //sublist = whole list
468  if (prev == other_it->current) {
469  list->last = NULL;
470  prev = current = next = NULL;
471  other_it->prev = other_it->current = other_it->next = NULL;
472  }
473  else {
474  prev->next = other_it->next;
475  other_it->next->prev = prev;
476 
477  current = other_it->current = NULL;
478  next = other_it->next;
479  other_it->prev = prev;
480  }
481  return end_of_new_list;
482 }
void assign_to_sublist(ELIST2_ITERATOR *start_it, ELIST2_ITERATOR *end_it)
Definition: elst2.cpp:73
ELIST2_LINK * data()
Definition: elst2.h:200
ELIST2_LINK * data_relative(inT8 offset)
Definition: elst2.cpp:264
void sort(int comparator(const void *, const void *))
Definition: elst2.cpp:109
ELIST2_LINK * backward()
Definition: elst2.cpp:226
#define TRUE
Definition: capi.h:45
int32_t inT32
Definition: host.h:38
const ERRCODE NULL_NEXT
Definition: lsterr.h:36
const ERRCODE NULL_DATA
Definition: lsterr.h:34
ELIST2_LINK * extract()
Definition: elst2.h:593
voidpf uLong offset
Definition: ioapi.h:42
bool empty() const
Definition: elst2.h:107
void mark_cycle_pt()
Definition: elst2.h:677
const ERRCODE BAD_PARAMETER
Definition: lsterr.h:39
void add_sorted(int comparator(const void *, const void *), ELIST2_LINK *new_link)
Definition: elst2.cpp:146
#define FALSE
Definition: capi.h:46
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
void add_before_then_move(ELIST2_LINK *new_link)
Definition: elst2.h:399
int8_t inT8
Definition: host.h:34
const ERRCODE EMPTY_LIST
Definition: lsterr.h:38
const ERRCODE NULL_PREV
Definition: lsterr.h:37
void add_to_end(ELIST2_LINK *new_link)
Definition: elst2.h:791
inT32 length() const
Definition: elst2.cpp:91
void exchange(ELIST2_ITERATOR *other_it)
Definition: elst2.cpp:298
BOOL8 at_last()
Definition: elst2.h:716
Definition: errcode.h:30
void internal_clear(void(*zapper)(ELIST2_LINK *))
Definition: elst2.cpp:42
BOOL8 cycled_list()
Definition: elst2.h:735
const ERRCODE NO_LIST
Definition: lsterr.h:32
int count(LIST var_list)
Definition: oldlist.cpp:103
ELIST2_LINK * forward()
Definition: elst2.cpp:187