Commit 03435adc for tesseract

commit 03435adca0634806661e09e8ceb2a03a1a43970f
Author: Egor Pugin <egor.pugin@gmail.com>
Date:   Wed Apr 7 00:04:30 2021 +0300

    [elist] Rework macro into template and small macro. Move common iterator template into 'list_iterator.h'.

diff --git a/src/ccmain/paramsd.cpp b/src/ccmain/paramsd.cpp
index 8d5cd20d..38d0d5cb 100644
--- a/src/ccmain/paramsd.cpp
+++ b/src/ccmain/paramsd.cpp
@@ -54,8 +54,6 @@ static std::map<int, ParamContent *> vcMap;
 static int nrParams = 0;
 static int writeCommands[2];

-ELISTIZE(ParamContent)
-
 // Constructors for the various ParamTypes.
 ParamContent::ParamContent(tesseract::StringParam *it) {
   my_id_ = nrParams;
diff --git a/src/ccstruct/blobbox.cpp b/src/ccstruct/blobbox.cpp
index d66b7bea..83bb7253 100644
--- a/src/ccstruct/blobbox.cpp
+++ b/src/ccstruct/blobbox.cpp
@@ -39,9 +39,7 @@

 namespace tesseract {

-ELISTIZE(BLOBNBOX)
 ELIST2IZE(TO_ROW)
-ELISTIZE(TO_BLOCK)

 // Up to 30 degrees is allowed for rotations of diacritic blobs.
 const double kCosSmallAngle = 0.866;
diff --git a/src/ccstruct/blobbox.h b/src/ccstruct/blobbox.h
index b5ba7557..56a288fe 100644
--- a/src/ccstruct/blobbox.h
+++ b/src/ccstruct/blobbox.h
@@ -677,7 +677,7 @@ private:
 };

 ELIST2IZEH(TO_ROW)
-class TO_BLOCK : public ELIST_LINK {
+class TESS_API TO_BLOCK : public ELIST_LINK {
 public:
   TO_BLOCK() : pitch_decision(PITCH_DUNNO) {
     clear();
diff --git a/src/ccstruct/coutln.cpp b/src/ccstruct/coutln.cpp
index e9d26ffe..1a5eb5c0 100644
--- a/src/ccstruct/coutln.cpp
+++ b/src/ccstruct/coutln.cpp
@@ -42,7 +42,6 @@

 namespace tesseract {

-ELISTIZE(C_OUTLINE)
 ICOORD C_OUTLINE::step_coords[4] = {ICOORD(-1, 0), ICOORD(0, -1), ICOORD(1, 0), ICOORD(0, 1)};

 /**
diff --git a/src/ccstruct/ocrblock.cpp b/src/ccstruct/ocrblock.cpp
index f03b8c77..8a7fa6fa 100644
--- a/src/ccstruct/ocrblock.cpp
+++ b/src/ccstruct/ocrblock.cpp
@@ -26,7 +26,6 @@

 namespace tesseract {

-ELISTIZE(BLOCK)
 /**
  * BLOCK::BLOCK
  *
diff --git a/src/ccstruct/ocrpara.cpp b/src/ccstruct/ocrpara.cpp
index 40f757b4..dda72db1 100644
--- a/src/ccstruct/ocrpara.cpp
+++ b/src/ccstruct/ocrpara.cpp
@@ -24,8 +24,6 @@

 namespace tesseract {

-ELISTIZE(PARA)
-
 using tesseract::JUSTIFICATION_CENTER;
 using tesseract::JUSTIFICATION_LEFT;
 using tesseract::JUSTIFICATION_RIGHT;
diff --git a/src/ccstruct/ocrrow.cpp b/src/ccstruct/ocrrow.cpp
index 80c7d170..f02f0749 100644
--- a/src/ccstruct/ocrrow.cpp
+++ b/src/ccstruct/ocrrow.cpp
@@ -26,7 +26,6 @@

 namespace tesseract {

-ELISTIZE(ROW)
 /**********************************************************************
  * ROW::ROW
  *
diff --git a/src/ccstruct/pageres.cpp b/src/ccstruct/pageres.cpp
index 88c9a3c4..534088fc 100644
--- a/src/ccstruct/pageres.cpp
+++ b/src/ccstruct/pageres.cpp
@@ -45,10 +45,6 @@ struct Pix;

 namespace tesseract {

-ELISTIZE(BLOCK_RES)
-ELISTIZE(ROW_RES)
-ELISTIZE(WERD_RES)
-
 // Gain factor for computing thresholds that determine the ambiguity of a
 // word.
 static const double kStopperAmbiguityThresholdGain = 8.0;
diff --git a/src/ccstruct/points.cpp b/src/ccstruct/points.cpp
index 03654c4c..1e0375e7 100644
--- a/src/ccstruct/points.cpp
+++ b/src/ccstruct/points.cpp
@@ -29,7 +29,6 @@

 namespace tesseract {

-ELISTIZE(ICOORDELT)        // turn to list
 bool FCOORD::normalise() { // Convert to unit vec
   float len = length();

diff --git a/src/ccstruct/ratngs.cpp b/src/ccstruct/ratngs.cpp
index 4b4997c9..5801cd9b 100644
--- a/src/ccstruct/ratngs.cpp
+++ b/src/ccstruct/ratngs.cpp
@@ -33,9 +33,6 @@

 namespace tesseract {

-ELISTIZE(BLOB_CHOICE)
-ELISTIZE(WERD_CHOICE)
-
 const float WERD_CHOICE::kBadRating = 100000.0;
 // Min offset in baseline-normalized coords to make a character a subscript.
 const int kMinSubscriptOffset = 20;
diff --git a/src/ccstruct/stepblob.cpp b/src/ccstruct/stepblob.cpp
index 13051337..513619d7 100644
--- a/src/ccstruct/stepblob.cpp
+++ b/src/ccstruct/stepblob.cpp
@@ -35,7 +35,6 @@ class DENORM;
 // Max perimeter to width ratio for a baseline position above box bottom.
 const double kMaxPerimeterWidthRatio = 8.0;

-ELISTIZE(C_BLOB)
 /**********************************************************************
  * position_outline
  *
diff --git a/src/ccutil/ambigs.cpp b/src/ccutil/ambigs.cpp
index c118822d..a4dcd242 100644
--- a/src/ccutil/ambigs.cpp
+++ b/src/ccutil/ambigs.cpp
@@ -47,8 +47,6 @@ AmbigSpec::AmbigSpec() {
   wrong_ngram_size = 0;
 }

-ELISTIZE(AmbigSpec)
-
 // Initializes the ambigs by adding a nullptr pointer to each table.
 void UnicharAmbigs::InitUnicharAmbigs(const UNICHARSET &unicharset, bool use_ambigs_for_adaption) {
   for (int i = 0; i < unicharset.size(); ++i) {
diff --git a/src/ccutil/clst.h b/src/ccutil/clst.h
index 2d057447..b216f878 100644
--- a/src/ccutil/clst.h
+++ b/src/ccutil/clst.h
@@ -19,6 +19,7 @@
 #ifndef CLST_H
 #define CLST_H

+#include "list_iterator.h"
 #include "lsterr.h"
 #include "serialis.h"

@@ -703,38 +704,15 @@ public:
   }
 };

-template <typename CLASSNAME>
-class X_C_IT : public CLIST_ITERATOR {
-public:
-  X_C_IT() = default;
-protected:
-  template <typename U>
-  X_C_IT(U *list) : CLIST_ITERATOR(list) {}
-
-public:
-  CLASSNAME *data() {
-    return static_cast<CLASSNAME *>(CLIST_ITERATOR::data());
-  }
-  CLASSNAME *data_relative(int8_t offset) {
-    return static_cast<CLASSNAME *>(CLIST_ITERATOR::data_relative(offset));
-  }
-  CLASSNAME *forward() {
-    return static_cast<CLASSNAME *>(CLIST_ITERATOR::forward());
-  }
-  CLASSNAME *extract() {
-    return static_cast<CLASSNAME *>(CLIST_ITERATOR::extract());
-  }
-};
-
-#define CLISTIZEH(CLASSNAME)                                    \
-  class CLASSNAME##_CLIST : public X_CLIST<CLASSNAME> {         \
-  public:                                                       \
-    using X_CLIST<CLASSNAME>::X_CLIST;                          \
-  };                                                            \
-  class CLASSNAME##_C_IT : public X_C_IT<CLASSNAME> {           \
-  public:                                                       \
-    using X_C_IT<CLASSNAME>::X_C_IT;                            \
-    CLASSNAME##_C_IT(CLASSNAME##_CLIST *list) : X_C_IT(list) {} \
+#define CLISTIZEH(CLASSNAME)                                          \
+  class CLASSNAME##_CLIST : public X_CLIST<CLASSNAME> {               \
+  public:                                                             \
+    using X_CLIST<CLASSNAME>::X_CLIST;                                \
+  };                                                                  \
+  class CLASSNAME##_C_IT : public X_ITER<CLIST_ITERATOR, CLASSNAME> { \
+  public:                                                             \
+    using X_ITER<CLIST_ITERATOR, CLASSNAME>::X_ITER;                  \
+    CLASSNAME##_C_IT(CLASSNAME##_CLIST *list) : X_ITER(list) {}       \
   };

 } // namespace tesseract
diff --git a/src/ccutil/elst.h b/src/ccutil/elst.h
index ba6f3787..6f4bf28b 100644
--- a/src/ccutil/elst.h
+++ b/src/ccutil/elst.h
@@ -19,6 +19,7 @@
 #ifndef ELST_H
 #define ELST_H

+#include "list_iterator.h"
 #include "lsterr.h"
 #include "serialis.h"

@@ -804,142 +805,45 @@ inline void ELIST_ITERATOR::add_to_end( // element to add
   }
 }

-/***********************************************************************
- ********************    MACROS    **************************************
- ***********************************************************************/
-
-/***********************************************************************
-  ELISTIZE(CLASSNAME) MACRO
-  ============================
-
-CLASSNAME is assumed to be the name of a class which has a baseclass of
-ELIST_LINK.
+template <typename CLASSNAME>
+class X_LIST : public ELIST {
+public:
+  X_LIST() = default;
+  X_LIST(const X_LIST &) = delete;
+  X_LIST &operator=(const X_LIST &) = delete;
+  ~X_LIST() {
+    clear();
+  }

-NOTE:  Because we don't use virtual functions in the list code, the list code
-will NOT work correctly for classes derived from this.
+  /* delete elements */
+  void clear() {
+    ELIST::internal_clear([](ELIST_LINK *link) {delete reinterpret_cast<CLASSNAME *>(link);});
+  }

-The macros generate:
-  - An element deletion function:      CLASSNAME##_zapper
-  - An E_LIST subclass: CLASSNAME##_LIST
-  - An E_LIST_ITERATOR subclass:       CLASSNAME##_IT
+  /* Become a deep copy of src_list */
+  template <typename U>
+  void deep_copy(const U *src_list, CLASSNAME *(*copier)(const CLASSNAME *)) {
+    static_assert(std::is_base_of_v<X_LIST, U>);

-NOTE: Generated names are DELIBERATELY designed to clash with those for
-ELIST2IZE but NOT with those for CLISTIZE.
+    X_ITER<ELIST_ITERATOR, CLASSNAME> from_it(const_cast<U *>(src_list));
+    X_ITER<ELIST_ITERATOR, CLASSNAME> to_it(this);

-Two macros are provided: ELISTIZE and ELISTIZEH.
-The ...IZEH macros just define the class names for use in .h files
-The ...IZE macros define the code use in .c files
-***********************************************************************/
+    for (from_it.mark_cycle_pt(); !from_it.cycled_list(); from_it.forward())
+      to_it.add_after_then_move((*copier)(from_it.data()));
+  }
+};

-/***********************************************************************
-  ELISTIZEH(CLASSNAME)  MACRO
-
-ELISTIZEH is a concatenation of 3 fragments ELISTIZEH_A, ELISTIZEH_B and
-ELISTIZEH_C.
-***********************************************************************/
-
-#define ELISTIZEH_A(CLASSNAME) TESS_API extern void CLASSNAME##_zapper(ELIST_LINK *link);
-
-#define ELISTIZEH_B(CLASSNAME)                                                                 \
-                                                                                               \
-  /***********************************************************************                     \
-   *                           CLASS - CLASSNAME##_LIST                                        \
-   *                                                                                           \
-   *                           List class for class CLASSNAME                                  \
-   *                                                                                           \
-   **********************************************************************/                     \
-                                                                                               \
-  class CLASSNAME##_LIST : public ELIST {                                                      \
-  public:                                                                                      \
-    CLASSNAME##_LIST() : ELIST() {}                                                            \
-                                                                                               \
-    void clear() { /* delete elements */                                                       \
-      ELIST::internal_clear(&CLASSNAME##_zapper);                                              \
-    }                                                                                          \
-                                                                                               \
-    ~CLASSNAME##_LIST() {                                                                      \
-      clear();                                                                                 \
-    }                                                                                          \
-                                                                                               \
-    /* Become a deep copy of src_list*/                                                        \
-    void deep_copy(const CLASSNAME##_LIST *src_list, CLASSNAME *(*copier)(const CLASSNAME *)); \
-                                                                                               \
-    /* Prevent assign and copy construction. */                                                \
-    CLASSNAME##_LIST(const CLASSNAME##_LIST &) = delete;                                       \
-    void operator=(const CLASSNAME##_LIST &) = delete;                                         \
-
-#define ELISTIZEH_C(CLASSNAME)                                                     \
-  }                                                                                \
-  ;                                                                                \
-                                                                                   \
-  /***********************************************************************         \
-   *                           CLASS - CLASSNAME##_IT                              \
-   *                                                                               \
-   *                           Iterator class for class CLASSNAME##_LIST           \
-   *                                                                               \
-   *  Note: We don't need to coerce pointers to member functions input             \
-   *  parameters as these are automatically converted to the type of the base      \
-   *  type. ("A ptr to a class may be converted to a pointer to a public base      \
-   *  class of that class")                                                        \
-   **********************************************************************/         \
-                                                                                   \
-  class CLASSNAME##_IT : public ELIST_ITERATOR {                                   \
-  public:                                                                          \
-    CLASSNAME##_IT() : ELIST_ITERATOR() {}                                         \
-                                                                                   \
-    /* TODO(rays) This constructor should be explicit, but that means changing     \
-       hundreds of incorrect initializations of iterators that use = over ()       \
-     */                                                                            \
-    CLASSNAME##_IT(CLASSNAME##_LIST *list) : ELIST_ITERATOR(list) {}               \
-                                                                                   \
-    CLASSNAME *data() {                                                            \
-      return reinterpret_cast<CLASSNAME *>(ELIST_ITERATOR::data());                \
-    }                                                                              \
-    CLASSNAME *data_relative(int8_t offset) {                                      \
-      return reinterpret_cast<CLASSNAME *>(ELIST_ITERATOR::data_relative(offset)); \
-    }                                                                              \
-    CLASSNAME *forward() {                                                         \
-      return reinterpret_cast<CLASSNAME *>(ELIST_ITERATOR::forward());             \
-    }                                                                              \
-    CLASSNAME *extract() {                                                         \
-      return reinterpret_cast<CLASSNAME *>(ELIST_ITERATOR::extract());             \
-    }                                                                              \
+#define ELISTIZEH(CLASSNAME)                                        \
+  class CLASSNAME##_LIST : public X_LIST<CLASSNAME> {               \
+  public:                                                           \
+    using X_LIST<CLASSNAME>::X_LIST;                                \
+  };                                                                \
+  class CLASSNAME##_IT : public X_ITER<ELIST_ITERATOR, CLASSNAME> { \
+  public:                                                           \
+    using X_ITER<ELIST_ITERATOR, CLASSNAME>::X_ITER;                \
+    CLASSNAME##_IT(CLASSNAME##_LIST *list) : X_ITER(list) {}        \
   };

-#define ELISTIZEH(CLASSNAME) \
-  ELISTIZEH_A(CLASSNAME)     \
-  ELISTIZEH_B(CLASSNAME)     \
-  ELISTIZEH_C(CLASSNAME)
-
-/***********************************************************************
-  ELISTIZE(CLASSNAME) MACRO
-***********************************************************************/
-
-#define ELISTIZE(CLASSNAME)                                                   \
-                                                                              \
-  /***********************************************************************    \
-   *                           CLASSNAME##_zapper                             \
-   *                                                                          \
-   *  A function which can delete a CLASSNAME element.  This is passed to the \
-   *  generic clear list member function so that when a list is cleared the   \
-   *  elements on the list are properly destroyed from the base class, even   \
-   *  though we don't use a virtual destructor function.                      \
-   **********************************************************************/    \
-                                                                              \
-  void CLASSNAME##_zapper(ELIST_LINK *link) {                                 \
-    delete reinterpret_cast<CLASSNAME *>(link);                               \
-  }                                                                           \
-                                                                              \
-  /* Become a deep copy of src_list*/                                         \
-  void CLASSNAME##_LIST::deep_copy(const CLASSNAME##_LIST *src_list,          \
-                                   CLASSNAME *(*copier)(const CLASSNAME *)) { \
-    CLASSNAME##_IT from_it(const_cast<CLASSNAME##_LIST *>(src_list));         \
-    CLASSNAME##_IT to_it(this);                                               \
-                                                                              \
-    for (from_it.mark_cycle_pt(); !from_it.cycled_list(); from_it.forward())  \
-      to_it.add_after_then_move((*copier)(from_it.data()));                   \
-  }
-
 } // namespace tesseract

 #endif
