File indexing completed on 2025-06-30 08:40:15
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 << values[i];
0544 ss << ",";
0545 }
0546 if (len != 0) {
0547 ss << 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 << values[i];
0591 ss << ",";
0592 }
0593 if (len != 0) {
0594 ss << 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