Commit 4b82ea11 for tesseract

commit 4b82ea11820975003ed898c90cf3dde39c630a8a
Author: Stefan Weil <sw@weilnetz.de>
Date:   Sat Aug 15 17:07:23 2026 +0200

    Fix Coverity warnings (Variable copied when it could be moved)

    Coverity reported 18 warnings of type 'Variable copied when it could be
    moved' in the following files:
    - src/api/baseapi.cpp
    - src/ccmain/paragraphs.cpp
    - src/ccmain/tessedit.cpp
    - src/ccstruct/blamer.cpp
    - src/ccstruct/boxread.cpp
    - src/ccutil/helpers.h
    - src/classify/shapetable.cpp
    - src/dict/trie.cpp
    - src/lstm/plumbing.cpp
    - src/lstm/recodebeam.cpp
    - src/training/pango/pango_font_info.cpp
    - unittest/imagedata_test.cc
    - unittest/paragraphs_test.cc

    Fix them by using std::move where the source variable is not used
    afterwards, and add the missing include of <utility>.

    Assisted-by: OpenCode / big-pickle (opencode)
    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/api/baseapi.cpp b/src/api/baseapi.cpp
index 0c162837..712f6a5d 100644
--- a/src/api/baseapi.cpp
+++ b/src/api/baseapi.cpp
@@ -889,7 +889,7 @@ bool TessBaseAPI::ProcessPagesFileList(FILE *flist, std::string *buf, const char
     std::string line;
     for (const auto ch : *buf) {
       if (ch == '\n') {
-        lines.push_back(line);
+        lines.push_back(std::move(line));
         line.clear();
       } else {
         line.push_back(ch);
@@ -897,7 +897,7 @@ bool TessBaseAPI::ProcessPagesFileList(FILE *flist, std::string *buf, const char
     }
     if (!line.empty()) {
       // Add last line without terminating LF.
-      lines.push_back(line);
+      lines.push_back(std::move(line));
     }
     if (lines.empty()) {
       return false;
diff --git a/src/ccmain/paragraphs.cpp b/src/ccmain/paragraphs.cpp
index 012fc62d..15b9fde2 100644
--- a/src/ccmain/paragraphs.cpp
+++ b/src/ccmain/paragraphs.cpp
@@ -547,7 +547,7 @@ void RowScratchRegisters::AppendDebugInfo(const ParagraphTheory &theory,
     model_string += "0";
   }

-  dbg.push_back(model_string);
+  dbg.push_back(std::move(model_string));
 }

 void RowScratchRegisters::Init(const RowInfo &row) {
diff --git a/src/ccmain/tessedit.cpp b/src/ccmain/tessedit.cpp
index 7ec89bd9..412b8c15 100644
--- a/src/ccmain/tessedit.cpp
+++ b/src/ccmain/tessedit.cpp
@@ -286,7 +286,7 @@ void Tesseract::ParseLanguageString(const std::string &lang_str, std::vector<std
     lang_code = prefix + lang_code;
     // Check whether lang_code is already in the target vector and add.
     if (!IsStrInList(lang_code, *target)) {
-      target->push_back(lang_code);
+      target->push_back(std::move(lang_code));
     }
   }
 }
diff --git a/src/ccstruct/blamer.cpp b/src/ccstruct/blamer.cpp
index 77a323b3..7c3dec3b 100644
--- a/src/ccstruct/blamer.cpp
+++ b/src/ccstruct/blamer.cpp
@@ -79,7 +79,7 @@ void BlamerBundle::SetWordTruth(const UNICHARSET &unicharset, const char *truth_
     if (id != INVALID_UNICHAR_ID) {
       uch = unicharset.get_normed_unichar(id);
     }
-    truth_text_.push_back(uch);
+    truth_text_.push_back(std::move(uch));
   }
 }

@@ -96,7 +96,7 @@ void BlamerBundle::SetSymbolTruth(const UNICHARSET &unicharset, const char *char
     }
   }
   int length = truth_word_.length();
-  truth_text_.push_back(symbol_str);
+  truth_text_.push_back(std::move(symbol_str));
   truth_word_.InsertBox(length, char_box);
   if (length == 0) {
     truth_has_char_boxes_ = true;
diff --git a/src/ccstruct/boxread.cpp b/src/ccstruct/boxread.cpp
index 1a208661..8b8703d7 100644
--- a/src/ccstruct/boxread.cpp
+++ b/src/ccstruct/boxread.cpp
@@ -31,6 +31,7 @@
 #include <locale>  // for std::locale::classic
 #include <sstream> // for std::stringstream
 #include <string>  // for std::string
+#include <utility> // for std::move

 namespace tesseract {

@@ -130,7 +131,7 @@ bool ReadMemBoxes(int target_page, bool skip_blanks, const char *box_data, bool
     if (box_texts != nullptr) {
       std::string full_text;
       MakeBoxFileStr(utf8_str.c_str(), box, target_page, full_text);
-      box_texts->push_back(full_text);
+      box_texts->push_back(std::move(full_text));
     }
     if (pages != nullptr) {
       pages->push_back(page);
diff --git a/src/ccutil/helpers.h b/src/ccutil/helpers.h
index 0bedade1..414fd073 100644
--- a/src/ccutil/helpers.h
+++ b/src/ccutil/helpers.h
@@ -26,6 +26,7 @@
 #include <cstdio>
 #include <algorithm>  // for std::find
 #include <string>
+#include <utility>    // for std::move
 #include <vector>

 #include "serialis.h"
@@ -55,12 +56,12 @@ inline const std::vector<std::string> split(const std::string &s, char c) {
     if (n != c) {
       buff += n;
     } else if (n == c && !buff.empty()) {
-      v.push_back(buff);
+      v.push_back(std::move(buff));
       buff.clear();
     }
   }
   if (!buff.empty()) {
-    v.push_back(buff);
+    v.push_back(std::move(buff));
   }
   return v;
 }
diff --git a/src/classify/shapetable.cpp b/src/classify/shapetable.cpp
index cf3ec60b..7fb1e072 100644
--- a/src/classify/shapetable.cpp
+++ b/src/classify/shapetable.cpp
@@ -28,6 +28,7 @@
 #include "unicity_table.h"

 #include <algorithm>
+#include <utility> // for std::move

 namespace tesseract {

@@ -743,7 +744,7 @@ int ShapeTable::AddUnicharToResults(int unichar_id, float rating, std::vector<in
   if (result_index < 0) {
     UnicharRating result(unichar_id, rating);
     result_index = results->size();
-    results->push_back(result);
+    results->push_back(std::move(result));
     (*unichar_map)[unichar_id] = result_index;
   }
   return result_index;
diff --git a/src/dict/trie.cpp b/src/dict/trie.cpp
index 3ba415e3..703ccd14 100644
--- a/src/dict/trie.cpp
+++ b/src/dict/trie.cpp
@@ -27,6 +27,8 @@
 #include "helpers.h"
 #include "kdpair.h"

+#include <utility> // for std::move
+
 namespace tesseract {

 const char kDoNotReverse[] = "RRP_DO_NO_REVERSE";
@@ -298,7 +300,7 @@ bool Trie::read_word_list(const char *filename, std::vector<std::string> *words)
     if (debug_level_ && word_count % 10000 == 0) {
       tprintf("Read %d words so far\n", word_count);
     }
-    words->push_back(word_str);
+    words->push_back(std::move(word_str));
   }
   if (debug_level_) {
     tprintf("Read %d words total.\n", word_count);
diff --git a/src/lstm/plumbing.cpp b/src/lstm/plumbing.cpp
index f0133148..7288bd02 100644
--- a/src/lstm/plumbing.cpp
+++ b/src/lstm/plumbing.cpp
@@ -18,6 +18,8 @@

 #include "plumbing.h"

+#include <utility> // for std::move
+
 namespace tesseract {

 // ni_ and no_ will be set by AddToStack.
@@ -152,7 +154,7 @@ void Plumbing::EnumerateLayers(const std::string *prefix, std::vector<std::strin
       auto *plumbing = static_cast<Plumbing *>(stack_[i]);
       plumbing->EnumerateLayers(&layer_name, layers);
     } else {
-      layers.push_back(layer_name);
+      layers.push_back(std::move(layer_name));
     }
   }
 }
diff --git a/src/lstm/recodebeam.cpp b/src/lstm/recodebeam.cpp
index 2bf5d9a2..affce775 100644
--- a/src/lstm/recodebeam.cpp
+++ b/src/lstm/recodebeam.cpp
@@ -24,6 +24,7 @@
 #include "unicharcompress.h"

 #include <algorithm> // for std::reverse
+#include <utility>   // for std::move

 namespace tesseract {

@@ -157,7 +158,7 @@ void RecodeBeamSearch::SaveMostCertainChoices(const float *outputs,
                      std::pair<const char *, float>(character, outputs[i]));
     }
   }
-  timesteps.push_back(choices);
+  timesteps.push_back(std::move(choices));
 }

 void RecodeBeamSearch::segmentTimestepsByCharacters() {
@@ -167,7 +168,7 @@ void RecodeBeamSearch::segmentTimestepsByCharacters() {
          ++j) {
       segment.push_back(timesteps[j]);
     }
-    segmentedTimesteps.push_back(segment);
+    segmentedTimesteps.push_back(std::move(segment));
   }
 }
 std::vector<std::vector<std::pair<const char *, float>>>
@@ -334,7 +335,7 @@ void RecodeBeamSearch::PrintBeam2(bool uids,
   // create the topology
   for (int step = beam.size() - 1; step >= 0; --step) {
     std::vector<const RecodeNode *> layer;
-    topology.push_back(layer);
+    topology.push_back(std::move(layer));
   }
   // fill the topology with depths first
   for (int step = beam.size() - 1; step >= 0; --step) {
@@ -475,7 +476,7 @@ void RecodeBeamSearch::extractSymbolChoices(const UNICHARSET *unicharset) {
           excludedUnichars[j - 1].insert(elem);
         }
       } else {
-        excludedUnichars.push_back(excludeCodeList);
+        excludedUnichars.push_back(std::move(excludeCodeList));
       }
       // Save the best choice for the choice iterator.
       if (j - 1 < ctc_choices.size()) {
@@ -490,17 +491,17 @@ void RecodeBeamSearch::extractSymbolChoices(const UNICHARSET *unicharset) {
         const char *result = unicharset->id_to_unichar_ext(id);
         float rating = ratings[bestPos];
         choice.emplace_back(result, rating);
-        ctc_choices.push_back(choice);
+        ctc_choices.push_back(std::move(choice));
       }
       // fill the blank spot with an empty array
     } else {
       if (j - 1 >= excludedUnichars.size()) {
         std::unordered_set<int> excludeCodeList;
-        excludedUnichars.push_back(excludeCodeList);
+        excludedUnichars.push_back(std::move(excludeCodeList));
       }
       if (j - 1 >= ctc_choices.size()) {
         std::vector<std::pair<const char *, float>> choice;
-        ctc_choices.push_back(choice);
+        ctc_choices.push_back(std::move(choice));
       }
     }
   }
diff --git a/src/training/pango/pango_font_info.cpp b/src/training/pango/pango_font_info.cpp
index e3a681ce..42ae3921 100644
--- a/src/training/pango/pango_font_info.cpp
+++ b/src/training/pango/pango_font_info.cpp
@@ -43,6 +43,7 @@
 #include <cstdlib>
 #include <cstring>
 #include <string_view>
+#include <utility> // for std::move

 #ifndef _MSC_VER
 #  include <sys/param.h>
@@ -647,7 +648,7 @@ std::string FontUtils::BestFonts(const std::unordered_map<char32, int64_t> &ch_m
     most_ok_chars = std::max(ok_chars, most_ok_chars);
     best_raw_score = std::max(raw_score, best_raw_score);

-    font_flags.push_back(ch_flags);
+    font_flags.push_back(std::move(ch_flags));
     font_scores.push_back(ok_chars);
     raw_scores.push_back(raw_score);
   }
@@ -669,7 +670,7 @@ std::string FontUtils::BestFonts(const std::unordered_map<char32, int64_t> &ch_m
     int score = font_scores[i];
     int raw_score = raw_scores[i];
     if ((score >= least_good_enough && raw_score >= least_raw_enough) || score >= override_enough) {
-      fonts->push_back(std::make_pair(font_names[i].c_str(), font_flags[i]));
+      fonts->push_back(std::make_pair(font_names[i].c_str(), std::move(font_flags[i])));
       tlog(1, "OK font %s = %.4f%%, raw = %d = %.2f%%\n", font_names[i].c_str(),
            100.0 * score / most_ok_chars, raw_score, 100.0 * raw_score / best_raw_score);
       font_list += font_names[i];
diff --git a/unittest/imagedata_test.cc b/unittest/imagedata_test.cc
index 2b185ef9..1f74d638 100644
--- a/unittest/imagedata_test.cc
+++ b/unittest/imagedata_test.cc
@@ -10,6 +10,7 @@
 // limitations under the License.

 #include <string>
+#include <utility> // for std::move
 #include <vector>

 #include "imagedata.h"
@@ -97,7 +98,7 @@ TEST_F(ImagedataTest, CachesMultiDocs) {
   for (size_t d = 0; d < kNumPages.size(); ++d) {
     page_texts.emplace_back(std::vector<std::string>());
     std::string filename = MakeFakeDoc(kNumPages[d], d, &page_texts.back());
-    filenames.push_back(filename);
+    filenames.push_back(std::move(filename));
   }
   // Now try getting them back with different cache strategies and check that
   // the pages come out in the right order.
diff --git a/unittest/paragraphs_test.cc b/unittest/paragraphs_test.cc
index 340f734b..39ae5efe 100644
--- a/unittest/paragraphs_test.cc
+++ b/unittest/paragraphs_test.cc
@@ -9,7 +9,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.

-#include <string> // for std::string
+#include <string>  // for std::string
+#include <utility> // for std::move

 #include "include_gunit.h" // for TEST
 #include "log.h"           // for LOG
@@ -156,7 +157,7 @@ void EvaluateParagraphDetection(const TextAndModel *correct, int n,
                         correct[i].model.ToString() +
                         (correct[i].is_very_first_or_continuation ? " crown" : "") +
                         (correct[i].is_list_item ? " li" : "");
-        dbg_lines.push_back(s);
+        dbg_lines.push_back(std::move(s));
       } else {
         dbg_lines.emplace_back(correct[i].ascii);
       }
@@ -178,7 +179,7 @@ void EvaluateParagraphDetection(const TextAndModel *correct, int n,
         }
       }
       std::string s = correct[i].ascii + annotation;
-      dbg_lines.push_back(s);
+      dbg_lines.push_back(std::move(s));
     }
     std::string s;
     for (auto &dbg_line : dbg_lines) {