diff --git a/src/ccutil/list_iterator.h b/src/ccutil/list_iterator.h
new file mode 100644
index 00000000..c419ed20
--- /dev/null
+++ b/src/ccutil/list_iterator.h
@@ -0,0 +1,44 @@
+/**********************************************************************
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ *
+ **********************************************************************/
+
+#ifndef LIST_ITERATOR_H
+#define LIST_ITERATOR_H
+
+#include <stdint.h>
+
+namespace tesseract {
+
+template <typename CONTAINER, typename CLASSNAME>
+class X_ITER : public CONTAINER {
+public:
+  X_ITER() = default;
+  template <typename U>
+  X_ITER(U *list) : CONTAINER(list) {}
+
+  CLASSNAME *data() {
+    return static_cast<CLASSNAME *>(CONTAINER::data());
+  }
+  CLASSNAME *data_relative(int8_t offset) {
+    return static_cast<CLASSNAME *>(CONTAINER::data_relative(offset));
+  }
+  CLASSNAME *forward() {
+    return static_cast<CLASSNAME *>(CONTAINER::forward());
+  }
+  CLASSNAME *extract() {
+    return static_cast<CLASSNAME *>(CONTAINER::extract());
+  }
+};
+
+} // namespace tesseract
+
+#endif
diff --git a/src/classify/trainingsample.cpp b/src/classify/trainingsample.cpp
index d4307a2e..ccbb84aa 100644
--- a/src/classify/trainingsample.cpp
+++ b/src/classify/trainingsample.cpp
@@ -32,8 +32,6 @@

 namespace tesseract {

-ELISTIZE(TrainingSample)
-
 // Center of randomizing operations.
 const int kRandomizingCenter = 128;

diff --git a/src/textord/colpartitionset.cpp b/src/textord/colpartitionset.cpp
index 4a89c989..1252c2ae 100644
--- a/src/textord/colpartitionset.cpp
+++ b/src/textord/colpartitionset.cpp
@@ -30,8 +30,6 @@ namespace tesseract {
 // Minimum width of a column to be interesting as a multiple of resolution.
 const double kMinColumnWidth = 2.0 / 3;

-ELISTIZE(ColPartitionSet)
-
 ColPartitionSet::ColPartitionSet(ColPartition_LIST *partitions) {
   ColPartition_IT it(&parts_);
   it.add_list_after(partitions);
diff --git a/src/textord/fpchop.cpp b/src/textord/fpchop.cpp
index 3e0adbd7..faee5f02 100644
--- a/src/textord/fpchop.cpp
+++ b/src/textord/fpchop.cpp
@@ -34,8 +34,6 @@ namespace tesseract {
 INT_VAR(textord_fp_chop_error, 2, "Max allowed bending of chop cells");
 double_VAR(textord_fp_chop_snap, 0.5, "Max distance of chop pt from vertex");

-ELISTIZE(C_OUTLINE_FRAG)
-
 static WERD *add_repeated_word(WERD_IT *rep_it, int16_t &rep_left, int16_t &prev_chop_coord,
                                uint8_t &blanks, float pitch, WERD_IT *word_it);

diff --git a/src/textord/pitsync1.cpp b/src/textord/pitsync1.cpp
index 8f2ecadc..415d29ca 100644
--- a/src/textord/pitsync1.cpp
+++ b/src/textord/pitsync1.cpp
@@ -23,8 +23,6 @@

 namespace tesseract {

-ELISTIZE(FPSEGPT)
-
 INT_VAR(pitsync_linear_version, 6, "Use new fast algorithm");
 double_VAR(pitsync_joined_edge, 0.75, "Dist inside big blob for chopping");
 double_VAR(pitsync_offset_freecut_fraction, 0.25, "Fraction of cut for free cuts");
diff --git a/src/textord/sortflts.cpp b/src/textord/sortflts.cpp
index 0ea74839..edf9c34c 100644
--- a/src/textord/sortflts.cpp
+++ b/src/textord/sortflts.cpp
@@ -20,7 +20,6 @@

 namespace tesseract {

-ELISTIZE(SORTED_FLOAT)
 /**
  * @name SORTED_FLOATS::add
  *
diff --git a/src/textord/tablefind.cpp b/src/textord/tablefind.cpp
index ea4cd7f5..2b4fb9d0 100644
--- a/src/textord/tablefind.cpp
+++ b/src/textord/tablefind.cpp
@@ -150,8 +150,6 @@ static BOOL_VAR(textord_tablefind_show_stats, false,
 static BOOL_VAR(textord_tablefind_recognize_tables, false,
                 "Enables the table recognizer for table layout and filtering.");

-ELISTIZE(ColSegment)
-
 // Templated helper function used to create destructor callbacks for the
 // BBGrid::ClearGridData() method.
 template <typename T>
diff --git a/src/textord/tabvector.cpp b/src/textord/tabvector.cpp
index c5a9b43a..bc9ff596 100644
--- a/src/textord/tabvector.cpp
+++ b/src/textord/tabvector.cpp
@@ -59,8 +59,6 @@ double_VAR(textord_tabvector_vertical_gap_fraction, 0.5,
 double_VAR(textord_tabvector_vertical_box_ratio, 0.5,
            "Fraction of box matches required to declare a line vertical");

-ELISTIZE(TabConstraint)
-
 // Create a constraint for the top or bottom of this TabVector.
 void TabConstraint::CreateConstraint(TabVector *vector, bool is_top) {
   auto *constraint = new TabConstraint(vector, is_top);
diff --git a/src/textord/workingpartset.cpp b/src/textord/workingpartset.cpp
index 53398694..45c4abac 100644
--- a/src/textord/workingpartset.cpp
+++ b/src/textord/workingpartset.cpp
@@ -23,8 +23,6 @@

 namespace tesseract {

-ELISTIZE(WorkingPartSet)
-
 // Add the partition to this WorkingPartSet. Unrelated partitions are
 // stored in the order in which they are received, but if the partition
 // has a SingletonPartner, make sure that it stays with its partner.
diff --git a/src/wordrec/lm_state.cpp b/src/wordrec/lm_state.cpp
index fcae0ac8..0376fd95 100644
--- a/src/wordrec/lm_state.cpp
+++ b/src/wordrec/lm_state.cpp
@@ -21,8 +21,6 @@

 namespace tesseract {

-ELISTIZE(ViterbiStateEntry)
-
 void ViterbiStateEntry::Print(const char *msg) const {
   tprintf("%s ViterbiStateEntry", msg);
   if (updated) {
diff --git a/unittest/list_test.cc b/unittest/list_test.cc
index 5310214a..04d8c343 100644
--- a/unittest/list_test.cc
+++ b/unittest/list_test.cc
@@ -45,7 +45,6 @@ public:

 CLISTIZEH(Clst)
 ELISTIZEH(Elst)
-ELISTIZE(Elst)
 ELIST2IZEH(Elst2)
 ELIST2IZE(Elst2)