File indexing completed on 2025-10-30 09:01:23
0001 
0002 
0003 
0004 
0005 #pragma once
0006 
0007 #include <limits>
0008 #include <string>
0009 #include <algorithm>
0010 #include <vector>
0011 #include <array>
0012 #include <map>
0013 #include <cmath>
0014 #include <iomanip>
0015 #include <cstring>
0016 
0017 #include <JANA/JLogger.h>
0018 #include <JANA/JException.h>
0019 #include <JANA/Services/JServiceLocator.h>
0020 
0021 class JParameter {
0022 
0023     std::string m_name;             
0024     std::string m_value;            
0025     std::string m_default_value;    
0026     std::string m_description;      
0027 
0028     bool m_has_default = false;     
0029                                     
0030     bool m_is_default = false;      
0031                                     
0032     bool m_is_deprecated = false;   
0033                                     
0034     bool m_is_advanced = false;       
0035                                     
0036     bool m_is_used = false;         
0037 
0038     bool m_is_conflicted = false;   
0039 
0040 public:
0041 
0042     JParameter(std::string key, std::string value, std::string defaultValue, std::string description, bool hasDefault, bool isDefault)
0043     : m_name(std::move(key)),
0044       m_value(std::move(value)),
0045       m_default_value(std::move(defaultValue)),
0046       m_description(std::move(description)),
0047       m_has_default(hasDefault),
0048       m_is_default(isDefault) {}
0049 
0050     inline const std::string& GetKey() const { return m_name; }
0051     inline const std::string& GetValue() const { return m_value; }
0052     inline const std::string& GetDefault() const { return m_default_value; }
0053     inline const std::string& GetDescription() const { return m_description; }
0054 
0055     inline bool HasDefault() const { return m_has_default; }
0056     inline bool IsDefault() const { return m_is_default; }
0057     inline bool IsAdvanced() const { return m_is_advanced; }
0058     inline bool IsUsed() const { return m_is_used; }
0059     inline bool IsDeprecated() const { return m_is_deprecated; }
0060     inline bool IsConflicted() const { return m_is_conflicted; }
0061 
0062     inline void SetKey(std::string key) { m_name = std::move(key); }
0063     inline void SetValue(std::string val) { m_value = std::move(val); }
0064     inline void SetDefault(std::string defaultValue) { m_default_value = std::move(defaultValue); }
0065     inline void SetDescription(std::string desc) { m_description = std::move(desc); }
0066     inline void SetHasDefault(bool hasDefault) { m_has_default = hasDefault; }
0067     inline void SetIsDefault(bool isDefault) { m_is_default = isDefault; }
0068     inline void SetIsAdvanced(bool isHidden) { m_is_advanced = isHidden; }
0069     inline void SetIsUsed(bool isUsed) { m_is_used = isUsed; }
0070     inline void SetIsDeprecated(bool isDeprecated) { m_is_deprecated = isDeprecated; }
0071     inline void SetIsConflicted(bool isConflicted) { m_is_conflicted = isConflicted; }
0072 
0073 };
0074 
0075 class JParameterManager : public JService {
0076 public:
0077 
0078     JParameterManager();
0079 
0080     JParameterManager(const JParameterManager&);
0081 
0082     ~JParameterManager() override;
0083 
0084     inline void SetLogger(JLogger logger) { m_logger = logger; }
0085 
0086     bool Exists(std::string name);
0087 
0088     JParameter* FindParameter(std::string);
0089 
0090     void PrintParameters();
0091     
0092     void PrintParameters(int verbosity, int strictness);
0093 
0094     std::map<std::string, JParameter*> GetAllParameters();
0095 
0096     template<typename T>
0097     JParameter* GetParameter(std::string name, T& val);
0098 
0099     template<typename T>
0100     T GetParameterValue(std::string name);
0101 
0102     template<typename T>
0103     JParameter* SetParameter(std::string name, T val);
0104 
0105     template<typename T>
0106     JParameter* SetDefaultParameter(std::string name, T& val, std::string description = "");
0107 
0108     template <typename T>
0109     T RegisterParameter(std::string name, const T default_val, std::string description = "");
0110 
0111     void FilterParameters(std::map<std::string,std::string> &parms, std::string filter="");
0112 
0113     void ReadConfigFile(std::string name);
0114 
0115     void WriteConfigFile(std::string name);
0116 
0117     template<typename T>
0118     static inline void Parse(const std::string& value, T& out);
0119 
0120     template<typename T>
0121     static inline void Parse(const std::string& value, std::vector<T>& out);
0122 
0123     template<typename T, size_t arrSize>
0124     static inline void Parse(const std::string& value, std::array<T,arrSize>& out); 
0125 
0126     template<size_t arrSize>
0127     static inline void Parse(const std::string& value, std::array<std::string,arrSize>& out);
0128 
0129 
0130     
0131 
0132 
0133 
0134     template<typename T>
0135     static std::string Stringify(const T& value);
0136 
0137     template<typename T>
0138     static std::string Stringify(const std::vector<T>& values);
0139 
0140     template<typename T,size_t N>
0141     static std::string Stringify(const std::array<T,N>& values);
0142  
0143     template<size_t N>
0144     static std::string Stringify(const std::array<std::string,N>& values);
0145 
0146     template<typename T>
0147     static bool Equals(const T& lhs, const T& rhs);
0148 
0149 
0150     static std::string ToLower(const std::string& name);
0151 
0152     JLogger GetLogger(const std::string& prefix);
0153 
0154 private:
0155 
0156     std::map<std::string, JParameter*> m_parameters;
0157 
0158     int m_strictness = 1;
0159     int m_verbosity = 1;
0160 
0161     std::mutex m_mutex;
0162 };
0163 
0164 
0165 
0166 
0167 
0168 
0169 
0170 
0171 
0172 
0173 template<typename T>
0174 JParameter* JParameterManager::GetParameter(std::string name, T& val) {
0175 
0176     auto result = m_parameters.find(ToLower(name));
0177     if (result == m_parameters.end()) {
0178         return nullptr;
0179     }
0180     Parse(result->second->GetValue(),val);
0181     result->second->SetIsUsed(true);
0182     return result->second;
0183 }
0184 
0185 
0186 
0187 
0188 
0189 
0190 
0191 
0192 template<typename T>
0193 T JParameterManager::GetParameterValue(std::string name) {
0194     T t;
0195     auto result = m_parameters.find(ToLower(name));
0196     if (result == m_parameters.end()) {
0197         throw JException("Unknown parameter \"%s\"", name.c_str());
0198     }
0199     result->second->SetIsUsed(true);
0200     Parse(result->second->GetValue(),t);
0201     return t;
0202 }
0203 
0204 
0205 
0206 
0207 
0208 
0209 
0210 template<typename T>
0211 JParameter* JParameterManager::SetParameter(std::string name, T val) {
0212 
0213     auto result = m_parameters.find(ToLower(name));
0214 
0215     if (result == m_parameters.end()) {
0216         auto* param = new JParameter {name, Stringify(val), "", "", false, false};
0217         m_parameters[ToLower(name)] = param;
0218         return param;
0219     }
0220     result->second->SetValue(Stringify(val));
0221     result->second->SetIsDefault(false);
0222     return result->second;
0223 }
0224 
0225 
0226 
0227 
0228 
0229 
0230 
0231 
0232 
0233 
0234 
0235 
0236 
0237 
0238 
0239 
0240 
0241 
0242 
0243 
0244 
0245 
0246 
0247 
0248 
0249 
0250 
0251 
0252 template<typename T>
0253 JParameter* JParameterManager::SetDefaultParameter(std::string name, T& val, std::string description) {
0254 
0255     std::lock_guard<std::mutex> lock(m_mutex);
0256     JParameter* param = nullptr;
0257     T t;
0258     auto result = m_parameters.find(ToLower(name));
0259     if (result != m_parameters.end()) {
0260         
0261         param = result->second;
0262 
0263         if (!param->HasDefault()) {
0264             
0265             param->SetHasDefault(true);
0266             param->SetDefault(Stringify(val));
0267             param->SetDescription(std::move(description));
0268         }
0269         else {
0270             
0271             
0272             
0273             Parse(param->GetDefault(),t);
0274             if (!Equals(val, t)) {
0275                 if (!param->IsConflicted()) {
0276                     
0277                     LOG_WARN(m_logger) << "Parameter '" << name << "' has conflicting defaults: '"
0278                                     << Stringify(val) << "' vs '" << param->GetDefault() << "'"
0279                                     << LOG_END;
0280                     param->SetIsConflicted(true);
0281                 }
0282                 
0283                 
0284                 
0285                 param->SetDefault(Stringify(val));
0286             }
0287             if (param->IsDefault()) {
0288                 param->SetValue(Stringify(val)); 
0289             }
0290         }
0291     }
0292     else {
0293         
0294         auto valstr = Stringify(val);
0295         param = new JParameter {name, valstr, valstr, std::move(description), true, true};
0296 
0297         
0298         
0299         
0300         Parse(valstr,t);
0301         if (!Equals(val, t)) {
0302             LOG_WARN(m_logger) << "Parameter '" << name << "' with value '" << valstr
0303                                << "' loses equality with itself after stringification" << LOG_END;
0304         }
0305         m_parameters[ToLower(name)] = param;
0306     }
0307 
0308     
0309     
0310     Parse(param->GetValue(),t);
0311     val = t;
0312     param->SetIsUsed(true);
0313     return param;
0314 }
0315 
0316 
0317 
0318 
0319 
0320 
0321 
0322 
0323 
0324 
0325 
0326 
0327 
0328 
0329 template <typename T>
0330 inline T JParameterManager::RegisterParameter(std::string name, const T default_val, std::string description){
0331     T val = default_val;
0332     SetDefaultParameter(name.c_str(), val, description);
0333     return val;
0334 }
0335 
0336 
0337 #if __cplusplus >= 201703L
0338 
0339 template <typename T>
0340 void JParameterManager::Parse(const std::string& s, T& out) {
0341     constexpr bool parseable = JTypeInfo::is_parseable<T>::value;
0342     static_assert(parseable, "Type is not automatically parseable by JParameterManager. To use, provide a template specialization for JParameterManager::Parse(std::string in, T& out).");
0343     if constexpr (parseable) {
0344         std::stringstream ss(s);
0345         ss >> out;
0346     }
0347 }
0348 #else
0349 
0350 template <typename T>
0351 void JParameterManager::Parse(const std::string& s, T& out) {
0352     std::stringstream ss(s);
0353     ss >> out;
0354 }
0355 #endif
0356 
0357 
0358 
0359 
0360 template <>
0361 inline void JParameterManager::Parse(const std::string& value, std::string& out) {
0362     out = value;
0363 }
0364 
0365 
0366 
0367 template <>
0368 inline void JParameterManager::Parse(const std::string& value, bool& val) {
0369     if (value == "0" || value =="false" || value == "off") val = false;
0370     else if (value == "1" || value == "true" || value == "on") val = true;
0371     else throw JException("'%s' not parseable as bool", value.c_str());
0372 }
0373 
0374 
0375 template<typename T, size_t N>
0376 inline void JParameterManager::Parse(const std::string& value,std::array<T,N> &val) {
0377     std::string s;
0378     std::stringstream ss(value);
0379     int indx = 0;
0380     while (getline(ss, s, ',')) {
0381         T t;
0382         Parse(s, t);
0383         val[indx++]= t;
0384     }
0385 }
0386 
0387 
0388 template<size_t N>
0389 inline void JParameterManager::Parse(const std::string& value,std::array<std::string,N> &val) {
0390     std::string s;
0391     std::stringstream ss(value);
0392     std::string temp;   
0393     int indx = 0;
0394     while (getline(ss, s, ',')) {
0395         std::string t;
0396         if (s.back() == '\\') {
0397             s.pop_back();
0398             temp += s + ',';
0399             continue;
0400         }
0401         if (!temp.empty()) {
0402             Parse(temp + s, t);
0403             val[indx++]= t;
0404             temp.clear();
0405         }
0406         else {
0407             Parse(s, t);
0408             val[indx++]= t;
0409         }
0410     }
0411 }
0412 
0413 
0414 template<typename T>
0415 inline void JParameterManager::Parse(const std::string& value, std::vector<T> &val) {
0416     std::stringstream ss(value);
0417     std::string s;
0418     val.clear(); 
0419     while (getline(ss, s, ',')) {
0420         T t;
0421         Parse(s, t);
0422         val.push_back(t);
0423     }
0424 }
0425 
0426 
0427 template<>
0428 inline void JParameterManager::Parse(const std::string& value, std::vector<std::string> &val) {
0429     std::stringstream ss(value);
0430     std::string s;
0431     val.clear(); 
0432     std::string temp;   
0433     while (getline(ss, s, ',')) {
0434         std::string t;
0435         if (s.back() == '\\') {
0436             s.pop_back();
0437             temp += s + ',';
0438             continue;
0439         }
0440         if (!temp.empty()) {
0441             Parse(temp + s, t);
0442             val.push_back(t);
0443             temp.clear();
0444         }
0445         else {
0446             Parse(s, t);
0447             val.push_back(t);
0448         }
0449     }
0450 }
0451 
0452 
0453 template <>
0454 inline void JParameterManager::Parse(const std::string& in, JLogger::Level& out) {
0455     std::string token(in);
0456     std::transform(in.begin(), in.end(), token.begin(), ::tolower);
0457     if (std::strcmp(token.c_str(), "trace") == 0) { 
0458         out = JLogger::Level::TRACE;
0459     }
0460     else if (std::strcmp(token.c_str(), "debug") == 0) { 
0461         out = JLogger::Level::DEBUG;
0462     }
0463     else if (std::strcmp(token.c_str(), "info") == 0) { 
0464         out = JLogger::Level::INFO;
0465     }
0466     else if (std::strcmp(token.c_str(), "warn") == 0) { 
0467         out = JLogger::Level::WARN;
0468     }
0469     else if (std::strcmp(token.c_str(), "error") == 0) { 
0470         out = JLogger::Level::ERROR;
0471     }
0472     else if (std::strcmp(token.c_str(), "fatal") == 0) { 
0473         out = JLogger::Level::FATAL;
0474     }
0475     else if (std::strcmp(token.c_str(), "off") == 0) { 
0476         out = JLogger::Level::OFF;
0477     }
0478     else {
0479         throw JException("Unable to parse log level: '%s'. Options are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF", in.c_str());
0480     }
0481 }
0482 
0483 #if __cplusplus >= 201703L
0484 
0485 template <typename T>
0486 inline std::string JParameterManager::Stringify(const T& value) {
0487     constexpr bool serializable = JTypeInfo::is_serializable<T>::value;
0488     static_assert(serializable, "Type is not automatically serializable by JParameterManager. To use, provide a template specialization for JParameterManager::Stringify(const T& val) -> std::string.");
0489     if constexpr (serializable) {
0490         std::stringstream ss;
0491         ss << value;
0492         return ss.str();
0493     }
0494 }
0495 #else
0496 
0497 template <typename T>
0498 inline std::string JParameterManager::Stringify(const T& value) {
0499     std::stringstream ss;
0500     ss << value;
0501     return ss.str();
0502 }
0503 #endif
0504 
0505 
0506 template <>
0507 inline std::string JParameterManager::Stringify(const float& value) {
0508     std::stringstream ss;
0509     
0510     
0511     ss << std::setprecision(std::numeric_limits<float>::max_digits10) << value;
0512     return ss.str();
0513 }
0514 template <>
0515 inline std::string JParameterManager::Stringify(const double& value) {
0516     std::stringstream ss;
0517     
0518     
0519     ss << std::setprecision(std::numeric_limits<double>::max_digits10) << value;
0520     return ss.str();
0521 }
0522 template <>
0523 inline std::string JParameterManager::Stringify(const long double& value) {
0524     std::stringstream ss;
0525     
0526     
0527     ss << std::setprecision(std::numeric_limits<long double>::max_digits10) << value;
0528     return ss.str();
0529 }
0530 
0531 
0532 template <>
0533 inline std::string JParameterManager::Stringify(const std::string& value) {
0534     return value;
0535 }
0536 
0537 
0538 template <typename T>
0539 inline std::string JParameterManager::Stringify(const std::vector<T> &values) {
0540     std::stringstream ss;
0541     size_t len = values.size();
0542     for (size_t i = 0; i+1 < len; ++i) {
0543         ss << Stringify(values[i]);
0544         ss << ",";
0545     }
0546     if (len != 0) {
0547         ss << Stringify(values[len-1]);
0548     }
0549     return ss.str();
0550 }
0551 
0552 
0553 template <>
0554 inline std::string JParameterManager::Stringify(const std::vector<std::string> &values) {
0555     size_t len = values.size();
0556     std::stringstream ssv;
0557     for (size_t i = 0; i < len; ++i) {
0558         if (values[i].find(',') != std::string::npos) {
0559             std::stringstream ss(values[i]);
0560             std::string s;
0561             std::string s_end = values[i].substr(values[i].rfind(',')+1);
0562             while (getline(ss, s, ',')) {
0563                 if (s == s_end) {
0564                     ssv << s;
0565                     if (i != len-1) {
0566                         ssv << ',';
0567                     }
0568                     break;
0569                 }
0570                 ssv << s << "\\,";
0571                 continue;
0572             }
0573         } else {
0574             ssv << values[i];
0575             if (i != len-1) {
0576                 ssv << ',';
0577             }
0578         }
0579     }
0580     return ssv.str();
0581 }
0582 
0583 
0584 
0585 template <typename T, size_t N>
0586 inline std::string JParameterManager::Stringify(const std::array<T,N> &values) {
0587     std::stringstream ss;
0588     size_t len = values.size();
0589     for (size_t i = 0; i+1 < N; ++i) {
0590         ss << Stringify(values[i]);
0591         ss << ",";
0592     }
0593     if (len != 0) {
0594         ss << Stringify(values[len-1]);
0595     }
0596     return ss.str();
0597 }
0598 
0599 
0600 template <size_t N>
0601 inline std::string JParameterManager::Stringify(const std::array<std::string,N> &values) {
0602     size_t len = values.size();
0603     std::stringstream ssv;
0604     for (size_t i = 0; i < len; ++i) {
0605         if (values[i].find(',') != std::string::npos) {
0606             std::stringstream ss(values[i]);
0607             std::string s;
0608             std::string s_end = values[i].substr(values[i].rfind(',')+1);
0609             while (getline(ss, s, ',')) {
0610                 if (s == s_end) {
0611                     ssv << s;
0612                     if (i != len-1) {
0613                         ssv << ',';
0614                     }
0615                     break;
0616                 }
0617                 ssv << s << "\\,";
0618                 continue;
0619             }
0620         } else {
0621             ssv << values[i];
0622             if (i != len-1) {
0623                 ssv << ',';
0624             }
0625         }
0626     }
0627     return ssv.str();
0628 }
0629 
0630 
0631 
0632 
0633 template <typename T>
0634 inline bool JParameterManager::Equals(const T& lhs, const T& rhs) {
0635     return lhs == rhs;
0636 }
0637 
0638 
0639 
0640