Commit 2fa96b76 for tesseract

commit 2fa96b765b31cde1e7afb784ea2666553596432e
Author: Stefan Weil <sw@weilnetz.de>
Date:   Wed Apr 7 17:21:13 2021 +0200

    Modernize and optimize list_rec a little bit

    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/classify/adaptive.cpp b/src/classify/adaptive.cpp
index 6586b09f..b111a4de 100644
--- a/src/classify/adaptive.cpp
+++ b/src/classify/adaptive.cpp
@@ -164,9 +164,9 @@ void Classify::PrintAdaptedTemplates(FILE *File, ADAPT_TEMPLATES_STRUCT *Templat
     IClass = Templates->Templates->Class[i];
     AClass = Templates->Class[i];
     if (!IsEmptyAdaptedClass(AClass)) {
-      fprintf(File, "%5d  %s %3d %3d %3d %3d\n", i, unicharset.id_to_unichar(i), IClass->NumConfigs,
+      fprintf(File, "%5d  %s %3d %3d %3d %3zd\n", i, unicharset.id_to_unichar(i), IClass->NumConfigs,
               AClass->NumPermConfigs, IClass->NumProtos,
-              IClass->NumProtos - count(AClass->TempProtos));
+              IClass->NumProtos - AClass->TempProtos->size());
     }
   }
   fprintf(File, "\n");
