All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
elst.h
Go to the documentation of this file.
1 /**********************************************************************
2  * File: elst.h (Formerly elist.h)
3  * Description: Embedded list module include file.
4  * Author: Phil Cheatle
5  * Created: Mon Jan 07 08:35:34 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 #ifndef ELST_H
21 #define ELST_H
22 
23 #include <stdio.h>
24 #include "host.h"
25 #include "serialis.h"
26 #include "lsterr.h"
27 
28 class ELIST_ITERATOR;
29 
30 /**********************************************************************
31 This module implements list classes and iterators.
32 The following list types and iterators are provided:
33 
34  List type List Class Iterator Class Element Class
35  --------- ---------- -------------- -------------
36 
37  Embedded list ELIST
38  ELIST_ITERATOR
39  ELIST_LINK
40  (Single linked)
41 
42  Embedded list ELIST2
43  ELIST2_ITERATOR
44  ELIST2_LINK
45  (Double linked)
46 
47  Cons List CLIST
48  CLIST_ITERATOR
49  CLIST_LINK
50  (Single linked)
51 
52  Cons List CLIST2
53  CLIST2_ITERATOR
54  CLIST2_LINK
55  (Double linked)
56 
57 An embedded list is where the list pointers are provided by a generic class.
58 Data types to be listed inherit from the generic class. Data is thus linked
59 in only ONE list at any one time.
60 
61 A cons list has a separate structure for a "cons cell". This contains the
62 list pointer(s) AND a pointer to the data structure held on the list. A
63 structure can be on many cons lists at the same time, and the structure does
64 not need to inherit from any generic class in order to be on the list.
65 
66 The implementation of lists is very careful about space and speed overheads.
67 This is why many embedded lists are provided. The same concerns mean that
68 in-line type coercion is done, rather than use virtual functions. This is
69 cumbersome in that each data type to be listed requires its own iterator and
70 list class - though macros can gererate these. It also prevents heterogenous
71 lists.
72 **********************************************************************/
73 
74 /**********************************************************************
75  * CLASS - ELIST_LINK
76  *
77  * Generic link class for singly linked lists with embedded links
78  *
79  * Note: No destructor - elements are assumed to be destroyed EITHER after
80  * they have been extracted from a list OR by the ELIST destructor which
81  * walks the list.
82  **********************************************************************/
83 
85 {
86  friend class ELIST_ITERATOR;
87  friend class ELIST;
88 
89  ELIST_LINK *next;
90 
91  public:
93  next = NULL;
94  }
95  //constructor
96 
97  ELIST_LINK(const ELIST_LINK &) { // don't copy link.
98  next = NULL;
99  }
100 
101  void operator= ( //dont copy links
102  const ELIST_LINK &) {
103  next = NULL;
104  }
105 };
106 
107 /**********************************************************************
108  * CLASS - ELIST
109  *
110  * Generic list class for singly linked lists with embedded links
111  **********************************************************************/
112 
114 {
115  friend class ELIST_ITERATOR;
116 
117  ELIST_LINK *last; //End of list
118  //(Points to head)
119  ELIST_LINK *First() { // return first
120  return last ? last->next : NULL;
121  }
122 
123  public:
124  ELIST() { //constructor
125  last = NULL;
126  }
127 
128  void internal_clear ( //destroy all links
129  //ptr to zapper functn
130  void (*zapper) (ELIST_LINK *));
131 
132  bool empty() const { //is list empty?
133  return !last;
134  }
135 
136  bool singleton() const {
137  return last ? (last == last->next) : false;
138  }
139 
140  void shallow_copy( //dangerous!!
141  ELIST *from_list) { //beware destructors!!
142  last = from_list->last;
143  }
144 
145  //ptr to copier functn
146  void internal_deep_copy (ELIST_LINK * (*copier) (ELIST_LINK *),
147  const ELIST * list); //list being copied
148 
149  void assign_to_sublist( //to this list
150  ELIST_ITERATOR *start_it, //from list start
151  ELIST_ITERATOR *end_it); //from list end
152 
153  inT32 length() const; // # elements in list
154 
155  void sort ( //sort elements
156  int comparator ( //comparison routine
157  const void *, const void *));
158 
159  // Assuming list has been sorted already, insert new_link to
160  // keep the list sorted according to the same comparison function.
161  // Comparision function is the same as used by sort, i.e. uses double
162  // indirection. Time is O(1) to add to beginning or end.
163  // Time is linear to add pre-sorted items to an empty list.
164  // If unique is set to true and comparator() returns 0 (an entry with the
165  // same information as the one contained in new_link is already in the
166  // list) - new_link is not added to the list and the function returns the
167  // pointer to the identical entry that already exists in the list
168  // (otherwise the function returns new_link).
169  ELIST_LINK *add_sorted_and_find(int comparator(const void*, const void*),
170  bool unique, ELIST_LINK* new_link);
171 
172  // Same as above, but returns true if the new entry was inserted, false
173  // if the identical entry already existed in the list.
174  bool add_sorted(int comparator(const void*, const void*),
175  bool unique, ELIST_LINK* new_link) {
176  return (add_sorted_and_find(comparator, unique, new_link) == new_link);
177  }
178 
179 };
180 
181 /***********************************************************************
182  * CLASS - ELIST_ITERATOR
183  *
184  * Generic iterator class for singly linked lists with embedded links
185  **********************************************************************/
186 
188 {
190 
191  ELIST *list; //List being iterated
192  ELIST_LINK *prev; //prev element
193  ELIST_LINK *current; //current element
194  ELIST_LINK *next; //next element
195  bool ex_current_was_last; //current extracted
196  //was end of list
197  bool ex_current_was_cycle_pt; //current extracted
198  //was cycle point
199  ELIST_LINK *cycle_pt; //point we are cycling
200  //the list to.
201  bool started_cycling; //Have we moved off
202  //the start?
203 
204  ELIST_LINK *extract_sublist( //from this current...
205  ELIST_ITERATOR *other_it); //to other current
206 
207  public:
208  ELIST_ITERATOR() { //constructor
209  list = NULL;
210  } //unassigned list
211 
212  explicit ELIST_ITERATOR(ELIST *list_to_iterate);
213 
214  void set_to_list( //change list
215  ELIST *list_to_iterate);
216 
217  void add_after_then_move( //add after current &
218  ELIST_LINK *new_link); //move to new
219 
220  void add_after_stay_put( //add after current &
221  ELIST_LINK *new_link); //stay at current
222 
223  void add_before_then_move( //add before current &
224  ELIST_LINK *new_link); //move to new
225 
226  void add_before_stay_put( //add before current &
227  ELIST_LINK *new_link); //stay at current
228 
229  void add_list_after( //add a list &
230  ELIST *list_to_add); //stay at current
231 
232  void add_list_before( //add a list &
233  ELIST *list_to_add); //move to it 1st item
234 
235  ELIST_LINK *data() { //get current data
236  #ifndef NDEBUG
237  if (!list)
238  NO_LIST.error ("ELIST_ITERATOR::data", ABORT, NULL);
239  if (!current)
240  NULL_DATA.error ("ELIST_ITERATOR::data", ABORT, NULL);
241  #endif
242  return current;
243  }
244 
245  ELIST_LINK *data_relative( //get data + or - ...
246  inT8 offset); //offset from current
247 
248  ELIST_LINK *forward(); //move to next element
249 
250  ELIST_LINK *extract(); //remove from list
251 
252  ELIST_LINK *move_to_first(); //go to start of list
253 
254  ELIST_LINK *move_to_last(); //go to end of list
255 
256  void mark_cycle_pt(); //remember current
257 
258  bool empty() { //is list empty?
259  #ifndef NDEBUG
260  if (!list)
261  NO_LIST.error ("ELIST_ITERATOR::empty", ABORT, NULL);
262  #endif
263  return list->empty ();
264  }
265 
266  bool current_extracted() { //current extracted?
267  return !current;
268  }
269 
270  bool at_first(); //Current is first?
271 
272  bool at_last(); //Current is last?
273 
274  bool cycled_list(); //Completed a cycle?
275 
276  void add_to_end( //add at end &
277  ELIST_LINK *new_link); //dont move
278 
279  void exchange( //positions of 2 links
280  ELIST_ITERATOR *other_it); //other iterator
281 
282  inT32 length(); //# elements in list
283 
284  void sort ( //sort elements
285  int comparator ( //comparison routine
286  const void *, const void *));
287 
288 };
289 
290 /***********************************************************************
291  * ELIST_ITERATOR::set_to_list
292  *
293  * (Re-)initialise the iterator to point to the start of the list_to_iterate
294  * over.
295  **********************************************************************/
296 
297 inline void ELIST_ITERATOR::set_to_list( //change list
298  ELIST *list_to_iterate) {
299  #ifndef NDEBUG
300  if (!this)
301  NULL_OBJECT.error ("ELIST_ITERATOR::set_to_list", ABORT, NULL);
302  if (!list_to_iterate)
303  BAD_PARAMETER.error ("ELIST_ITERATOR::set_to_list", ABORT,
304  "list_to_iterate is NULL");
305  #endif
306 
307  list = list_to_iterate;
308  prev = list->last;
309  current = list->First ();
310  next = current ? current->next : NULL;
311  cycle_pt = NULL; //await explicit set
312  started_cycling = FALSE;
313  ex_current_was_last = FALSE;
314  ex_current_was_cycle_pt = FALSE;
315 }
316 
317 
318 /***********************************************************************
319  * ELIST_ITERATOR::ELIST_ITERATOR
320  *
321  * CONSTRUCTOR - set iterator to specified list;
322  **********************************************************************/
323 
324 inline ELIST_ITERATOR::ELIST_ITERATOR(ELIST *list_to_iterate) {
325  set_to_list(list_to_iterate);
326 }
327 
328 
329 /***********************************************************************
330  * ELIST_ITERATOR::add_after_then_move
331  *
332  * Add a new element to the list after the current element and move the
333  * iterator to the new element.
334  **********************************************************************/
335 
336 inline void ELIST_ITERATOR::add_after_then_move( // element to add
337  ELIST_LINK *new_element) {
338  #ifndef NDEBUG
339  if (!this)
340  NULL_OBJECT.error ("ELIST_ITERATOR::add_after_then_move", ABORT, NULL);
341  if (!list)
342  NO_LIST.error ("ELIST_ITERATOR::add_after_then_move", ABORT, NULL);
343  if (!new_element)
344  BAD_PARAMETER.error ("ELIST_ITERATOR::add_after_then_move", ABORT,
345  "new_element is NULL");
346  if (new_element->next)
347  STILL_LINKED.error ("ELIST_ITERATOR::add_after_then_move", ABORT, NULL);
348  #endif
349 
350  if (list->empty ()) {
351  new_element->next = new_element;
352  list->last = new_element;
353  prev = next = new_element;
354  }
355  else {
356  new_element->next = next;
357 
358  if (current) { //not extracted
359  current->next = new_element;
360  prev = current;
361  if (current == list->last)
362  list->last = new_element;
363  }
364  else { //current extracted
365  prev->next = new_element;
366  if (ex_current_was_last)
367  list->last = new_element;
368  if (ex_current_was_cycle_pt)
369  cycle_pt = new_element;
370  }
371  }
372  current = new_element;
373 }
374 
375 
376 /***********************************************************************
377  * ELIST_ITERATOR::add_after_stay_put
378  *
379  * Add a new element to the list after the current element but do not move
380  * the iterator to the new element.
381  **********************************************************************/
382 
383 inline void ELIST_ITERATOR::add_after_stay_put( // element to add
384  ELIST_LINK *new_element) {
385  #ifndef NDEBUG
386  if (!this)
387  NULL_OBJECT.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, NULL);
388  if (!list)
389  NO_LIST.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, NULL);
390  if (!new_element)
391  BAD_PARAMETER.error ("ELIST_ITERATOR::add_after_stay_put", ABORT,
392  "new_element is NULL");
393  if (new_element->next)
394  STILL_LINKED.error ("ELIST_ITERATOR::add_after_stay_put", ABORT, NULL);
395  #endif
396 
397  if (list->empty ()) {
398  new_element->next = new_element;
399  list->last = new_element;
400  prev = next = new_element;
401  ex_current_was_last = FALSE;
402  current = NULL;
403  }
404  else {
405  new_element->next = next;
406 
407  if (current) { //not extracted
408  current->next = new_element;
409  if (prev == current)
410  prev = new_element;
411  if (current == list->last)
412  list->last = new_element;
413  }
414  else { //current extracted
415  prev->next = new_element;
416  if (ex_current_was_last) {
417  list->last = new_element;
418  ex_current_was_last = FALSE;
419  }
420  }
421  next = new_element;
422  }
423 }
424 
425 
426 /***********************************************************************
427  * ELIST_ITERATOR::add_before_then_move
428  *
429  * Add a new element to the list before the current element and move the
430  * iterator to the new element.
431  **********************************************************************/
432 
433 inline void ELIST_ITERATOR::add_before_then_move( // element to add
434  ELIST_LINK *new_element) {
435  #ifndef NDEBUG
436  if (!this)
437  NULL_OBJECT.error ("ELIST_ITERATOR::add_before_then_move", ABORT, NULL);
438  if (!list)
439  NO_LIST.error ("ELIST_ITERATOR::add_before_then_move", ABORT, NULL);
440  if (!new_element)
441  BAD_PARAMETER.error ("ELIST_ITERATOR::add_before_then_move", ABORT,
442  "new_element is NULL");
443  if (new_element->next)
444  STILL_LINKED.error ("ELIST_ITERATOR::add_before_then_move", ABORT, NULL);
445  #endif
446 
447  if (list->empty ()) {
448  new_element->next = new_element;
449  list->last = new_element;
450  prev = next = new_element;
451  }
452  else {
453  prev->next = new_element;
454  if (current) { //not extracted
455  new_element->next = current;
456  next = current;
457  }
458  else { //current extracted
459  new_element->next = next;
460  if (ex_current_was_last)
461  list->last = new_element;
462  if (ex_current_was_cycle_pt)
463  cycle_pt = new_element;
464  }
465  }
466  current = new_element;
467 }
468 
469 
470 /***********************************************************************
471  * ELIST_ITERATOR::add_before_stay_put
472  *
473  * Add a new element to the list before the current element but dont move the
474  * iterator to the new element.
475  **********************************************************************/
476 
477 inline void ELIST_ITERATOR::add_before_stay_put( // element to add
478  ELIST_LINK *new_element) {
479  #ifndef NDEBUG
480  if (!this)
481  NULL_OBJECT.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, NULL);
482  if (!list)
483  NO_LIST.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, NULL);
484  if (!new_element)
485  BAD_PARAMETER.error ("ELIST_ITERATOR::add_before_stay_put", ABORT,
486  "new_element is NULL");
487  if (new_element->next)
488  STILL_LINKED.error ("ELIST_ITERATOR::add_before_stay_put", ABORT, NULL);
489  #endif
490 
491  if (list->empty ()) {
492  new_element->next = new_element;
493  list->last = new_element;
494  prev = next = new_element;
495  ex_current_was_last = TRUE;
496  current = NULL;
497  }
498  else {
499  prev->next = new_element;
500  if (current) { //not extracted
501  new_element->next = current;
502  if (next == current)
503  next = new_element;
504  }
505  else { //current extracted
506  new_element->next = next;
507  if (ex_current_was_last)
508  list->last = new_element;
509  }
510  prev = new_element;
511  }
512 }
513 
514 
515 /***********************************************************************
516  * ELIST_ITERATOR::add_list_after
517  *
518  * Insert another list to this list after the current element but dont move the
519  * iterator.
520  **********************************************************************/
521 
522 inline void ELIST_ITERATOR::add_list_after(ELIST *list_to_add) {
523  #ifndef NDEBUG
524  if (!this)
525  NULL_OBJECT.error ("ELIST_ITERATOR::add_list_after", ABORT, NULL);
526  if (!list)
527  NO_LIST.error ("ELIST_ITERATOR::add_list_after", ABORT, NULL);
528  if (!list_to_add)
529  BAD_PARAMETER.error ("ELIST_ITERATOR::add_list_after", ABORT,
530  "list_to_add is NULL");
531  #endif
532 
533  if (!list_to_add->empty ()) {
534  if (list->empty ()) {
535  list->last = list_to_add->last;
536  prev = list->last;
537  next = list->First ();
538  ex_current_was_last = TRUE;
539  current = NULL;
540  }
541  else {
542  if (current) { //not extracted
543  current->next = list_to_add->First ();
544  if (current == list->last)
545  list->last = list_to_add->last;
546  list_to_add->last->next = next;
547  next = current->next;
548  }
549  else { //current extracted
550  prev->next = list_to_add->First ();
551  if (ex_current_was_last) {
552  list->last = list_to_add->last;
553  ex_current_was_last = FALSE;
554  }
555  list_to_add->last->next = next;
556  next = prev->next;
557  }
558  }
559  list_to_add->last = NULL;
560  }
561 }
562 
563 
564 /***********************************************************************
565  * ELIST_ITERATOR::add_list_before
566  *
567  * Insert another list to this list before the current element. Move the
568  * iterator to the start of the inserted elements
569  * iterator.
570  **********************************************************************/
571 
572 inline void ELIST_ITERATOR::add_list_before(ELIST *list_to_add) {
573  #ifndef NDEBUG
574  if (!this)
575  NULL_OBJECT.error ("ELIST_ITERATOR::add_list_before", ABORT, NULL);
576  if (!list)
577  NO_LIST.error ("ELIST_ITERATOR::add_list_before", ABORT, NULL);
578  if (!list_to_add)
579  BAD_PARAMETER.error ("ELIST_ITERATOR::add_list_before", ABORT,
580  "list_to_add is NULL");
581  #endif
582 
583  if (!list_to_add->empty ()) {
584  if (list->empty ()) {
585  list->last = list_to_add->last;
586  prev = list->last;
587  current = list->First ();
588  next = current->next;
589  ex_current_was_last = FALSE;
590  }
591  else {
592  prev->next = list_to_add->First ();
593  if (current) { //not extracted
594  list_to_add->last->next = current;
595  }
596  else { //current extracted
597  list_to_add->last->next = next;
598  if (ex_current_was_last)
599  list->last = list_to_add->last;
600  if (ex_current_was_cycle_pt)
601  cycle_pt = prev->next;
602  }
603  current = prev->next;
604  next = current->next;
605  }
606  list_to_add->last = NULL;
607  }
608 }
609 
610 
611 /***********************************************************************
612  * ELIST_ITERATOR::extract
613  *
614  * Do extraction by removing current from the list, returning it to the
615  * caller, but NOT updating the iterator. (So that any calling loop can do
616  * this.) The iterator's current points to NULL. If the extracted element
617  * is to be deleted, this is the callers responsibility.
618  **********************************************************************/
619 
621  ELIST_LINK *extracted_link;
622 
623  #ifndef NDEBUG
624  if (!this)
625  NULL_OBJECT.error ("ELIST_ITERATOR::extract", ABORT, NULL);
626  if (!list)
627  NO_LIST.error ("ELIST_ITERATOR::extract", ABORT, NULL);
628  if (!current) //list empty or
629  //element extracted
630  NULL_CURRENT.error ("ELIST_ITERATOR::extract",
631  ABORT, NULL);
632  #endif
633 
634  if (list->singleton()) {
635  // Special case where we do need to change the iterator.
636  prev = next = list->last = NULL;
637  } else {
638  prev->next = next; //remove from list
639 
640  if (current == list->last) {
641  list->last = prev;
642  ex_current_was_last = TRUE;
643  } else {
644  ex_current_was_last = FALSE;
645  }
646  }
647  // Always set ex_current_was_cycle_pt so an add/forward will work in a loop.
648  ex_current_was_cycle_pt = (current == cycle_pt) ? TRUE : FALSE;
649  extracted_link = current;
650  extracted_link->next = NULL; //for safety
651  current = NULL;
652  return extracted_link;
653 }
654 
655 
656 /***********************************************************************
657  * ELIST_ITERATOR::move_to_first()
658  *
659  * Move current so that it is set to the start of the list.
660  * Return data just in case anyone wants it.
661  **********************************************************************/
662 
664  #ifndef NDEBUG
665  if (!this)
666  NULL_OBJECT.error ("ELIST_ITERATOR::move_to_first", ABORT, NULL);
667  if (!list)
668  NO_LIST.error ("ELIST_ITERATOR::move_to_first", ABORT, NULL);
669  #endif
670 
671  current = list->First ();
672  prev = list->last;
673  next = current ? current->next : NULL;
674  return current;
675 }
676 
677 
678 /***********************************************************************
679  * ELIST_ITERATOR::mark_cycle_pt()
680  *
681  * Remember the current location so that we can tell whether we've returned
682  * to this point later.
683  *
684  * If the current point is deleted either now, or in the future, the cycle
685  * point will be set to the next item which is set to current. This could be
686  * by a forward, add_after_then_move or add_after_then_move.
687  **********************************************************************/
688 
690  #ifndef NDEBUG
691  if (!this)
692  NULL_OBJECT.error ("ELIST_ITERATOR::mark_cycle_pt", ABORT, NULL);
693  if (!list)
694  NO_LIST.error ("ELIST_ITERATOR::mark_cycle_pt", ABORT, NULL);
695  #endif
696 
697  if (current)
698  cycle_pt = current;
699  else
700  ex_current_was_cycle_pt = TRUE;
701  started_cycling = FALSE;
702 }
703 
704 
705 /***********************************************************************
706  * ELIST_ITERATOR::at_first()
707  *
708  * Are we at the start of the list?
709  *
710  **********************************************************************/
711 
713  #ifndef NDEBUG
714  if (!this)
715  NULL_OBJECT.error ("ELIST_ITERATOR::at_first", ABORT, NULL);
716  if (!list)
717  NO_LIST.error ("ELIST_ITERATOR::at_first", ABORT, NULL);
718  #endif
719 
720  //we're at a deleted
721  return ((list->empty ()) || (current == list->First ()) || ((current == NULL) &&
722  (prev == list->last) && //NON-last pt between
723  !ex_current_was_last)); //first and last
724 }
725 
726 
727 /***********************************************************************
728  * ELIST_ITERATOR::at_last()
729  *
730  * Are we at the end of the list?
731  *
732  **********************************************************************/
733 
734 inline bool ELIST_ITERATOR::at_last() {
735  #ifndef NDEBUG
736  if (!this)
737  NULL_OBJECT.error ("ELIST_ITERATOR::at_last", ABORT, NULL);
738  if (!list)
739  NO_LIST.error ("ELIST_ITERATOR::at_last", ABORT, NULL);
740  #endif
741 
742  //we're at a deleted
743  return ((list->empty ()) || (current == list->last) || ((current == NULL) &&
744  (prev == list->last) && //last point between
745  ex_current_was_last)); //first and last
746 }
747 
748 
749 /***********************************************************************
750  * ELIST_ITERATOR::cycled_list()
751  *
752  * Have we returned to the cycle_pt since it was set?
753  *
754  **********************************************************************/
755 
757  #ifndef NDEBUG
758  if (!this)
759  NULL_OBJECT.error ("ELIST_ITERATOR::cycled_list", ABORT, NULL);
760  if (!list)
761  NO_LIST.error ("ELIST_ITERATOR::cycled_list", ABORT, NULL);
762  #endif
763 
764  return ((list->empty ()) || ((current == cycle_pt) && started_cycling));
765 
766 }
767 
768 
769 /***********************************************************************
770  * ELIST_ITERATOR::length()
771  *
772  * Return the length of the list
773  *
774  **********************************************************************/
775 
777  #ifndef NDEBUG
778  if (!this)
779  NULL_OBJECT.error ("ELIST_ITERATOR::length", ABORT, NULL);
780  if (!list)
781  NO_LIST.error ("ELIST_ITERATOR::length", ABORT, NULL);
782  #endif
783 
784  return list->length ();
785 }
786 
787 
788 /***********************************************************************
789  * ELIST_ITERATOR::sort()
790  *
791  * Sort the elements of the list, then reposition at the start.
792  *
793  **********************************************************************/
794 
795 inline void
796 ELIST_ITERATOR::sort ( //sort elements
797 int comparator ( //comparison routine
798 const void *, const void *)) {
799  #ifndef NDEBUG
800  if (!this)
801  NULL_OBJECT.error ("ELIST_ITERATOR::sort", ABORT, NULL);
802  if (!list)
803  NO_LIST.error ("ELIST_ITERATOR::sort", ABORT, NULL);
804  #endif
805 
806  list->sort (comparator);
807  move_to_first();
808 }
809 
810 
811 /***********************************************************************
812  * ELIST_ITERATOR::add_to_end
813  *
814  * Add a new element to the end of the list without moving the iterator.
815  * This is provided because a single linked list cannot move to the last as
816  * the iterator couldn't set its prev pointer. Adding to the end is
817  * essential for implementing
818  queues.
819 **********************************************************************/
820 
821 inline void ELIST_ITERATOR::add_to_end( // element to add
822  ELIST_LINK *new_element) {
823  #ifndef NDEBUG
824  if (!this)
825  NULL_OBJECT.error ("ELIST_ITERATOR::add_to_end", ABORT, NULL);
826  if (!list)
827  NO_LIST.error ("ELIST_ITERATOR::add_to_end", ABORT, NULL);
828  if (!new_element)
829  BAD_PARAMETER.error ("ELIST_ITERATOR::add_to_end", ABORT,
830  "new_element is NULL");
831  if (new_element->next)
832  STILL_LINKED.error ("ELIST_ITERATOR::add_to_end", ABORT, NULL);
833  #endif
834 
835  if (this->at_last ()) {
836  this->add_after_stay_put (new_element);
837  }
838  else {
839  if (this->at_first ()) {
840  this->add_before_stay_put (new_element);
841  list->last = new_element;
842  }
843  else { //Iteratr is elsewhere
844  new_element->next = list->last->next;
845  list->last->next = new_element;
846  list->last = new_element;
847  }
848  }
849 }
850 
851 
852 /***********************************************************************
853  ******************** MACROS **************************************
854  ***********************************************************************/
855 
856 /***********************************************************************
857  QUOTE_IT MACRO DEFINITION
858  ===========================
859 Replace <parm> with "<parm>". <parm> may be an arbitrary number of tokens
860 ***********************************************************************/
861 
862 #define QUOTE_IT( parm ) #parm
863 
864 /***********************************************************************
865  ELISTIZE( CLASSNAME ) MACRO
866  ============================
867 
868 CLASSNAME is assumed to be the name of a class which has a baseclass of
869 ELIST_LINK.
870 
871 NOTE: Because we dont use virtual functions in the list code, the list code
872 will NOT work correctly for classes derived from this.
873 
874 The macros generate:
875  - An element deletion function: CLASSNAME##_zapper
876  - An E_LIST subclass: CLASSNAME##_LIST
877  - An E_LIST_ITERATOR subclass: CLASSNAME##_IT
878 
879 NOTE: Generated names are DELIBERATELY designed to clash with those for
880 ELIST2IZE but NOT with those for CLISTIZE and CLIST2IZE
881 
882 Two macros are provided: ELISTIZE and ELISTIZEH.
883 The ...IZEH macros just define the class names for use in .h files
884 The ...IZE macros define the code use in .c files
885 ***********************************************************************/
886 
887 /***********************************************************************
888  ELISTIZEH( CLASSNAME ) MACRO
889 
890 ELISTIZEH is a concatenation of 3 fragments ELISTIZEH_A, ELISTIZEH_B and
891 ELISTIZEH_C.
892 ***********************************************************************/
893 
894 #define ELISTIZEH_A(CLASSNAME) \
895  \
896 extern DLLSYM void CLASSNAME##_zapper(ELIST_LINK* link);
897 
898 #define ELISTIZEH_B(CLASSNAME) \
899  \
900 /*********************************************************************** \
901 * CLASS - CLASSNAME##_LIST \
902 * \
903 * List class for class CLASSNAME \
904 * \
905 **********************************************************************/ \
906  \
907 class DLLSYM CLASSNAME##_LIST : public ELIST { \
908  public: \
909  CLASSNAME##_LIST():ELIST() {} \
910  \
911  void clear() { /* delete elements */\
912  ELIST::internal_clear(&CLASSNAME##_zapper); \
913  } \
914  \
915  ~CLASSNAME##_LIST() { \
916  clear(); \
917  } \
918  \
919  /* Become a deep copy of src_list*/ \
920  void deep_copy(const CLASSNAME##_LIST* src_list, \
921  CLASSNAME* (*copier)(const CLASSNAME*)); \
922  \
923 private: \
924  /* Prevent assign and copy construction. */ \
925  CLASSNAME##_LIST(const CLASSNAME##_LIST&) { \
926  DONT_CONSTRUCT_LIST_BY_COPY.error(QUOTE_IT(CLASSNAME##_LIST), ABORT, NULL);\
927  } \
928  void operator=(const CLASSNAME##_LIST&) { \
929  DONT_ASSIGN_LISTS.error(QUOTE_IT(CLASSNAME##_LIST), ABORT, NULL ); \
930  } \
931 
932 #define ELISTIZEH_C( CLASSNAME ) \
933 }; \
934  \
935  \
936  \
937 /*********************************************************************** \
938 * CLASS - CLASSNAME##_IT \
939 * \
940 * Iterator class for class CLASSNAME##_LIST \
941 * \
942 * Note: We don't need to coerce pointers to member functions input \
943 * parameters as these are automatically converted to the type of the base \
944 * type. ("A ptr to a class may be converted to a pointer to a public base \
945 * class of that class") \
946 **********************************************************************/ \
947  \
948 class DLLSYM CLASSNAME##_IT : public ELIST_ITERATOR { \
949  public: \
950  CLASSNAME##_IT():ELIST_ITERATOR(){} \
951  \
952  /* TODO(rays) This constructor should be explicit, but that means changing \
953  hundreds of incorrect initializations of iterators that use = over () */ \
954  CLASSNAME##_IT(CLASSNAME##_LIST* list) : ELIST_ITERATOR(list) {} \
955  \
956  CLASSNAME* data() { \
957  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::data()); \
958  } \
959  \
960  CLASSNAME* data_relative(inT8 offset) { \
961  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::data_relative(offset));\
962  } \
963  \
964  CLASSNAME* forward() { \
965  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::forward()); \
966  } \
967  \
968  CLASSNAME* extract() { \
969  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::extract()); \
970  } \
971  \
972  CLASSNAME* move_to_first() { \
973  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::move_to_first()); \
974  } \
975  \
976  CLASSNAME* move_to_last() { \
977  return reinterpret_cast<CLASSNAME*>(ELIST_ITERATOR::move_to_last()); \
978  } \
979 };
980 
981 #define ELISTIZEH( CLASSNAME ) \
982  \
983 ELISTIZEH_A( CLASSNAME ) \
984  \
985 ELISTIZEH_B( CLASSNAME ) \
986  \
987 ELISTIZEH_C( CLASSNAME )
988 
989 
990 /***********************************************************************
991  ELISTIZE( CLASSNAME ) MACRO
992 ***********************************************************************/
993 
994 #define ELISTIZE(CLASSNAME) \
995  \
996 /*********************************************************************** \
997 * CLASSNAME##_zapper \
998 * \
999 * A function which can delete a CLASSNAME element. This is passed to the \
1000 * generic clear list member function so that when a list is cleared the \
1001 * elements on the list are properly destroyed from the base class, even \
1002 * though we dont use a virtual destructor function. \
1003 **********************************************************************/ \
1004  \
1005 DLLSYM void CLASSNAME##_zapper(ELIST_LINK* link) { \
1006  delete reinterpret_cast<CLASSNAME*>(link); \
1007 } \
1008  \
1009 /* Become a deep copy of src_list*/ \
1010 void CLASSNAME##_LIST::deep_copy(const CLASSNAME##_LIST* src_list, \
1011  CLASSNAME* (*copier)(const CLASSNAME*)) { \
1012  \
1013  CLASSNAME##_IT from_it(const_cast<CLASSNAME##_LIST*>(src_list)); \
1014  CLASSNAME##_IT to_it(this); \
1015  \
1016  for (from_it.mark_cycle_pt(); !from_it.cycled_list(); from_it.forward()) \
1017  to_it.add_after_then_move((*copier)(from_it.data())); \
1018 }
1019 
1020 #endif
ELIST_LINK * move_to_first()
Definition: elst.h:663
void set_to_list(ELIST *list_to_iterate)
Definition: elst.h:297
void add_to_end(ELIST_LINK *new_link)
Definition: elst.h:821
bool cycled_list()
Definition: elst.h:756
LIST last(LIST var_list)
Definition: oldlist.cpp:277
ELIST_LINK()
Definition: elst.h:92
void sort(int comparator(const void *, const void *))
Definition: elst.cpp:125
Definition: errcode.h:30
bool singleton() const
Definition: elst.h:136
ELIST_ITERATOR()
Definition: elst.h:208
bool empty() const
Definition: elst.h:132
inT32 length() const
Definition: elst.cpp:101
void mark_cycle_pt()
Definition: elst.h:689
const ERRCODE BAD_PARAMETER
Definition: lsterr.h:39
const ERRCODE NO_LIST
Definition: lsterr.h:32
void add_list_before(ELIST *list_to_add)
Definition: elst.h:572
void add_after_stay_put(ELIST_LINK *new_link)
Definition: elst.h:383
void add_after_then_move(ELIST_LINK *new_link)
Definition: elst.h:336
ELIST()
Definition: elst.h:124
void add_before_then_move(ELIST_LINK *new_link)
Definition: elst.h:433
const ERRCODE NULL_CURRENT
Definition: lsterr.h:35
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
bool empty()
Definition: elst.h:258
ELIST_LINK * data()
Definition: elst.h:235
inT32 length()
Definition: elst.h:776
ELIST_LINK * extract()
Definition: elst.h:620
bool current_extracted()
Definition: elst.h:266
void sort(int comparator(const void *, const void *))
Definition: elst.h:796
const ERRCODE NULL_DATA
Definition: lsterr.h:34
#define FALSE
Definition: capi.h:29
void add_list_after(ELIST *list_to_add)
Definition: elst.h:522
Definition: elst.h:113
void shallow_copy(ELIST *from_list)
Definition: elst.h:140
#define TRUE
Definition: capi.h:28
bool at_first()
Definition: elst.h:712
bool add_sorted(int comparator(const void *, const void *), bool unique, ELIST_LINK *new_link)
Definition: elst.h:174
const ERRCODE STILL_LINKED
Definition: lsterr.h:40
#define NULL
Definition: host.h:144
SIGNED char inT8
Definition: host.h:98
const ERRCODE NULL_OBJECT
Definition: lsterr.h:33
#define DLLSYM
Definition: platform.h:25
ELIST_LINK(const ELIST_LINK &)
Definition: elst.h:97
bool at_last()
Definition: elst.h:734
void assign_to_sublist(ELIST_ITERATOR *start_it, ELIST_ITERATOR *end_it)
Definition: elst.cpp:77
void add_before_stay_put(ELIST_LINK *new_link)
Definition: elst.h:477
int inT32
Definition: host.h:102