All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  #ifndef NDEBUG
49  if (!this)
50  NULL_OBJECT.error ("ELIST2::internal_clear", ABORT, NULL);
51  #endif
52 
53  if (!empty ()) {
54  ptr = last->next; //set to first
55  last->next = NULL; //break circle
56  last = NULL; //set list empty
57  while (ptr) {
58  next = ptr->next;
59  zapper(ptr);
60  ptr = next;
61  }
62  }
63 }
64 
65 /***********************************************************************
66  * ELIST2::assign_to_sublist
67  *
68  * The list is set to a sublist of another list. "This" list must be empty
69  * before this function is invoked. The two iterators passed must refer to
70  * the same list, different from "this" one. The sublist removed is the
71  * inclusive list from start_it's current position to end_it's current
72  * position. If this range passes over the end of the source list then the
73  * source list has its end set to the previous element of start_it. The
74  * extracted sublist is unaffected by the end point of the source list, its
75  * end point is always the end_it position.
76  **********************************************************************/
77 
78 void ELIST2::assign_to_sublist( //to this list
79  ELIST2_ITERATOR *start_it, //from list start
80  ELIST2_ITERATOR *end_it) { //from list end
81  const ERRCODE LIST_NOT_EMPTY =
82  "Destination list must be empty before extracting a sublist";
83 
84  #ifndef NDEBUG
85  if (!this)
86  NULL_OBJECT.error ("ELIST2::assign_to_sublist", ABORT, NULL);
87  #endif
88 
89  if (!empty ())
90  LIST_NOT_EMPTY.error ("ELIST2.assign_to_sublist", ABORT, NULL);
91 
92  last = start_it->extract_sublist (end_it);
93 }
94 
95 
96 /***********************************************************************
97  * ELIST2::length
98  *
99  * Return count of elements on list
100  **********************************************************************/
101 
102 inT32 ELIST2::length() const { // count elements
103  ELIST2_ITERATOR it(const_cast<ELIST2*>(this));
104  inT32 count = 0;
105 
106  #ifndef NDEBUG
107  if (!this)
108  NULL_OBJECT.error ("ELIST2::length", ABORT, NULL);
109  #endif
110 
111  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
112  count++;
113  return count;
114 }
115 
116 
117 /***********************************************************************
118  * ELIST2::sort
119  *
120  * Sort elements on list
121  * NB If you dont like the const declarations in the comparator, coerce yours:
122  * ( int (*)(const void *, const void *)
123  **********************************************************************/
124 
125 void
126 ELIST2::sort ( //sort elements
127 int comparator ( //comparison routine
128 const void *, const void *)) {
129  ELIST2_ITERATOR it(this);
130  inT32 count;
131  ELIST2_LINK **base; //ptr array to sort
132  ELIST2_LINK **current;
133  inT32 i;
134 
135  #ifndef NDEBUG
136  if (!this)
137  NULL_OBJECT.error ("ELIST2::sort", ABORT, NULL);
138  #endif
139 
140  /* Allocate an array of pointers, one per list element */
141  count = length ();
142  base = (ELIST2_LINK **) malloc (count * sizeof (ELIST2_LINK *));
143 
144  /* Extract all elements, putting the pointers in the array */
145  current = base;
146  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
147  *current = it.extract ();
148  current++;
149  }
150 
151  /* Sort the pointer array */
152  qsort ((char *) base, count, sizeof (*base), comparator);
153 
154  /* Rebuild the list from the sorted pointers */
155  current = base;
156  for (i = 0; i < count; i++) {
157  it.add_to_end (*current);
158  current++;
159  }
160  free(base);
161 }
162 
163 // Assuming list has been sorted already, insert new_link to
164 // keep the list sorted according to the same comparison function.
165 // Comparision function is the same as used by sort, i.e. uses double
166 // indirection. Time is O(1) to add to beginning or end.
167 // Time is linear to add pre-sorted items to an empty list.
168 void ELIST2::add_sorted(int comparator(const void*, const void*),
169  ELIST2_LINK* new_link) {
170  // Check for adding at the end.
171  if (last == NULL || comparator(&last, &new_link) < 0) {
172  if (last == NULL) {
173  new_link->next = new_link;
174  new_link->prev = new_link;
175  } else {
176  new_link->next = last->next;
177  new_link->prev = last;
178  last->next = new_link;
179  new_link->next->prev = new_link;
180  }
181  last = new_link;
182  } else {
183  // Need to use an iterator.
184  ELIST2_ITERATOR it(this);
185  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
186  ELIST2_LINK* link = it.data();
187  if (comparator(&link, &new_link) > 0)
188  break;
189  }
190  if (it.cycled_list())
191  it.add_to_end(new_link);
192  else
193  it.add_before_then_move(new_link);
194  }
195 }
196 
197 /***********************************************************************
198  * MEMBER FUNCTIONS OF CLASS: ELIST2_ITERATOR
199  * ==========================================
200  **********************************************************************/
201 
202 /***********************************************************************
203  * ELIST2_ITERATOR::forward
204  *
205  * Move the iterator to the next element of the list.
206  * REMEMBER: ALL LISTS ARE CIRCULAR.
207  **********************************************************************/
208 
210  #ifndef NDEBUG
211  if (!this)
212  NULL_OBJECT.error ("ELIST2_ITERATOR::forward", ABORT, NULL);
213  if (!list)
214  NO_LIST.error ("ELIST2_ITERATOR::forward", ABORT, NULL);
215  #endif
216  if (list->empty ())
217  return NULL;
218 
219  if (current) { //not removed so
220  //set previous
221  prev = current;
222  started_cycling = TRUE;
223  // In case next is deleted by another iterator, get it from the current.
224  current = current->next;
225  }
226  else {
227  if (ex_current_was_cycle_pt)
228  cycle_pt = next;
229  current = next;
230  }
231  next = current->next;
232 
233  #ifndef NDEBUG
234  if (!current)
235  NULL_DATA.error ("ELIST2_ITERATOR::forward", ABORT, NULL);
236  if (!next)
237  NULL_NEXT.error ("ELIST2_ITERATOR::forward", ABORT,
238  "This is: %p Current is: %p", this, current);
239  #endif
240  return current;
241 }
242 
243 
244 /***********************************************************************
245  * ELIST2_ITERATOR::backward
246  *
247  * Move the iterator to the previous element of the list.
248  * REMEMBER: ALL LISTS ARE CIRCULAR.
249  **********************************************************************/
250 
252  #ifndef NDEBUG
253  if (!this)
254  NULL_OBJECT.error ("ELIST2_ITERATOR::backward", ABORT, NULL);
255  if (!list)
256  NO_LIST.error ("ELIST2_ITERATOR::backward", ABORT, NULL);
257  #endif
258  if (list->empty ())
259  return NULL;
260 
261  if (current) { //not removed so
262  //set previous
263  next = current;
264  started_cycling = TRUE;
265  // In case prev is deleted by another iterator, get it from current.
266  current = current->prev;
267  } else {
268  if (ex_current_was_cycle_pt)
269  cycle_pt = prev;
270  current = prev;
271  }
272  prev = current->prev;
273 
274  #ifndef NDEBUG
275  if (!current)
276  NULL_DATA.error ("ELIST2_ITERATOR::backward", ABORT, NULL);
277  if (!prev)
278  NULL_PREV.error ("ELIST2_ITERATOR::backward", ABORT,
279  "This is: %p Current is: %p", this, current);
280  #endif
281  return current;
282 }
283 
284 
285 /***********************************************************************
286  * ELIST2_ITERATOR::data_relative
287  *
288  * Return the data pointer to the element "offset" elements from current.
289  * (This function can't be INLINEd because it contains a loop)
290  **********************************************************************/
291 
293  inT8 offset) { //offset from current
294  ELIST2_LINK *ptr;
295 
296  #ifndef NDEBUG
297  if (!this)
298  NULL_OBJECT.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
299  if (!list)
300  NO_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
301  if (list->empty ())
302  EMPTY_LIST.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
303  #endif
304 
305  if (offset < 0)
306  for (ptr = current ? current : next; offset++ < 0; ptr = ptr->prev);
307  else
308  for (ptr = current ? current : prev; offset-- > 0; ptr = ptr->next);
309 
310  #ifndef NDEBUG
311  if (!ptr)
312  NULL_DATA.error ("ELIST2_ITERATOR::data_relative", ABORT, NULL);
313  #endif
314 
315  return ptr;
316 }
317 
318 
319 /***********************************************************************
320  * ELIST2_ITERATOR::exchange()
321  *
322  * Given another iterator, whose current element is a different element on
323  * the same list list OR an element of another list, exchange the two current
324  * elements. On return, each iterator points to the element which was the
325  * other iterators current on entry.
326  * (This function hasn't been in-lined because its a bit big!)
327  **********************************************************************/
328 
329 void ELIST2_ITERATOR::exchange( //positions of 2 links
330  ELIST2_ITERATOR *other_it) { //other iterator
331  const ERRCODE DONT_EXCHANGE_DELETED =
332  "Can't exchange deleted elements of lists";
333 
334  ELIST2_LINK *old_current;
335 
336  #ifndef NDEBUG
337  if (!this)
338  NULL_OBJECT.error ("ELIST2_ITERATOR::exchange", ABORT, NULL);
339  if (!list)
340  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, NULL);
341  if (!other_it)
342  BAD_PARAMETER.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it NULL");
343  if (!(other_it->list))
344  NO_LIST.error ("ELIST2_ITERATOR::exchange", ABORT, "other_it");
345  #endif
346 
347  /* Do nothing if either list is empty or if both iterators reference the same
348  link */
349 
350  if ((list->empty ()) ||
351  (other_it->list->empty ()) || (current == other_it->current))
352  return;
353 
354  /* Error if either current element is deleted */
355 
356  if (!current || !other_it->current)
357  DONT_EXCHANGE_DELETED.error ("ELIST2_ITERATOR.exchange", ABORT, NULL);
358 
359  /* Now handle the 4 cases: doubleton list; non-doubleton adjacent elements
360  (other before this); non-doubleton adjacent elements (this before other);
361  non-adjacent elements. */
362 
363  //adjacent links
364  if ((next == other_it->current) ||
365  (other_it->next == current)) {
366  //doubleton list
367  if ((next == other_it->current) &&
368  (other_it->next == current)) {
369  prev = next = current;
370  other_it->prev = other_it->next = other_it->current;
371  }
372  else { //non-doubleton with
373  //adjacent links
374  //other before this
375  if (other_it->next == current) {
376  other_it->prev->next = current;
377  other_it->current->next = next;
378  other_it->current->prev = current;
379  current->next = other_it->current;
380  current->prev = other_it->prev;
381  next->prev = other_it->current;
382 
383  other_it->next = other_it->current;
384  prev = current;
385  }
386  else { //this before other
387  prev->next = other_it->current;
388  current->next = other_it->next;
389  current->prev = other_it->current;
390  other_it->current->next = current;
391  other_it->current->prev = prev;
392  other_it->next->prev = current;
393 
394  next = current;
395  other_it->prev = other_it->current;
396  }
397  }
398  }
399  else { //no overlap
400  prev->next = other_it->current;
401  current->next = other_it->next;
402  current->prev = other_it->prev;
403  next->prev = other_it->current;
404  other_it->prev->next = current;
405  other_it->current->next = next;
406  other_it->current->prev = prev;
407  other_it->next->prev = current;
408  }
409 
410  /* update end of list pointer when necessary (remember that the 2 iterators
411  may iterate over different lists!) */
412 
413  if (list->last == current)
414  list->last = other_it->current;
415  if (other_it->list->last == other_it->current)
416  other_it->list->last = current;
417 
418  if (current == cycle_pt)
419  cycle_pt = other_it->cycle_pt;
420  if (other_it->current == other_it->cycle_pt)
421  other_it->cycle_pt = cycle_pt;
422 
423  /* The actual exchange - in all cases*/
424 
425  old_current = current;
426  current = other_it->current;
427  other_it->current = old_current;
428 }
429 
430 
431 /***********************************************************************
432  * ELIST2_ITERATOR::extract_sublist()
433  *
434  * This is a private member, used only by ELIST2::assign_to_sublist.
435  * Given another iterator for the same list, extract the links from THIS to
436  * OTHER inclusive, link them into a new circular list, and return a
437  * pointer to the last element.
438  * (Can't inline this function because it contains a loop)
439  **********************************************************************/
440 
441 ELIST2_LINK *ELIST2_ITERATOR::extract_sublist( //from this current
442  ELIST2_ITERATOR *other_it) { //to other current
443  #ifndef NDEBUG
444  const ERRCODE BAD_EXTRACTION_PTS =
445  "Can't extract sublist from points on different lists";
446  const ERRCODE DONT_EXTRACT_DELETED =
447  "Can't extract a sublist marked by deleted points";
448  #endif
449  const ERRCODE BAD_SUBLIST = "Can't find sublist end point in original list";
450 
451  ELIST2_ITERATOR temp_it = *this;
452  ELIST2_LINK *end_of_new_list;
453 
454  #ifndef NDEBUG
455  if (!this)
456  NULL_OBJECT.error ("ELIST2_ITERATOR::extract_sublist", ABORT, NULL);
457  if (!other_it)
458  BAD_PARAMETER.error ("ELIST2_ITERATOR::extract_sublist", ABORT,
459  "other_it NULL");
460  if (!list)
461  NO_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, NULL);
462  if (list != other_it->list)
463  BAD_EXTRACTION_PTS.error ("ELIST2_ITERATOR.extract_sublist", ABORT, NULL);
464  if (list->empty ())
465  EMPTY_LIST.error ("ELIST2_ITERATOR::extract_sublist", ABORT, NULL);
466 
467  if (!current || !other_it->current)
468  DONT_EXTRACT_DELETED.error ("ELIST2_ITERATOR.extract_sublist", ABORT,
469  NULL);
470  #endif
471 
472  ex_current_was_last = other_it->ex_current_was_last = FALSE;
473  ex_current_was_cycle_pt = FALSE;
474  other_it->ex_current_was_cycle_pt = FALSE;
475 
476  temp_it.mark_cycle_pt ();
477  do { //walk sublist
478  if (temp_it.cycled_list ()) //cant find end pt
479  BAD_SUBLIST.error ("ELIST2_ITERATOR.extract_sublist", ABORT, NULL);
480 
481  if (temp_it.at_last ()) {
482  list->last = prev;
483  ex_current_was_last = other_it->ex_current_was_last = TRUE;
484  }
485 
486  if (temp_it.current == cycle_pt)
487  ex_current_was_cycle_pt = TRUE;
488 
489  if (temp_it.current == other_it->cycle_pt)
490  other_it->ex_current_was_cycle_pt = TRUE;
491 
492  temp_it.forward ();
493  }
494  //do INCLUSIVE list
495  while (temp_it.prev != other_it->current);
496 
497  //circularise sublist
498  other_it->current->next = current;
499  //circularise sublist
500  current->prev = other_it->current;
501  end_of_new_list = other_it->current;
502 
503  //sublist = whole list
504  if (prev == other_it->current) {
505  list->last = NULL;
506  prev = current = next = NULL;
507  other_it->prev = other_it->current = other_it->next = NULL;
508  }
509  else {
510  prev->next = other_it->next;
511  other_it->next->prev = prev;
512 
513  current = other_it->current = NULL;
514  next = other_it->next;
515  other_it->prev = prev;
516  }
517  return end_of_new_list;
518 }
void internal_clear(void(*zapper)(ELIST2_LINK *))
Definition: elst2.cpp:42
ELIST2_LINK * extract()
Definition: elst2.h:613
bool empty() const
Definition: elst2.h:107
void add_sorted(int comparator(const void *, const void *), ELIST2_LINK *new_link)
Definition: elst2.cpp:168
void mark_cycle_pt()
Definition: elst2.h:706
void sort(int comparator(const void *, const void *))
Definition: elst2.cpp:126
Definition: errcode.h:30
void add_before_then_move(ELIST2_LINK *new_link)
Definition: elst2.h:408
ELIST2_LINK * backward()
Definition: elst2.cpp:251
const ERRCODE BAD_PARAMETER
Definition: lsterr.h:39
void assign_to_sublist(ELIST2_ITERATOR *start_it, ELIST2_ITERATOR *end_it)
Definition: elst2.cpp:78
const ERRCODE NO_LIST
Definition: lsterr.h:32
const ERRCODE NULL_NEXT
Definition: lsterr.h:36
ELIST2_LINK * forward()
Definition: elst2.cpp:209
BOOL8 at_last()
Definition: elst2.h:751
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
const ERRCODE NULL_PREV
Definition: lsterr.h:37
ELIST2_LINK * data()
Definition: elst2.h:199
const ERRCODE NULL_DATA
Definition: lsterr.h:34
#define FALSE
Definition: capi.h:29
int count(LIST var_list)
Definition: oldlist.cpp:108
const ERRCODE EMPTY_LIST
Definition: lsterr.h:38
inT32 length() const
Definition: elst2.cpp:102
#define TRUE
Definition: capi.h:28
BOOL8 cycled_list()
Definition: elst2.h:773
void exchange(ELIST2_ITERATOR *other_it)
Definition: elst2.cpp:329
#define NULL
Definition: host.h:144
SIGNED char inT8
Definition: host.h:98
const ERRCODE NULL_OBJECT
Definition: lsterr.h:33
ELIST2_LINK * data_relative(inT8 offset)
Definition: elst2.cpp:292
void add_to_end(ELIST2_LINK *new_link)
Definition: elst2.h:838
int inT32
Definition: host.h:102