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