diff --git a/include/tesseract/baseapi.h b/include/tesseract/baseapi.h index dd9fe4a299..510827de14 100644 --- a/include/tesseract/baseapi.h +++ b/include/tesseract/baseapi.h @@ -161,6 +161,17 @@ class TESS_API TessBaseAPI { */ void PrintVariables(FILE *fp) const; + /* + * Report parameters' usage statistics, i.e. report which params have been + * set, modified and read/checked until now during this run-time's lifetime. + * + * Use this method for run-time 'discovery' about which tesseract parameters + * are actually *used* during your particular usage of the library, ergo + * answering the question: + * "Which of all those parameters are actually *relevant* to my use case today?" + */ + void ReportParamsUsageStatistics() const; + /** * Get value of named variable as a string, if it exists. */ diff --git a/src/api/baseapi.cpp b/src/api/baseapi.cpp index f78894ce74..c089ebcfd7 100644 --- a/src/api/baseapi.cpp +++ b/src/api/baseapi.cpp @@ -292,8 +292,8 @@ bool TessBaseAPI::SetDebugVariable(const char *name, const char *value) { } bool TessBaseAPI::GetIntVariable(const char *name, int *value) const { - auto *p = ParamUtils::FindParam(name, GlobalParams()->int_params, - tesseract_->params()->int_params); + auto *p = ParamUtils::FindParam(name, GlobalParams()->int_params(), + tesseract_->params()->int_params()); if (p == nullptr) { return false; } @@ -302,8 +302,8 @@ bool TessBaseAPI::GetIntVariable(const char *name, int *value) const { } bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const { - auto *p = ParamUtils::FindParam(name, GlobalParams()->bool_params, - tesseract_->params()->bool_params); + auto *p = ParamUtils::FindParam(name, GlobalParams()->bool_params(), + tesseract_->params()->bool_params()); if (p == nullptr) { return false; } @@ -312,14 +312,14 @@ bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const { } const char *TessBaseAPI::GetStringVariable(const char *name) const { - auto *p = ParamUtils::FindParam(name, GlobalParams()->string_params, - tesseract_->params()->string_params); + auto *p = ParamUtils::FindParam(name, GlobalParams()->string_params(), + tesseract_->params()->string_params()); return (p != nullptr) ? p->c_str() : nullptr; } bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const { - auto *p = ParamUtils::FindParam(name, GlobalParams()->double_params, - tesseract_->params()->double_params); + auto *p = ParamUtils::FindParam(name, GlobalParams()->double_params(), + tesseract_->params()->double_params()); if (p == nullptr) { return false; } @@ -357,6 +357,19 @@ void TessBaseAPI::PrintVariables(FILE *fp) const { ParamUtils::PrintParams(fp, tesseract_->params()); } +// Report parameters' usage statistics, i.e. report which params have been +// set, modified and read/checked until now during this run-time's lifetime. +// +// Use this method for run-time 'discovery' about which tesseract parameters +// are actually *used* during your particular usage of the library, ergo +// answering the question: +// "Which of all those parameters are actually *relevant* to my use case today?" +void TessBaseAPI::ReportParamsUsageStatistics() const { + tesseract::ParamsVectors *vec = tesseract_->params(); + + ParamUtils::ReportParamsUsageStatistics(vec); +} + /** * The datapath must be the name of the data directory or * some other file in which the data directory resides (for instance argv[0].) diff --git a/src/ccmain/paramsd.cpp b/src/ccmain/paramsd.cpp index 60de457b32..83a9c4020e 100644 --- a/src/ccmain/paramsd.cpp +++ b/src/ccmain/paramsd.cpp @@ -212,16 +212,16 @@ SVMenuNode *ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) { int num_iterations = (tess->params() == nullptr) ? 1 : 2; for (int v = 0; v < num_iterations; ++v) { tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params(); - for (auto ¶m : vec->int_params) { + for (auto ¶m : vec->int_params()) { vc_it.add_after_then_move(new ParamContent(param)); } - for (auto ¶m : vec->bool_params) { + for (auto ¶m : vec->bool_params()) { vc_it.add_after_then_move(new ParamContent(param)); } - for (auto ¶m : vec->string_params) { + for (auto ¶m : vec->string_params()) { vc_it.add_after_then_move(new ParamContent(param)); } - for (auto ¶m : vec->double_params) { + for (auto ¶m : vec->double_params()) { vc_it.add_after_then_move(new ParamContent(param)); } } diff --git a/src/ccutil/params.cpp b/src/ccutil/params.cpp index c4e087f08a..2b3d7d51bd 100644 --- a/src/ccutil/params.cpp +++ b/src/ccutil/params.cpp @@ -18,11 +18,14 @@ #include "params.h" -#include "helpers.h" // for chomp_string +#include "helpers.h" // for chomp_string, mupdf imports, etc.: see also the header collision comment in there (MSVC-specific). #include "host.h" // tesseract/export.h, windows.h for MAX_PATH #include "serialis.h" // for TFile #include "tprintf.h" +#include +#include + #include // for INT_MIN, INT_MAX #include // for NAN, std::isnan #include @@ -31,10 +34,12 @@ #include // for std::locale::classic #include // for std::stringstream + namespace tesseract { +TESS_API tesseract::ParamsVectors *GlobalParams() { - static tesseract::ParamsVectors global_params = tesseract::ParamsVectors(); + static tesseract::ParamsVectors global_params; // static auto-inits at startup return &global_params; } @@ -42,7 +47,7 @@ bool ParamUtils::ReadParamsFile(const char *file, SetParamConstraint constraint, ParamsVectors *member_params) { TFile fp; if (!fp.Open(file, nullptr)) { - tprintf("read_params_file: Can't open %s\n", file); + tprintf("ERROR: read_params_file: Can't open file {}\n", file); return true; } return ReadParamsFromFp(constraint, &fp, member_params); @@ -71,18 +76,157 @@ bool ParamUtils::ReadParamsFromFp(SetParamConstraint constraint, TFile *fp, if (!foundit) { anyerr = true; // had an error - tprintf("Warning: Parameter not found: %s\n", line); + tprintf("WARNING: Parameter not found: {}\n", line); } } } return anyerr; } +void ParamUtils::ReportParamsUsageStatistics(const ParamsVectors *member_params) +{ + std::string report_path = vars_report_file; + FILE* f = nullptr; + + if (report_path == "stdout" || report_path == "-" || report_path == "1") + f = stdout; + else if (report_path == "stdeerr" || report_path == "+" || report_path == "2") + f = stderr; + else if (!report_path.empty()) + { +#if defined(HAVE_MUPDF) + fz_context* ctx = fz_get_global_context(); + fz_mkdir_for_file(ctx, report_path.c_str()); + f = fz_fopen_utf8(ctx, report_path.c_str(), "w"); +#else + f = fopen(report_path.c_str(), "w"); +#endif + if (!f) + { + tprintf("ERROR: Cannot produce paramater usage report file: {}\n", report_path); + } + } + + if (!f) + return; + + fprintf(f, "\n\nTesseract Parameter Usage Statistics: which params have been relevant?\n" + "----------------------------------------------------------------------\n\n"); + + // first collect all parameter names: + + typedef enum { + INT_PARAM = 0, + BOOL_PARAM, + DOUBLE_PARAM, + STRING_PARAM, + } param_type_t; + + typedef struct param_info { + const char* name; + bool global; + param_type_t type; + const Param* ref; + } param_info_t; + + std::vector param_names; + + if (member_params != nullptr) { + for (auto p : member_params->int_params_c()) { + param_names.push_back({ p->name_str(), false, INT_PARAM, p }); + } + for (auto p : member_params->bool_params_c()) { + param_names.push_back({ p->name_str(), false, BOOL_PARAM, p }); + } + for (auto p : member_params->string_params_c()) { + param_names.push_back({ p->name_str(), false, STRING_PARAM, p }); + } + for (auto p : member_params->double_params_c()) { + param_names.push_back({ p->name_str(), false, DOUBLE_PARAM, p }); + } + } + + const ParamsVectors* globals = GlobalParams(); + + for (auto p : globals->int_params_c()) { + param_names.push_back({ p->name_str(), true, INT_PARAM, p }); + } + for (auto p : globals->bool_params_c()) { + param_names.push_back({ p->name_str(), true, BOOL_PARAM, p }); + } + for (auto p : globals->string_params_c()) { + param_names.push_back({ p->name_str(), true, STRING_PARAM, p }); + } + for (auto p : globals->double_params_c()) { + param_names.push_back({ p->name_str(), true, DOUBLE_PARAM, p }); + } + + sort(param_names.begin(), param_names.end(), [](param_info_t& a, param_info_t& b) + { + int rv = strcmp(b.name, a.name); + if (rv == 0) + { + rv = (int) b.global - (int) a.global; + } +#if !defined(NDEBUG) + if (rv == 0) + { + fprintf(stderr, "Apparently you have double-defined Tesseract Variable: '%s'! Fix that in the source code!\n", a.name); + ASSEERT0(!"Apparently you have double-defined a Tesseract Variable."); + } +#endif + return rv >= 0; + }); + + static const char* type_map[] = { "[Integer]", "[Boolean]", "[Float]", "[String]" }; + static const char* categories[] = { "(Global)", "(Local)" }; + static const char* write_access[] = { ".", "w", "W" }; + static const char* read_access[] = { ".", "r", "R" }; + + auto acc = [](int access) { + if (access > 2) + access = 2; + return access; + }; + + for (auto item : param_names) { + const Param* p = item.ref; + auto stats = p->access_counts(); + if (stats.reading > 0) + { + fmt::print(f, "* {:.<60} {:8} {}{} {:9} = {}\n", p->name_str(), categories[item.global], write_access[acc(stats.writing)], read_access[acc(stats.reading)], type_map[item.type], p->formatted_value_str()); + } + } + + if (report_all_variables) + { + fprintf(f, "\n\nUnused parameters:\n\n"); + + for (auto item : param_names) { + const Param* p = item.ref; + auto stats = p->access_counts(); + if (stats.reading <= 0) + { + fmt::print(f, "* {:.<60} {:8} {}{} {:9} = {}\n", p->name_str(), categories[item.global], write_access[acc(stats.writing)], read_access[acc(stats.reading)], type_map[item.type], p->formatted_value_str()); + } + } + } + + if (f != stdout) + { + fclose(f); + } + else + { + fflush(stdout); + } +} + bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstraint constraint, ParamsVectors *member_params) { // Look for the parameter among string parameters. auto *sp = - FindParam(name, GlobalParams()->string_params, member_params->string_params); + FindParam(name, GlobalParams()->string_params(), member_params->string_params()); if (sp != nullptr && sp->constraint_ok(constraint)) { sp->set_value(value); } @@ -91,7 +235,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain } // Look for the parameter among int parameters. - auto *ip = FindParam(name, GlobalParams()->int_params, member_params->int_params); + auto *ip = FindParam(name, GlobalParams()->int_params(), member_params->int_params()); if (ip && ip->constraint_ok(constraint)) { int intval = INT_MIN; std::stringstream stream(value); @@ -103,7 +247,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain } // Look for the parameter among bool parameters. - auto *bp = FindParam(name, GlobalParams()->bool_params, member_params->bool_params); + auto *bp = FindParam(name, GlobalParams()->bool_params(), member_params->bool_params()); if (bp != nullptr && bp->constraint_ok(constraint)) { if (*value == 'T' || *value == 't' || *value == 'Y' || *value == 'y' || *value == '1') { bp->set_value(true); @@ -114,7 +258,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain // Look for the parameter among double parameters. auto *dp = - FindParam(name, GlobalParams()->double_params, member_params->double_params); + FindParam(name, GlobalParams()->double_params(), member_params->double_params()); if (dp != nullptr && dp->constraint_ok(constraint)) { double doubleval = NAN; std::stringstream stream(value); @@ -131,26 +275,26 @@ bool ParamUtils::GetParamAsString(const char *name, const ParamsVectors *member_ std::string *value) { // Look for the parameter among string parameters. auto *sp = - FindParam(name, GlobalParams()->string_params, member_params->string_params); + FindParam(name, GlobalParams()->string_params_c(), member_params->string_params_c()); if (sp) { *value = sp->c_str(); return true; } // Look for the parameter among int parameters. - auto *ip = FindParam(name, GlobalParams()->int_params, member_params->int_params); + auto *ip = FindParam(name, GlobalParams()->int_params_c(), member_params->int_params_c()); if (ip) { *value = std::to_string(int32_t(*ip)); return true; } // Look for the parameter among bool parameters. - auto *bp = FindParam(name, GlobalParams()->bool_params, member_params->bool_params); + auto *bp = FindParam(name, GlobalParams()->bool_params_c(), member_params->bool_params_c()); if (bp != nullptr) { *value = bool(*bp) ? "1" : "0"; return true; } // Look for the parameter among double parameters. auto *dp = - FindParam(name, GlobalParams()->double_params, member_params->double_params); + FindParam(name, GlobalParams()->double_params_c(), member_params->double_params_c()); if (dp != nullptr) { std::ostringstream stream; stream.imbue(std::locale::classic()); @@ -163,27 +307,55 @@ bool ParamUtils::GetParamAsString(const char *name, const ParamsVectors *member_ void ParamUtils::PrintParams(FILE *fp, const ParamsVectors *member_params) { int num_iterations = (member_params == nullptr) ? 1 : 2; + // When printing to stdout info text is included. + // Info text is omitted when printing to a file (would result in an invalid config file). + if (!fp) + fp = stdout; + bool print_info = (fp == stdout || fp == stderr); std::ostringstream stream; stream.imbue(std::locale::classic()); for (int v = 0; v < num_iterations; ++v) { const ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params; - for (auto int_param : vec->int_params) { - stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\t' - << int_param->info_str() << '\n'; + for (auto int_param : vec->int_params_c()) { + if (print_info) { + stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\t' + << int_param->info_str() << '\n'; + } else { + stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\n'; + } } - for (auto bool_param : vec->bool_params) { - stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\t' - << bool_param->info_str() << '\n'; + for (auto bool_param : vec->bool_params_c()) { + if (print_info) { + stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\t' + << bool_param->info_str() << '\n'; + } else { + stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\n'; + } } - for (auto string_param : vec->string_params) { - stream << string_param->name_str() << '\t' << string_param->c_str() << '\t' - << string_param->info_str() << '\n'; + for (auto string_param : vec->string_params_c()) { + if (print_info) { + stream << string_param->name_str() << '\t' << string_param->c_str() << '\t' + << string_param->info_str() << '\n'; + } else { + stream << string_param->name_str() << '\t' << string_param->c_str() << '\n'; + } } - for (auto double_param : vec->double_params) { - stream << double_param->name_str() << '\t' << (double)(*double_param) << '\t' - << double_param->info_str() << '\n'; + for (auto double_param : vec->double_params_c()) { + if (print_info) { + stream << double_param->name_str() << '\t' << (double)(*double_param) << '\t' + << double_param->info_str() << '\n'; + } else { + stream << double_param->name_str() << '\t' << (double)(*double_param) << '\n'; + } } } +#ifdef HAVE_MUPDF + if (print_info) + { + tprintf("{}", stream.str().c_str()); + return; + } +#endif fprintf(fp, "%s", stream.str().c_str()); } @@ -192,16 +364,16 @@ void ParamUtils::ResetToDefaults(ParamsVectors *member_params) { int num_iterations = (member_params == nullptr) ? 1 : 2; for (int v = 0; v < num_iterations; ++v) { ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params; - for (auto ¶m : vec->int_params) { + for (auto ¶m : vec->int_params()) { param->ResetToDefault(); } - for (auto ¶m : vec->bool_params) { + for (auto ¶m : vec->bool_params()) { param->ResetToDefault(); } - for (auto ¶m : vec->string_params) { + for (auto ¶m : vec->string_params()) { param->ResetToDefault(); } - for (auto ¶m : vec->double_params) { + for (auto ¶m : vec->double_params()) { param->ResetToDefault(); } } diff --git a/src/ccutil/params.h b/src/ccutil/params.h index 0f3f874357..9bbe6d2fe0 100644 --- a/src/ccutil/params.h +++ b/src/ccutil/params.h @@ -2,6 +2,8 @@ * File: params.h * Description: Class definitions of the *_VAR classes for tunable constants. * Author: Ray Smith + * + * UTF8 detect helper statement: «bloody MSVC» * * (C) Copyright 1991, Hewlett-Packard Ltd. ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,11 +45,43 @@ enum SetParamConstraint { SET_PARAM_CONSTRAINT_NON_INIT_ONLY, }; -struct ParamsVectors { - std::vector int_params; - std::vector bool_params; - std::vector string_params; - std::vector double_params; +class ParamsVectors { + std::vector _int_params; + std::vector _bool_params; + std::vector _string_params; + std::vector _double_params; + +public: + ParamsVectors() { + } + ~ParamsVectors() { + } + + std::vector &int_params() { + return _int_params; + } + std::vector &bool_params() { + return _bool_params; + } + std::vector &string_params() { + return _string_params; + } + std::vector &double_params() { + return _double_params; + } + + const std::vector &int_params_c() const { + return _int_params; + } + const std::vector &bool_params_c() const { + return _bool_params; + } + const std::vector &string_params_c() const { + return _string_params; + } + const std::vector &double_params_c() const { + return _double_params; + } }; // Utility functions for working with Tesseract parameters. @@ -69,6 +103,25 @@ class TESS_API ParamUtils { static bool SetParam(const char *name, const char *value, SetParamConstraint constraint, ParamsVectors *member_params); + // accept both - and _ in key names, e.g. user-specified 'debug-all' would match 'debug_all' + // in the database. + static inline bool CompareKeys(const char *db_key, const char *user_key) + { + // if (0 == strcmp(db_key, user_key)) + // return true; + + for (; *db_key && *user_key; db_key++, user_key++) + { + if (*db_key != *user_key) + { + if (*db_key == '_' && *user_key == '-') + continue; + return false; + } + } + return true; + } + // Returns the pointer to the parameter with the given name (of the // appropriate type) if it was found in the vector obtained from // GlobalParams() or in the given member_params. @@ -76,16 +129,16 @@ class TESS_API ParamUtils { static T *FindParam(const char *name, const std::vector &global_vec, const std::vector &member_vec) { for (auto *param : global_vec) { - if (strcmp(param->name_str(), name) == 0) { + if (CompareKeys(param->name_str(), name)) { return param; } } for (auto *param : member_vec) { - if (strcmp(param->name_str(), name) == 0) { + if (CompareKeys(param->name_str(), name)) { return param; } } - return nullptr; + return nullptr; } // Removes the given pointer to the param from the given vector. template @@ -105,6 +158,15 @@ class TESS_API ParamUtils { // Print parameters to the given file. static void PrintParams(FILE *fp, const ParamsVectors *member_params); + // Report parameters' usage statistics, i.e. report which params have been + // set, modified and read/checked until now during this run-time's lifetime. + // + // Use this method for run-time 'discovery' about which tesseract parameters + // are actually *used* during your particular usage of the library, ergo + // answering the question: + // "Which of all those parameters are actually *relevant* to my use case today?" + static void ReportParamsUsageStatistics(const ParamsVectors *member_params); + // Resets all parameters back to default values; static void ResetToDefaults(ParamsVectors *member_params); }; @@ -133,16 +195,29 @@ class Param { (constraint == SET_PARAM_CONSTRAINT_NON_INIT_ONLY && !this->is_init())); } + typedef struct access_counts { + int reading; + int writing; + } access_counts_t; + + access_counts_t access_counts() const { + return access_counts_; + } + + virtual std::string formatted_value_str() const = 0; + protected: Param(const char *name, const char *comment, bool init) : name_(name), info_(comment), init_(init) { debug_ = (strstr(name, "debug") != nullptr) || (strstr(name, "display")); + access_counts_ = {0,0}; } const char *name_; // name of this parameter const char *info_; // for menus bool init_; // needs to be set before init bool debug_; + mutable access_counts_t access_counts_; }; class IntParam : public Param { @@ -151,40 +226,51 @@ class IntParam : public Param { : Param(name, comment, init) { value_ = value; default_ = value; - params_vec_ = &(vec->int_params); - vec->int_params.push_back(this); + access_counts_.writing++; + params_vec_ = vec; + vec->int_params().push_back(this); } ~IntParam() { - ParamUtils::RemoveParam(this, params_vec_); + ParamUtils::RemoveParam(this, ¶ms_vec_->int_params()); } operator int32_t() const { - return value_; + access_counts_.reading++; + return value_; } void operator=(int32_t value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void set_value(int32_t value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void ResetToDefault() { - value_ = default_; + access_counts_.writing++; + value_ = default_; } void ResetFrom(const ParamsVectors *vec) { - for (auto *param : vec->int_params) { + for (auto *param : vec->int_params_c()) { if (strcmp(param->name_str(), name_) == 0) { - // printf("overriding param %s=%d by =%d\n", name_, value_, - // param); - value_ = *param; + // tprintf("overriding param {}={} by ={}\n", name_, value_, + // *param); + access_counts_.writing++; + value_ = *param; break; } } } + virtual std::string formatted_value_str() const override { + return std::to_string(value_); + } + private: int32_t value_; int32_t default_; - // Pointer to the vector that contains this param (not owned by this class). - std::vector *params_vec_; + + // Pointer to the vector that contains this param (not owned by this class). Used by the destructor. + ParamsVectors *params_vec_; }; class BoolParam : public Param { @@ -193,40 +279,51 @@ class BoolParam : public Param { : Param(name, comment, init) { value_ = value; default_ = value; - params_vec_ = &(vec->bool_params); - vec->bool_params.push_back(this); + access_counts_.writing++; + params_vec_ = vec; + vec->bool_params().push_back(this); } ~BoolParam() { - ParamUtils::RemoveParam(this, params_vec_); + ParamUtils::RemoveParam(this, ¶ms_vec_->bool_params()); } operator bool() const { - return value_; + access_counts_.reading++; + return value_; } void operator=(bool value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void set_value(bool value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void ResetToDefault() { - value_ = default_; + access_counts_.writing++; + value_ = default_; } void ResetFrom(const ParamsVectors *vec) { - for (auto *param : vec->bool_params) { + for (auto *param : vec->bool_params_c()) { if (strcmp(param->name_str(), name_) == 0) { - // printf("overriding param %s=%s by =%s\n", name_, value_ ? "true" : + // tprintf("overriding param {}={} by ={}\n", name_, value_ ? "true" : // "false", *param ? "true" : "false"); - value_ = *param; + access_counts_.writing++; + value_ = *param; break; } } } + virtual std::string formatted_value_str() const override { + return std::to_string(value_); + } + private: bool value_; bool default_; + // Pointer to the vector that contains this param (not owned by this class). - std::vector *params_vec_; + ParamsVectors *params_vec_; }; class StringParam : public Param { @@ -236,52 +333,74 @@ class StringParam : public Param { : Param(name, comment, init) { value_ = value; default_ = value; - params_vec_ = &(vec->string_params); - vec->string_params.push_back(this); + access_counts_.writing++; + params_vec_ = vec; + vec->string_params().push_back(this); } ~StringParam() { - ParamUtils::RemoveParam(this, params_vec_); + ParamUtils::RemoveParam(this, ¶ms_vec_->string_params()); } operator std::string &() { - return value_; + access_counts_.reading++; + return value_; } const char *c_str() const { - return value_.c_str(); + access_counts_.reading++; + return value_.c_str(); } bool contains(char c) const { - return value_.find(c) != std::string::npos; + access_counts_.reading++; + return value_.find(c) != std::string::npos; } bool empty() const { - return value_.empty(); + access_counts_.reading++; + return value_.empty(); } bool operator==(const std::string &other) const { - return value_ == other; + access_counts_.reading++; + return value_ == other; } void operator=(const std::string &value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void set_value(const std::string &value) { - value_ = value; + access_counts_.writing++; + value_ = value; + } + const std::string &value() { + access_counts_.reading++; + return value_; } void ResetToDefault() { - value_ = default_; + access_counts_.writing++; + value_ = default_; } void ResetFrom(const ParamsVectors *vec) { - for (auto *param : vec->string_params) { + for (auto *param : vec->string_params_c()) { if (strcmp(param->name_str(), name_) == 0) { - // printf("overriding param %s=%s by =%s\n", name_, value_, + // tprintf("overriding param {}={} by ={}\n", name_, value_, // param->c_str()); - value_ = *param; + access_counts_.writing++; + value_ = *param; break; } } } + virtual std::string formatted_value_str() const override { + std::string rv = (const char *)u8"«"; + rv += value_; + rv += (const char *)u8"»"; + return rv; + } + private: std::string value_; std::string default_; + // Pointer to the vector that contains this param (not owned by this class). - std::vector *params_vec_; + ParamsVectors *params_vec_; }; class DoubleParam : public Param { @@ -290,40 +409,57 @@ class DoubleParam : public Param { : Param(name, comment, init) { value_ = value; default_ = value; - params_vec_ = &(vec->double_params); - vec->double_params.push_back(this); + access_counts_.writing++; + params_vec_ = vec; + vec->double_params().push_back(this); } ~DoubleParam() { - ParamUtils::RemoveParam(this, params_vec_); + ParamUtils::RemoveParam(this, ¶ms_vec_->double_params()); } operator double() const { - return value_; + access_counts_.reading++; + return value_; } void operator=(double value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void set_value(double value) { - value_ = value; + access_counts_.writing++; + value_ = value; } void ResetToDefault() { - value_ = default_; + access_counts_.writing++; + value_ = default_; } void ResetFrom(const ParamsVectors *vec) { - for (auto *param : vec->double_params) { + for (auto *param : vec->double_params_c()) { if (strcmp(param->name_str(), name_) == 0) { - // printf("overriding param %s=%f by =%f\n", name_, value_, + // tprintf("overriding param {}={} by ={}\n", name_, value_, // *param); - value_ = *param; + access_counts_.writing++; + value_ = *param; break; } } } + virtual std::string formatted_value_str() const override { +#if 0 + return std::to_string(value_); // always outputs %.6f format style values +#else + char sbuf[40]; + snprintf(sbuf, sizeof(sbuf), "%1.f", value_); + return sbuf; +#endif + } + private: double value_; double default_; + // Pointer to the vector that contains this param (not owned by this class). - std::vector *params_vec_; + ParamsVectors *params_vec_; }; // Global parameter lists. @@ -338,6 +474,7 @@ class DoubleParam : public Param { TESS_API ParamsVectors *GlobalParams(); + /************************************************************************* * Note on defining parameters. * @@ -382,6 +519,12 @@ ParamsVectors *GlobalParams(); #define double_INIT_MEMBER(name, val, comment, vec) name(val, #name, comment, true, vec) +// ------------------------------------ + +extern BOOL_VAR_H(debug_all); +extern STRING_VAR_H(vars_report_file); +extern BOOL_VAR_H(report_all_variables); + } // namespace tesseract #endif