@@ -305,10 +305,6 @@ TEMP_CONFIG_STRUCT *ReadTempConfig(TFile *fp) {
  * @note Globals: none
  */
 void WriteAdaptedClass(FILE *File, ADAPT_CLASS_STRUCT *Class, int NumConfigs) {
-  int NumTempProtos;
-  LIST TempProtos;
-  int i;
-
   /* first write high level adapted class structure */
   fwrite(Class, sizeof(ADAPT_CLASS_STRUCT), 1, File);

@@ -317,9 +313,9 @@ void WriteAdaptedClass(FILE *File, ADAPT_CLASS_STRUCT *Class, int NumConfigs) {
   fwrite(Class->PermConfigs, sizeof(uint32_t), WordsInVectorOfSize(MAX_NUM_CONFIGS), File);

   /* then write out the list of temporary protos */
-  NumTempProtos = count(Class->TempProtos);
-  fwrite(&NumTempProtos, sizeof(int), 1, File);
-  TempProtos = Class->TempProtos;
+  uint32_t NumTempProtos = Class->TempProtos->size();
+  fwrite(&NumTempProtos, sizeof(NumTempProtos), 1, File);
+  auto TempProtos = Class->TempProtos;
   iterate(TempProtos) {
     void *proto = TempProtos->node;
     fwrite(proto, sizeof(TEMP_PROTO_STRUCT), 1, File);
@@ -327,7 +323,7 @@ void WriteAdaptedClass(FILE *File, ADAPT_CLASS_STRUCT *Class, int NumConfigs) {

   /* then write out the adapted configs */
   fwrite(&NumConfigs, sizeof(int), 1, File);
-  for (i = 0; i < NumConfigs; i++) {
+  for (int i = 0; i < NumConfigs; i++) {
     if (test_bit(Class->PermConfigs, i)) {
       WritePermConfig(File, Class->Config[i].Perm);
     } else {
diff --git a/src/classify/cluster.cpp b/src/classify/cluster.cpp
index 900770df..ea04af39 100644
--- a/src/classify/cluster.cpp
+++ b/src/classify/cluster.cpp
@@ -1557,7 +1557,7 @@ LIST ClusterSamples(CLUSTERER *Clusterer, CLUSTERCONFIG *Config) {
   // out, which makes it safe to delete the clusterer.
   LIST proto_list = Clusterer->ProtoList;
   iterate(proto_list) {
-    auto *proto = reinterpret_cast<PROTOTYPE *>(first_node(proto_list));
+    auto *proto = reinterpret_cast<PROTOTYPE *>(proto_list->first_node());
     proto->Cluster = nullptr;
   }
   return Clusterer->ProtoList;
@@ -1642,7 +1642,7 @@ CLUSTER *NextSample(LIST *SearchState) {
   if (*SearchState == NIL_LIST) {
     return (nullptr);
   }
-  Cluster = reinterpret_cast<CLUSTER *> first_node(*SearchState);
+  Cluster = reinterpret_cast<CLUSTER *>((*SearchState)->first_node());
   *SearchState = pop(*SearchState);
   for (;;) {
     if (Cluster->Left == nullptr) {
@@ -1922,7 +1922,7 @@ static void ComputePrototypes(CLUSTERER *Clusterer, CLUSTERCONFIG *Config) {
     // remove the next cluster to be analyzed from the stack
     // try to make a prototype from the cluster
     // if successful, put it on the proto list, else split the cluster
-    Cluster = reinterpret_cast<CLUSTER *> first_node(ClusterStack);
+    Cluster = reinterpret_cast<CLUSTER *>(ClusterStack->first_node());
     ClusterStack = pop(ClusterStack);
     Prototype = MakePrototype(Clusterer, Config, Cluster);
     if (Prototype != nullptr) {
@@ -2776,8 +2776,8 @@ static double ComputeChiSquared(uint16_t DegreesOfFreedom, double Alpha)
    for the specified number of degrees of freedom.  Search the list for
    the desired chi-squared. */
   CHISTRUCT SearchKey(0.0, Alpha);
-  auto OldChiSquared = reinterpret_cast<CHISTRUCT *> first_node(
-      search(ChiWith[DegreesOfFreedom], &SearchKey, AlphaMatch));
+  auto OldChiSquared = reinterpret_cast<CHISTRUCT *>(
+      search(ChiWith[DegreesOfFreedom], &SearchKey, AlphaMatch)->first_node());

   if (OldChiSquared == nullptr) {
     OldChiSquared = new CHISTRUCT(DegreesOfFreedom, Alpha);
diff --git a/src/classify/mf.cpp b/src/classify/mf.cpp
index 2570fdb6..f66ffe4e 100644
--- a/src/classify/mf.cpp
+++ b/src/classify/mf.cpp
@@ -59,8 +59,7 @@ FEATURE_SET ExtractMicros(TBLOB *Blob, const DENORM &cn_denorm) {

 #ifndef _WIN32
     // Assert that feature parameters are well defined.
-    int i;
-    for (i = 0; i < Feature->Type->NumParams; i++) {
+    for (int i = 0; i < Feature->Type->NumParams; i++) {
       ASSERT_HOST(!std::isnan(Feature->Params[i]));
     }
 #endif
diff --git a/src/classify/mfdefs.h b/src/classify/mfdefs.h
index e17c5017..38ef2502 100644
--- a/src/classify/mfdefs.h
+++ b/src/classify/mfdefs.h
@@ -2,7 +2,6 @@
  ** Filename:    mfdefs.h
  ** Purpose:     Definition of micro-features
  ** Author:      Dan Johnson
- ** History:     Mon Jan 22 08:42:13 1990, DSJ, Created.
  **
  ** (c) Copyright Hewlett-Packard Company, 1988.
  ** Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/classify/mfoutline.cpp b/src/classify/mfoutline.cpp
index 760c518d..1ed00659 100644
--- a/src/classify/mfoutline.cpp
+++ b/src/classify/mfoutline.cpp
@@ -130,14 +130,13 @@ void FindDirectionChanges(MFOUTLINE Outline, float MinSlope, float MaxSlope) {
  * @param arg   micro-feature outline to be freed
  */
 void FreeMFOutline(void *arg) { // MFOUTLINE Outline)
-  MFOUTLINE Start;
   auto Outline = static_cast<MFOUTLINE>(arg);

   /* break the circular outline so we can use std. techniques to deallocate */
-  Start = list_rest(Outline);
+  MFOUTLINE Start = Outline->list_rest();
   set_rest(Outline, NIL_LIST);
   while (Start != nullptr) {
-    delete first_node(Start);
+    delete reinterpret_cast<MFEDGEPT *>(Start->first_node());
     Start = pop(Start);
   }

@@ -257,7 +256,7 @@ void Classify::NormalizeOutlines(LIST Outlines, float *XScale, float *YScale) {

     case baseline:
       iterate(Outlines) {
-        Outline = static_cast<MFOUTLINE> first_node(Outlines);
+        Outline = static_cast<MFOUTLINE>(Outlines->first_node());
         NormalizeOutline(Outline, 0.0);
       }
       *XScale = *YScale = MF_SCALE_FACTOR;
diff --git a/src/classify/mfoutline.h b/src/classify/mfoutline.h
index f2707a25..b0045df5 100644
--- a/src/classify/mfoutline.h
+++ b/src/classify/mfoutline.h
@@ -63,15 +63,15 @@ const float MF_SCALE_FACTOR = 0.5f / kBlnXHeight;
 // Inline functions for manipulating micro-feature outlines.

 static inline bool DegenerateOutline(MFOUTLINE Outline) {
-  return (Outline == NIL_LIST) || (Outline == list_rest(Outline));
+  return (Outline == NIL_LIST) || (Outline == Outline->list_rest());
 }

 static inline MFEDGEPT *PointAt(MFOUTLINE Outline) {
-  return reinterpret_cast<MFEDGEPT *> first_node(Outline);
+  return reinterpret_cast<MFEDGEPT *>(Outline->first_node());
 }

 static inline MFOUTLINE NextPointAfter(MFOUTLINE Outline) {
-  return list_rest(Outline);
+  return Outline->list_rest();
 }

 static inline void MakeOutlineCircular(MFOUTLINE Outline) {
diff --git a/src/classify/mfx.cpp b/src/classify/mfx.cpp
index 0ce5661a..93ea6d54 100644
--- a/src/classify/mfx.cpp
+++ b/src/classify/mfx.cpp
@@ -55,20 +55,19 @@ MICROFEATURES BlobMicroFeatures(TBLOB *Blob, const DENORM &cn_denorm) {
   MICROFEATURES MicroFeatures;
   LIST Outlines;
   LIST RemainingOutlines;
-  MFOUTLINE Outline;

   if (Blob != nullptr) {
     Outlines = ConvertBlob(Blob);

     RemainingOutlines = Outlines;
     iterate(RemainingOutlines) {
-      Outline = static_cast<MFOUTLINE> first_node(RemainingOutlines);
+      auto Outline = static_cast<MFOUTLINE>(RemainingOutlines->first_node());
       CharNormalizeOutline(Outline, cn_denorm);
     }

     RemainingOutlines = Outlines;
     iterate(RemainingOutlines) {
-      Outline = static_cast<MFOUTLINE> first_node(RemainingOutlines);
+      auto Outline = static_cast<MFOUTLINE>(RemainingOutlines->first_node());
       FindDirectionChanges(Outline, classify_min_slope, classify_max_slope);
       MarkDirectionChanges(Outline);
       MicroFeatures = ConvertToMicroFeatures(Outline, MicroFeatures);
diff --git a/src/classify/normmatch.cpp b/src/classify/normmatch.cpp
index 44a1bd08..ea79ad63 100644
--- a/src/classify/normmatch.cpp
+++ b/src/classify/normmatch.cpp
@@ -92,13 +92,6 @@ const double kWidthErrorWeighting = 0.125;
  * @return Best match rating for Feature against protos of ClassId.
  */
 float Classify::ComputeNormMatch(CLASS_ID ClassId, const FEATURE_STRUCT &feature, bool DebugMatch) {
-  LIST Protos;
-  float BestMatch;
-  float Match;
-  float Delta;
-  PROTOTYPE *Proto;
-  int ProtoId;
-
   if (ClassId >= NormProtos->NumProtos) {
     ClassId = NO_CLASS;
   }
@@ -106,24 +99,24 @@ float Classify::ComputeNormMatch(CLASS_ID ClassId, const FEATURE_STRUCT &feature
   /* handle requests for classification as noise */
   if (ClassId == NO_CLASS) {
     /* kludge - clean up constants and make into control knobs later */
-    Match = (feature.Params[CharNormLength] * feature.Params[CharNormLength] * 500.0 +
-             feature.Params[CharNormRx] * feature.Params[CharNormRx] * 8000.0 +
-             feature.Params[CharNormRy] * feature.Params[CharNormRy] * 8000.0);
-    return (1.0 - NormEvidenceOf(Match));
+    float Match = (feature.Params[CharNormLength] * feature.Params[CharNormLength] * 500.0f +
+                   feature.Params[CharNormRx] * feature.Params[CharNormRx] * 8000.0f +
+                   feature.Params[CharNormRy] * feature.Params[CharNormRy] * 8000.0f);
+    return (1.0f - NormEvidenceOf(Match));
   }

-  BestMatch = FLT_MAX;
-  Protos = NormProtos->Protos[ClassId];
+  float BestMatch = FLT_MAX;
+  LIST Protos = NormProtos->Protos[ClassId];

   if (DebugMatch) {
     tprintf("\nChar norm for class %s\n", unicharset.id_to_unichar(ClassId));
   }

-  ProtoId = 0;
+  int ProtoId = 0;
   iterate(Protos) {
-    Proto = reinterpret_cast<PROTOTYPE *> first_node(Protos);
-    Delta = feature.Params[CharNormY] - Proto->Mean[CharNormY];
-    Match = Delta * Delta * Proto->Weight.Elliptical[CharNormY];
+    auto Proto = reinterpret_cast<PROTOTYPE *>(Protos->first_node());
+    float Delta = feature.Params[CharNormY] - Proto->Mean[CharNormY];
+    float Match = Delta * Delta * Proto->Weight.Elliptical[CharNormY];
     if (DebugMatch) {
       tprintf("YMiddle: Proto=%g, Delta=%g, Var=%g, Dist=%g\n", Proto->Mean[CharNormY], Delta,
               Proto->Weight.Elliptical[CharNormY], Match);
diff --git a/src/classify/outfeat.cpp b/src/classify/outfeat.cpp
index 9dc9eb43..136ed8eb 100644
--- a/src/classify/outfeat.cpp
+++ b/src/classify/outfeat.cpp
@@ -38,22 +38,18 @@ namespace tesseract {
  * @note Globals: none
  */
 FEATURE_SET Classify::ExtractOutlineFeatures(TBLOB *Blob) {
-  LIST Outlines;
-  LIST RemainingOutlines;
-  MFOUTLINE Outline;
-  float XScale, YScale;
-
   auto FeatureSet = new FEATURE_SET_STRUCT(MAX_OUTLINE_FEATURES);
   if (Blob == nullptr) {
     return (FeatureSet);
   }

-  Outlines = ConvertBlob(Blob);
+  auto Outlines = ConvertBlob(Blob);

+  float XScale, YScale;
   NormalizeOutlines(Outlines, &XScale, &YScale);
-  RemainingOutlines = Outlines;
+  auto RemainingOutlines = Outlines;
   iterate(RemainingOutlines) {
-    Outline = static_cast<MFOUTLINE> first_node(RemainingOutlines);
+    auto Outline = static_cast<MFOUTLINE>(RemainingOutlines->first_node());
     ConvertToOutlineFeatures(Outline, FeatureSet);
   }
   if (classify_norm_method == baseline) {
diff --git a/src/classify/picofeat.cpp b/src/classify/picofeat.cpp
index 6872263b..12303730 100644
--- a/src/classify/picofeat.cpp
+++ b/src/classify/picofeat.cpp
@@ -58,17 +58,13 @@ void NormalizePicoX(FEATURE_SET FeatureSet);
  * @return Pico-features for Blob.
  */
 FEATURE_SET Classify::ExtractPicoFeatures(TBLOB *Blob) {
-  LIST Outlines;
-  LIST RemainingOutlines;
-  MFOUTLINE Outline;
-  float XScale, YScale;
-
   auto FeatureSet = new FEATURE_SET_STRUCT(MAX_PICO_FEATURES);
-  Outlines = ConvertBlob(Blob);
+  auto Outlines = ConvertBlob(Blob);
+  float XScale, YScale;
   NormalizeOutlines(Outlines, &XScale, &YScale);
-  RemainingOutlines = Outlines;
+  auto RemainingOutlines = Outlines;
   iterate(RemainingOutlines) {
-    Outline = static_cast<MFOUTLINE> first_node(RemainingOutlines);
+    auto Outline = static_cast<MFOUTLINE>(RemainingOutlines->first_node());
     ConvertToPicoFeatures2(Outline, FeatureSet);
   }
   if (classify_norm_method == baseline) {
diff --git a/src/cutil/oldlist.cpp b/src/cutil/oldlist.cpp
index bcf3adc1..583dd4b3 100644
--- a/src/cutil/oldlist.cpp
+++ b/src/cutil/oldlist.cpp
@@ -77,18 +77,6 @@ static int is_same(void *item1, void *item2) {
   return strcmp(static_cast<char *>(item1), static_cast<char *>(item2)) == 0;
 }

-/**********************************************************************
- *  c o u n t
- *
- *  Recursively count the elements in  a list.  Return the count.
- **********************************************************************/
-int count(LIST var_list) {
-  int temp = 0;
-
-  iterate(var_list) temp += 1;
-  return (temp);
-}
-
 /**********************************************************************
  *  d e l e t e    d
  *
@@ -106,16 +94,16 @@ LIST delete_d(LIST list, void *key, int_compare is_equal) {
   }

   while (list != NIL_LIST) {
-    if (!(*is_equal)(first_node(list), key)) {
+    if (!(*is_equal)(list->first_node(), key)) {
       if (last_one == NIL_LIST) {
         last_one = list;
-        list = list_rest(list);
+        list = list->list_rest();
         result = last_one;
         set_rest(last_one, NIL_LIST);
       } else {
         set_rest(last_one, list);
         last_one = list;
-        list = list_rest(list);
+        list = list->list_rest();
         set_rest(last_one, NIL_LIST);
       }
     } else {
@@ -134,7 +122,7 @@ LIST destroy(LIST list) {
   LIST next;

   while (list != NIL_LIST) {
-    next = list_rest(list);
+    next = list->list_rest();
     delete list;
     list = next;
   }
@@ -150,8 +138,8 @@ void destroy_nodes(LIST list, void_dest destructor) {
   ASSERT_HOST(destructor != nullptr);

   while (list != NIL_LIST) {
-    if (first_node(list) != nullptr) {
-      (*destructor)(first_node(list));
+    if (list->first_node() != nullptr) {
+      (*destructor)(list->first_node());
     }
     list = pop(list);
   }
@@ -163,10 +151,10 @@ void destroy_nodes(LIST list, void_dest destructor) {
  *  Return the last list item (this is list type).
  **********************************************************************/
 LIST last(LIST var_list) {
-  while (list_rest(var_list) != NIL_LIST) {
-    var_list = list_rest(var_list);
+  while (var_list->list_rest() != NIL_LIST) {
+    var_list = var_list->list_rest();
   }
-  return (var_list);
+  return var_list;
 }

 /**********************************************************************
@@ -176,9 +164,9 @@ LIST last(LIST var_list) {
  *  that it occupied in the list.
  **********************************************************************/
 LIST pop(LIST list) {
-  LIST temp = list_rest(list);
+  LIST temp = list->list_rest();
   delete list;
-  return (temp);
+  return temp;
 }

 /**********************************************************************
@@ -225,7 +213,7 @@ LIST search(LIST list, void *key, int_compare is_equal) {
     is_equal = is_same;
   }

-  iterate(list) if ((*is_equal)(first_node(list), key)) return (list);
+  iterate(list) if ((*is_equal)(list->first_node(), key)) return list;
   return (NIL_LIST);
 }

diff --git a/src/cutil/oldlist.h b/src/cutil/oldlist.h
index 2e0cbb83..41ef1d05 100644
--- a/src/cutil/oldlist.h
+++ b/src/cutil/oldlist.h
@@ -64,6 +64,8 @@

 #include <tesseract/export.h>

+#include <cstddef> // for size_t
+
 namespace tesseract {

 /*----------------------------------------------------------------------
@@ -75,18 +77,9 @@ namespace tesseract {
 using int_compare = int (*)(void *, void *);
 using void_dest = void (*)(void *);

-struct list_rec {
-  list_rec *node;
-  list_rec *next;
-};
-using LIST = list_rec *;
-
 /*----------------------------------------------------------------------
                   M a c r o s
 ----------------------------------------------------------------------*/
-/* Predefinitions */
-#define list_rest(l) ((l) ? (l)->next : NIL_LIST)
-#define first_node(l) ((l) ? (l)->node : NIL_LIST)

 /**********************************************************************
  *  i t e r a t e
@@ -95,7 +88,7 @@ using LIST = list_rec *;
  *  minus the head.  Continue until the list is NIL_LIST.
  **********************************************************************/

-#define iterate(l) for (; (l) != NIL_LIST; (l) = list_rest(l))
+#define iterate(l) for (; (l) != nullptr; (l) = (l)->list_rest())

 /**********************************************************************
  *  s e t   r e s t
@@ -107,10 +100,33 @@ using LIST = list_rec *;

 #define set_rest(l, cell) ((l)->next = (cell))

+struct list_rec {
+  list_rec *node;
+  list_rec *next;
+
+  list_rec *first_node() {
+    return node;
+  }
+
+  list_rec *list_rest() {
+    return next;
+  }
+
+  //********************************************************************
+  // Recursively count the elements in  a list.  Return the count.
+  //********************************************************************
+  size_t size() {
+    auto var_list = this;
+    size_t n = 0;
+    iterate(var_list) n++;
+    return n;
+  }
+};
+using LIST = list_rec *;
+
 /*----------------------------------------------------------------------
           Public Function Prototypes
 ----------------------------------------------------------------------*/
-int count(LIST var_list);

 LIST delete_d(LIST list, void *key, int_compare is_equal);

diff --git a/src/training/cntraining.cpp b/src/training/cntraining.cpp
index 8d122ab7..a020ac16 100644
--- a/src/training/cntraining.cpp
+++ b/src/training/cntraining.cpp
@@ -139,7 +139,7 @@ int main(int argc, char *argv[]) {
   std::vector<LIST> freeable_protos;
   iterate(pCharList) {
     // Cluster
-    CharSample = reinterpret_cast<LABELEDLIST> first_node(pCharList);
+    CharSample = reinterpret_cast<LABELEDLIST>(pCharList->first_node());
     Clusterer = SetUpForClustering(FeatureDefs, CharSample, PROGRAM_FEATURE_TYPE);
     if (Clusterer == nullptr) { // To avoid a SIGSEGV
       fprintf(stderr, "Error: nullptr clusterer!\n");
@@ -209,7 +209,7 @@ static void WriteNormProtos(const char *Directory, LIST LabeledProtoList,
   fprintf(File, "%0d\n", feature_desc->NumParams);
   WriteParamDesc(File, feature_desc->NumParams, feature_desc->ParamDesc);
   iterate(LabeledProtoList) {
-    LabeledProto = reinterpret_cast<LABELEDLIST> first_node(LabeledProtoList);
+    LabeledProto = reinterpret_cast<LABELEDLIST>(LabeledProtoList->first_node());
     N = NumberOfProtos(LabeledProto->List, true, false);
     if (N < 1) {
       printf(
@@ -235,7 +235,7 @@ static void WriteProtos(FILE *File, uint16_t N, LIST ProtoList, bool WriteSigPro

   // write prototypes
   iterate(ProtoList) {
-    Proto = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
+    Proto = reinterpret_cast<PROTOTYPE *>(ProtoList->first_node());
     if ((Proto->Significant && WriteSigProtos) || (!Proto->Significant && WriteInsigProtos)) {
       WritePrototype(File, N, Proto);
     }
diff --git a/src/training/common/commontraining.cpp b/src/training/common/commontraining.cpp
index 898a7784..f225f789 100644
--- a/src/training/common/commontraining.cpp
+++ b/src/training/common/commontraining.cpp
@@ -324,7 +324,7 @@ LABELEDLIST FindList(LIST List, const std::string &Label) {
   LABELEDLIST LabeledList;

   iterate(List) {
-    LabeledList = reinterpret_cast<LABELEDLIST> first_node(List);
+    LabeledList = reinterpret_cast<LABELEDLIST>(List->first_node());
     if (LabeledList->Label == Label) {
       return (LabeledList);
     }
@@ -360,7 +360,7 @@ void ReadTrainingSamples(const FEATURE_DEFS_STRUCT &feature_definitions, const c
   // Zero out the font_sample_count for all the classes.
   LIST it = *training_samples;
   iterate(it) {
-    char_sample = reinterpret_cast<LABELEDLIST>(first_node(it));
+    char_sample = reinterpret_cast<LABELEDLIST>(it->first_node());
     char_sample->font_sample_count = 0;
   }

@@ -415,10 +415,10 @@ void FreeTrainingSamples(LIST CharList) {

   LIST nodes = CharList;
   iterate(CharList) { /* iterate through all of the fonts */
-    char_sample = reinterpret_cast<LABELEDLIST> first_node(CharList);
+    char_sample = reinterpret_cast<LABELEDLIST>(CharList->first_node());
     FeatureList = char_sample->List;
     iterate(FeatureList) { /* iterate through all of the classes */
-      FeatureSet = reinterpret_cast<FEATURE_SET> first_node(FeatureList);
+      FeatureSet = reinterpret_cast<FEATURE_SET>(FeatureList->first_node());
       delete FeatureSet;
     }
     FreeLabeledList(char_sample);
@@ -467,7 +467,7 @@ CLUSTERER *SetUpForClustering(const FEATURE_DEFS_STRUCT &FeatureDefs, LABELEDLIS
   CharID = 0;
   std::vector<float> Sample;
   iterate(FeatureList) {
-    FeatureSet = reinterpret_cast<FEATURE_SET> first_node(FeatureList);
+    FeatureSet = reinterpret_cast<FEATURE_SET>(FeatureList->first_node());
     for (int i = 0; i < FeatureSet->MaxNumFeatures; i++) {
       if (Sample.empty()) {
         Sample.resize(N);
@@ -491,7 +491,7 @@ void MergeInsignificantProtos(LIST ProtoList, const char *label, CLUSTERER *Clus

   LIST pProtoList = ProtoList;
   iterate(pProtoList) {
-    Prototype = reinterpret_cast<PROTOTYPE *> first_node(pProtoList);
+    Prototype = reinterpret_cast<PROTOTYPE *>(pProtoList->first_node());
     if (Prototype->Significant || Prototype->Merged) {
       continue;
     }
@@ -500,7 +500,7 @@ void MergeInsignificantProtos(LIST ProtoList, const char *label, CLUSTERER *Clus
     // Find the nearest alive prototype.
     LIST list_it = ProtoList;
     iterate(list_it) {
-      auto *test_p = reinterpret_cast<PROTOTYPE *> first_node(list_it);
+      auto *test_p = reinterpret_cast<PROTOTYPE *>(list_it->first_node());
       if (test_p != Prototype && !test_p->Merged) {
         float dist = ComputeDistance(Clusterer->SampleSize, Clusterer->ParamDesc, &Prototype->Mean[0],
                                      &test_p->Mean[0]);
@@ -533,7 +533,7 @@ void MergeInsignificantProtos(LIST ProtoList, const char *label, CLUSTERER *Clus
   int min_samples = static_cast<int32_t>(clusterconfig->MinSamples * Clusterer->NumChar);
   pProtoList = ProtoList;
   iterate(pProtoList) {
-    Prototype = reinterpret_cast<PROTOTYPE *> first_node(pProtoList);
+    Prototype = reinterpret_cast<PROTOTYPE *>(pProtoList->first_node());
     // Process insignificant protos that do not match a green one
     if (!Prototype->Significant && Prototype->NumSamples >= min_samples && !Prototype->Merged) {
       if (debug) {
@@ -549,7 +549,7 @@ void CleanUpUnusedData(LIST ProtoList) {
   PROTOTYPE *Prototype;

   iterate(ProtoList) {
-    Prototype = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
+    Prototype = reinterpret_cast<PROTOTYPE *>(ProtoList->first_node());
     delete[] Prototype->Variance.Elliptical;
     Prototype->Variance.Elliptical = nullptr;
     delete[] Prototype->Magnitude.Elliptical;
@@ -566,7 +566,7 @@ LIST RemoveInsignificantProtos(LIST ProtoList, bool KeepSigProtos, bool KeepInsi
   LIST NewProtoList = NIL_LIST;
   auto pProtoList = ProtoList;
   iterate(pProtoList) {
-    auto Proto = reinterpret_cast<PROTOTYPE *> first_node(pProtoList);
+    auto Proto = reinterpret_cast<PROTOTYPE *>(pProtoList->first_node());
     if ((Proto->Significant && KeepSigProtos) || (!Proto->Significant && KeepInsigProtos)) {
       auto NewProto = new PROTOTYPE;
       NewProto->Mean = Proto->Mean;
@@ -617,7 +617,7 @@ MERGE_CLASS FindClass(LIST List, const std::string &Label) {
   MERGE_CLASS MergeClass;

   iterate(List) {
-    MergeClass = reinterpret_cast<MERGE_CLASS> first_node(List);
+    MergeClass = reinterpret_cast<MERGE_CLASS>(List->first_node());
     if (MergeClass->Label == Label) {
       return (MergeClass);
     }
@@ -638,7 +638,7 @@ void FreeLabeledClassList(LIST ClassList) {
   LIST nodes = ClassList;
   iterate(ClassList) /* iterate through all of the fonts */
   {
-    MergeClass = reinterpret_cast<MERGE_CLASS> first_node(ClassList);
+    MergeClass = reinterpret_cast<MERGE_CLASS>(ClassList->first_node());
     FreeClass(MergeClass->Class);
     delete MergeClass;
   }
@@ -665,7 +665,7 @@ CLASS_STRUCT *SetUpForFloat2Int(const UNICHARSET &unicharset, LIST LabeledClassL
   auto *float_classes = new CLASS_STRUCT[unicharset.size()];
   iterate(LabeledClassList) {
     UnicityTable<int> font_set;
-    MergeClass = reinterpret_cast<MERGE_CLASS> first_node(LabeledClassList);
+    MergeClass = reinterpret_cast<MERGE_CLASS>(LabeledClassList->first_node());
     Class = &float_classes[unicharset.unichar_to_id(MergeClass->Label.c_str())];
     NumProtos = MergeClass->Class->NumProtos;
     NumConfigs = MergeClass->Class->NumConfigs;
@@ -730,7 +730,7 @@ void FreeNormProtoList(LIST CharList)
   LIST nodes = CharList;
   iterate(CharList) /* iterate through all of the fonts */
   {
-    char_sample = reinterpret_cast<LABELEDLIST> first_node(CharList);
+    char_sample = reinterpret_cast<LABELEDLIST>(CharList->first_node());
     FreeLabeledList(char_sample);
   }
   destroy(nodes);
@@ -741,7 +741,7 @@ void FreeNormProtoList(LIST CharList)
 void AddToNormProtosList(LIST *NormProtoList, LIST ProtoList, const std::string &CharName) {
   auto LabeledProtoList = new LABELEDLISTNODE(CharName.c_str());
   iterate(ProtoList) {
-    auto Proto = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
+    auto Proto = reinterpret_cast<PROTOTYPE *>(ProtoList->first_node());
     LabeledProtoList->List = push(LabeledProtoList->List, Proto);
   }
   *NormProtoList = push(*NormProtoList, LabeledProtoList);
@@ -751,7 +751,7 @@ void AddToNormProtosList(LIST *NormProtoList, LIST ProtoList, const std::string
 int NumberOfProtos(LIST ProtoList, bool CountSigProtos, bool CountInsigProtos) {
   int N = 0;
   iterate(ProtoList) {
-    auto *Proto = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
+    auto *Proto = reinterpret_cast<PROTOTYPE *>(ProtoList->first_node());
     if ((Proto->Significant && CountSigProtos) || (!Proto->Significant && CountInsigProtos)) {
       N++;
     }
diff --git a/src/training/mftraining.cpp b/src/training/mftraining.cpp
index 14ccb13b..d0975c37 100644
--- a/src/training/mftraining.cpp
+++ b/src/training/mftraining.cpp
@@ -58,7 +58,7 @@ static void DisplayProtoList(const char *ch, LIST protolist) {
   auto window = std::make_unique<ScrollView>("Char samples", 50, 200, 520, 520, 260, 260, true);
   LIST proto = protolist;
   iterate(proto) {
-    auto *prototype = reinterpret_cast<PROTOTYPE *>(first_node(proto));
+    auto *prototype = reinterpret_cast<PROTOTYPE *>(proto->first_node());
     if (prototype->Significant) {
       window->Pen(ScrollView::GREEN);
     } else if (prototype->NumSamples == 0) {
@@ -116,7 +116,7 @@ static LIST ClusterOneConfig(int shape_id, const char *class_label, LIST mf_clas
   merge_class->Class->font_set.push_back(shape_id);
   LIST proto_it = proto_list;
   iterate(proto_it) {
-    auto *prototype = reinterpret_cast<PROTOTYPE *>(first_node(proto_it));
+    auto *prototype = reinterpret_cast<PROTOTYPE *>(proto_it->first_node());
     // See if proto can be approximated by existing proto.
     int p_id = FindClosestExistingProto(merge_class->Class, merge_class->NumMerged, prototype);
     if (p_id == NO_PROTO) {
diff --git a/src/wordrec/plotedges.cpp b/src/wordrec/plotedges.cpp
index 3054b9d7..67944e41 100644
--- a/src/wordrec/plotedges.cpp
+++ b/src/wordrec/plotedges.cpp
@@ -55,7 +55,7 @@ void display_edgepts(LIST outlines) {
   auto window = edge_window;
   /* Reclaim old memory */
   iterate(outlines) {
-    render_edgepts(window, reinterpret_cast<EDGEPT *> first_node(outlines), ScrollView::WHITE);
+    render_edgepts(window, reinterpret_cast<EDGEPT *>(outlines->first_node()), ScrollView::WHITE);
   }
 }