tesseract  4.0.0-1-g2a2b
elst2.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: elst2.cpp (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 <cstdlib>
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 = nullptr; //break circle
51  last = nullptr; //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, nullptr);
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_t ELIST2::length() const { // count elements
92  ELIST2_ITERATOR it(const_cast<ELIST2*>(this));
93  int32_t 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_t count;
114  ELIST2_LINK **base; //ptr array to sort
115  ELIST2_LINK **current;
116  int32_t 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(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 == nullptr || comparator(&last, &new_link) < 0) {
150  if (last == nullptr) {
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, nullptr);
191  #endif
192  if (list->empty ())
193  return nullptr;
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 
208 #ifndef NDEBUG
209  if (!current)
210  NULL_DATA.error ("ELIST2_ITERATOR::forward", ABORT, nullptr);
211 #endif
212 
213  next = current->next;
214 
215 #ifndef NDEBUG
216  if (!next)
217  NULL_NEXT.error ("ELIST2_ITERATOR::forward", ABORT,
218  "This is: %p Current is: %p", this, current);
219 #endif
220 
221  return current;
222 }
223 
224 /***********************************************************************
225  * ELIST2_ITERATOR::backward
226  *
227  * Move the iterator to the previous element of the list.
228  * REMEMBER: ALL LISTS ARE CIRCULAR.
229  **********************************************************************/
230 
232  #ifndef NDEBUG
233  if (!list)
234  NO_LIST.error ("ELIST2_ITERATOR::backward", ABORT, nullptr);
235  #endif
236  if (list->empty ())
237  return nullptr;
238 
239  if (current) { //not removed so
240  //set previous
241  next = current;
242  started_cycling = TRUE;
243  // In case prev is deleted by another iterator, get it from current.
244  current = current->prev;
245  } else {
246  if (ex_current_was_cycle_pt)
247  cycle_pt = prev;
248  current = prev;
249  }
250 
251  #ifndef NDEBUG
252  if (!current)
253  NULL_DATA.error ("ELIST2_ITERATOR::backward", ABORT, nullptr);
254  if (!prev)
255  NULL_PREV.error ("ELIST2_ITERATOR::backward", ABORT,
256  "This is: %p Current is: %p", this, current);
257  #endif
258 
259  prev = current->prev;
260  return current;
261 }
262 
263 /***********************************************************************
264  * ELIST2_ITERATOR::data_relative
265  *
266  * Return the data pointer to the element "offset" elements from current.
267  * (This function can't be INLINEd because it contains a loop)
268  **********************************************************************/
269 
271  int8_t offset) { //offset from current
272  ELIST2_LINK *ptr;
273 
274  #ifndef NDEBUG
275  if (!list)
276  NO_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, nullptr);
277  if (list->empty ())
278  EMPTY_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, nullptr);
279  #endif
280 
281  if (offset < 0)
282  for (ptr = current ? current : next; offset++ < 0; ptr = ptr->prev);
283  else
284  for (ptr = current ? current : prev; offset-- > 0; ptr = ptr->next);
285 
286  #ifndef NDEBUG
287  if (!ptr)
288  NULL_DATA.error ("ELIST2_ITERATOR::data_relative", ABORT, nullptr);
289  #endif
290 
291  return ptr;
292 }
293 
294 /***********************************************************************
295  * ELIST2_ITERATOR::exchange()
296  *
297  * Given another iterator, whose current element is a different element on
298  * the same list list OR an element of another list, exchange the two current
299  * elements. On return, each iterator points to the element which was the
300  * other iterators current on entry.
301  * (This function hasn't been in-lined because its a bit big!)
302  **********************************************************************/
303 
304 void ELIST2_ITERATOR::exchange( //positions of 2 links
305  ELIST2_ITERATOR *other_it) { //other iterator
306  const ERRCODE DONT_EXCHANGE_DELETED =
307  "Can't exchange deleted elements of lists";
308 
309  ELIST2_LINK *old_current;
310 
311  #ifndef NDEBUG
312  if (!list)
313  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, nullptr);
314  if (!other_it)
315  BAD_PARAMETER.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it nullptr");
316  if (!(other_it->list))
317  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it");
318  #endif
319 
320  /* Do nothing if either list is empty or if both iterators reference the same
321  link */
322 
323  if ((list->empty ()) ||
324  (other_it->list->empty ()) || (current == other_it->current))
325  return;
326 
327  /* Error if either current element is deleted */
328 
329  if (!current || !other_it->current)
330  DONT_EXCHANGE_DELETED.error ("ELIST2_ITERATOR.exchange", ABORT, nullptr);
331 
332  /* Now handle the 4 cases: doubleton list; non-doubleton adjacent elements
333  (other before this); non-doubleton adjacent elements (this before other);
334  non-adjacent elements. */
335 
336  //adjacent links
337  if ((next == other_it->current) ||
338  (other_it->next == current)) {
339  //doubleton list
340  if ((next == other_it->current) &&
341  (other_it->next == current)) {
342  prev = next = current;
343  other_it->prev = other_it->next = other_it->current;
344  }
345  else { //non-doubleton with
346  //adjacent links
347  //other before this
348  if (other_it->next == current) {
349  other_it->prev->next = current;
350  other_it->current->next = next;
351  other_it->current->prev = current;
352  current->next = other_it->current;
353  current->prev = other_it->prev;
354  next->prev = other_it->current;
355 
356  other_it->next = other_it->current;
357  prev = current;
358  }
359  else { //this before other
360  prev->next = other_it->current;
361  current->next = other_it->next;
362  current->prev = other_it->current;
363  other_it->current->next = current;
364  other_it->current->prev = prev;
365  other_it->next->prev = current;
366 
367  next = current;
368  other_it->prev = other_it->current;
369  }
370  }
371  }
372  else { //no overlap
373  prev->next = other_it->current;
374  current->next = other_it->next;
375  current->prev = other_it->prev;
376  next->prev = other_it->current;
377  other_it->prev->next = current;
378  other_it->current->next = next;
379  other_it->current->prev = prev;
380  other_it->next->prev = current;
381  }
382 
383  /* update end of list pointer when necessary (remember that the 2 iterators
384  may iterate over different lists!) */
385 
386  if (list->last == current)
387  list->last = other_it->current;
388  if (other_it->list->last == other_it->current)
389  other_it->list->last = current;
390 
391  if (current == cycle_pt)
392  cycle_pt = other_it->cycle_pt;
393  if (other_it->current == other_it->cycle_pt)
394  other_it->cycle_pt = cycle_pt;
395 
396  /* The actual exchange - in all cases*/
397 
398  old_current = current;
399  current = other_it->current;
400  other_it->current = old_current;
401 }
402 
403 /***********************************************************************
404  * ELIST2_ITERATOR::extract_sublist()
405  *
406  * This is a private member, used only by ELIST2::assign_to_sublist.
407  * Given another iterator for the same list, extract the links from THIS to
408  * OTHER inclusive, link them into a new circular list, and return a
409  * pointer to the last element.
410  * (Can't inline this function because it contains a loop)
411  **********************************************************************/
412 
413 ELIST2_LINK *ELIST2_ITERATOR::extract_sublist( //from this current
414  ELIST2_ITERATOR *other_it) { //to other current
415  #ifndef NDEBUG
416  const ERRCODE BAD_EXTRACTION_PTS =
417  "Can't extract sublist from points on different lists";
418  const ERRCODE DONT_EXTRACT_DELETED =
419  "Can't extract a sublist marked by deleted points";
420  #endif
421  const ERRCODE BAD_SUBLIST = "Can't find sublist end point in original list";
422 
423  ELIST2_ITERATOR temp_it = *this;
424  ELIST2_LINK *end_of_new_list;
425 
426  #ifndef NDEBUG
427  if (!other_it)
428  BAD_PARAMETER.error ("ELIST2_ITERATOR::extract_sublist", ABORT,
429  "other_it nullptr");
430  if (!list)
431  NO_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, nullptr);
432  if (list != other_it->list)
433  BAD_EXTRACTION_PTS.error ("ELIST2_ITERATOR.extract_sublist", ABORT, nullptr);
434  if (list->empty ())
435  EMPTY_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, nullptr);
436 
437  if (!current || !other_it->current)
438  DONT_EXTRACT_DELETED.error ("ELIST2_ITERATOR.extract_sublist", ABORT,
439  nullptr);
440  #endif
441 
442  ex_current_was_last = other_it->ex_current_was_last = false;
443  ex_current_was_cycle_pt = false;
444  other_it->ex_current_was_cycle_pt = false;
445 
446  temp_it.mark_cycle_pt ();
447  do { //walk sublist
448  if (temp_it.cycled_list()) // can't find end pt
449  BAD_SUBLIST.error ("ELIST2_ITERATOR.extract_sublist", ABORT, nullptr);
450 
451  if (temp_it.at_last ()) {
452  list->last = prev;
453  ex_current_was_last = other_it->ex_current_was_last = true;
454  }
455 
456  if (temp_it.current == cycle_pt)
457  ex_current_was_cycle_pt = true;
458 
459  if (temp_it.current == other_it->cycle_pt)
460  other_it->ex_current_was_cycle_pt = true;
461 
462  temp_it.forward ();
463  }
464  //do INCLUSIVE list
465  while (temp_it.prev != other_it->current);
466 
467  //circularise sublist
468  other_it->current->next = current;
469  //circularise sublist
470  current->prev = other_it->current;
471  end_of_new_list = other_it->current;
472 
473  //sublist = whole list
474  if (prev == other_it->current) {
475  list->last = nullptr;
476  prev = current = next = nullptr;
477  other_it->prev = other_it->current = other_it->next = nullptr;
478  }
479  else {
480  prev->next = other_it->next;
481  other_it->next->prev = prev;
482 
483  current = other_it->current = nullptr;
484  next = other_it->next;
485  other_it->prev = prev;
486  }
487  return end_of_new_list;
488 }
void internal_clear(void(*zapper)(ELIST2_LINK *))
Definition: elst2.cpp:42
ELIST2_LINK * extract()
Definition: elst2.h:592
#define TRUE
Definition: capi.h:51
bool at_last()
Definition: elst2.h:715
int count(LIST var_list)
Definition: oldlist.cpp:98
int32_t length() const
Definition: elst2.cpp:91
void exchange(ELIST2_ITERATOR *other_it)
Definition: elst2.cpp:304
const ERRCODE NULL_PREV
Definition: lsterr.h:37
ELIST2_LINK * backward()
Definition: elst2.cpp:231
void assign_to_sublist(ELIST2_ITERATOR *start_it, ELIST2_ITERATOR *end_it)
Definition: elst2.cpp:73
bool empty() const
Definition: elst2.h:107
const ERRCODE NO_LIST
Definition: lsterr.h:32
Definition: errcode.h:30
const ERRCODE NULL_NEXT
Definition: lsterr.h:36
const ERRCODE NULL_DATA
Definition: lsterr.h:34
void mark_cycle_pt()
Definition: elst2.h:676
ELIST2_LINK * data_relative(int8_t offset)
Definition: elst2.cpp:270
ELIST2_LINK * forward()
Definition: elst2.cpp:187
void add_before_then_move(ELIST2_LINK *new_link)
Definition: elst2.h:398
const ERRCODE EMPTY_LIST
Definition: lsterr.h:38
const ERRCODE BAD_PARAMETER
Definition: lsterr.h:39
bool cycled_list()
Definition: elst2.h:734
void add_sorted(int comparator(const void *, const void *), ELIST2_LINK *new_link)
Definition: elst2.cpp:146
ELIST2_LINK * data()
Definition: elst2.h:196
void sort(int comparator(const void *, const void *))
Definition: elst2.cpp:109
void add_to_end(ELIST2_LINK *new_link)
Definition: elst2.h:790
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:37