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