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