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