File indexing completed on 2025-01-18 10:17:35
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
0127
0128
0129
0130 template<typename T>
0131 static std::string Stringify(const T& value);
0132
0133 template<typename T>
0134 static std::string Stringify(const std::vector<T>& values);
0135
0136 template<typename T,size_t N>
0137 static std::string Stringify(const std::array<T,N>& values);
0138
0139 template<typename T>
0140 static bool Equals(const T& lhs, const T& rhs);
0141
0142
0143 static std::string ToLower(const std::string& name);
0144
0145 JLogger GetLogger(const std::string& prefix);
0146
0147 private:
0148
0149 std::map<std::string, JParameter*> m_parameters;
0150
0151 int m_strictness = 1;
0152 int m_verbosity = 1;
0153
0154 std::mutex m_mutex;
0155 };
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 template<typename T>
0167 JParameter* JParameterManager::GetParameter(std::string name, T& val) {
0168
0169 auto result = m_parameters.find(ToLower(name));
0170 if (result == m_parameters.end()) {
0171 return nullptr;
0172 }
0173 Parse(result->second->GetValue(),val);
0174 result->second->SetIsUsed(true);
0175 return result->second;
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185 template<typename T>
0186 T JParameterManager::GetParameterValue(std::string name) {
0187 T t;
0188 auto result = m_parameters.find(ToLower(name));
0189 if (result == m_parameters.end()) {
0190 throw JException("Unknown parameter \"%s\"", name.c_str());
0191 }
0192 result->second->SetIsUsed(true);
0193 Parse(result->second->GetValue(),t);
0194 return t;
0195 }
0196
0197
0198
0199
0200
0201
0202
0203 template<typename T>
0204 JParameter* JParameterManager::SetParameter(std::string name, T val) {
0205
0206 auto result = m_parameters.find(ToLower(name));
0207
0208 if (result == m_parameters.end()) {
0209 auto* param = new JParameter {name, Stringify(val), "", "", false, false};
0210 m_parameters[ToLower(name)] = param;
0211 return param;
0212 }
0213 result->second->SetValue(Stringify(val));
0214 result->second->SetIsDefault(false);
0215 return result->second;
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
0245 template<typename T>
0246 JParameter* JParameterManager::SetDefaultParameter(std::string name, T& val, std::string description) {
0247
0248 std::lock_guard<std::mutex> lock(m_mutex);
0249 JParameter* param = nullptr;
0250 T t;
0251 auto result = m_parameters.find(ToLower(name));
0252 if (result != m_parameters.end()) {
0253
0254 param = result->second;
0255
0256 if (!param->HasDefault()) {
0257
0258 param->SetHasDefault(true);
0259 param->SetDefault(Stringify(val));
0260 param->SetDescription(std::move(description));
0261 }
0262 else {
0263
0264
0265
0266 Parse(param->GetDefault(),t);
0267 if (!Equals(val, t)) {
0268 if (!param->IsConflicted()) {
0269
0270 LOG_WARN(m_logger) << "Parameter '" << name << "' has conflicting defaults: '"
0271 << Stringify(val) << "' vs '" << param->GetDefault() << "'"
0272 << LOG_END;
0273 param->SetIsConflicted(true);
0274 }
0275
0276
0277
0278 param->SetDefault(Stringify(val));
0279 }
0280 if (param->IsDefault()) {
0281 param->SetValue(Stringify(val));
0282 }
0283 }
0284 }
0285 else {
0286
0287 auto valstr = Stringify(val);
0288 param = new JParameter {name, valstr, valstr, std::move(description), true, true};
0289
0290
0291
0292
0293 Parse(valstr,t);
0294 if (!Equals(val, t)) {
0295 LOG_WARN(m_logger) << "Parameter '" << name << "' with value '" << valstr
0296 << "' loses equality with itself after stringification" << LOG_END;
0297 }
0298 m_parameters[ToLower(name)] = param;
0299 }
0300
0301
0302
0303 Parse(param->GetValue(),t);
0304 val = t;
0305 param->SetIsUsed(true);
0306 return param;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322 template <typename T>
0323 inline T JParameterManager::RegisterParameter(std::string name, const T default_val, std::string description){
0324 T val = default_val;
0325 SetDefaultParameter(name.c_str(), val, description);
0326 return val;
0327 }
0328
0329
0330 #if __cplusplus >= 201703L
0331
0332 template <typename T>
0333 void JParameterManager::Parse(const std::string& s, T& out) {
0334 constexpr bool parseable = JTypeInfo::is_parseable<T>::value;
0335 static_assert(parseable, "Type is not automatically parseable by JParameterManager. To use, provide a template specialization for JParameterManager::Parse(std::string in, T& out).");
0336 if constexpr (parseable) {
0337 std::stringstream ss(s);
0338 ss >> out;
0339 }
0340 }
0341 #else
0342
0343 template <typename T>
0344 void JParameterManager::Parse(const std::string& s, T& out) {
0345 std::stringstream ss(s);
0346 ss >> out;
0347 }
0348 #endif
0349
0350
0351
0352
0353 template <>
0354 inline void JParameterManager::Parse(const std::string& value, std::string& out) {
0355 out = value;
0356 }
0357
0358
0359
0360 template <>
0361 inline void JParameterManager::Parse(const std::string& value, bool& val) {
0362 if (value == "0" || value =="false" || value == "off") val = false;
0363 else if (value == "1" || value == "true" || value == "on") val = true;
0364 else throw JException("'%s' not parseable as bool", value.c_str());
0365 }
0366
0367
0368 template<typename T, size_t N>
0369 inline void JParameterManager::Parse(const std::string& value,std::array<T,N> &val) {
0370 std::string s;
0371 std::stringstream ss(value);
0372 int indx = 0;
0373 while (getline(ss, s, ',')) {
0374 T t;
0375 Parse(s, t);
0376 val[indx++]= t;
0377 }
0378 }
0379
0380
0381 template<typename T>
0382 inline void JParameterManager::Parse(const std::string& value, std::vector<T> &val) {
0383 std::stringstream ss(value);
0384 std::string s;
0385 val.clear();
0386 while (getline(ss, s, ',')) {
0387 T t;
0388 Parse(s, t);
0389 val.push_back(t);
0390 }
0391 }
0392
0393
0394 template <>
0395 inline void JParameterManager::Parse(const std::string& in, JLogger::Level& out) {
0396 std::string token(in);
0397 std::transform(in.begin(), in.end(), token.begin(), ::tolower);
0398 if (std::strcmp(token.c_str(), "trace") == 0) {
0399 out = JLogger::Level::TRACE;
0400 }
0401 else if (std::strcmp(token.c_str(), "debug") == 0) {
0402 out = JLogger::Level::DEBUG;
0403 }
0404 else if (std::strcmp(token.c_str(), "info") == 0) {
0405 out = JLogger::Level::INFO;
0406 }
0407 else if (std::strcmp(token.c_str(), "warn") == 0) {
0408 out = JLogger::Level::WARN;
0409 }
0410 else if (std::strcmp(token.c_str(), "error") == 0) {
0411 out = JLogger::Level::ERROR;
0412 }
0413 else if (std::strcmp(token.c_str(), "fatal") == 0) {
0414 out = JLogger::Level::FATAL;
0415 }
0416 else if (std::strcmp(token.c_str(), "off") == 0) {
0417 out = JLogger::Level::OFF;
0418 }
0419 else {
0420 throw JException("Unable to parse log level: '%s'. Options are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF", in.c_str());
0421 }
0422 }
0423
0424 #if __cplusplus >= 201703L
0425
0426 template <typename T>
0427 inline std::string JParameterManager::Stringify(const T& value) {
0428 constexpr bool serializable = JTypeInfo::is_serializable<T>::value;
0429 static_assert(serializable, "Type is not automatically serializable by JParameterManager. To use, provide a template specialization for JParameterManager::Stringify(const T& val) -> std::string.");
0430 if constexpr (serializable) {
0431 std::stringstream ss;
0432 ss << value;
0433 return ss.str();
0434 }
0435 }
0436 #else
0437
0438 template <typename T>
0439 inline std::string JParameterManager::Stringify(const T& value) {
0440 std::stringstream ss;
0441 ss << value;
0442 return ss.str();
0443 }
0444 #endif
0445
0446
0447 template <>
0448 inline std::string JParameterManager::Stringify(const float& value) {
0449 std::stringstream ss;
0450
0451
0452 ss << std::setprecision(std::numeric_limits<float>::max_digits10) << value;
0453 return ss.str();
0454 }
0455 template <>
0456 inline std::string JParameterManager::Stringify(const double& value) {
0457 std::stringstream ss;
0458
0459
0460 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << value;
0461 return ss.str();
0462 }
0463 template <>
0464 inline std::string JParameterManager::Stringify(const long double& value) {
0465 std::stringstream ss;
0466
0467
0468 ss << std::setprecision(std::numeric_limits<long double>::max_digits10) << value;
0469 return ss.str();
0470 }
0471
0472
0473 template <>
0474 inline std::string JParameterManager::Stringify(const std::string& value) {
0475 return value;
0476 }
0477
0478
0479 template <typename T>
0480 inline std::string JParameterManager::Stringify(const std::vector<T> &values) {
0481 std::stringstream ss;
0482 size_t len = values.size();
0483 for (size_t i = 0; i+1 < len; ++i) {
0484 ss << values[i];
0485 ss << ",";
0486 }
0487 if (len != 0) {
0488 ss << values[len-1];
0489 }
0490 return ss.str();
0491 }
0492
0493
0494
0495 template <typename T, size_t N>
0496 inline std::string JParameterManager::Stringify(const std::array<T,N> &values) {
0497 std::stringstream ss;
0498 size_t len = values.size();
0499 for (size_t i = 0; i+1 < N; ++i) {
0500 ss << values[i];
0501 ss << ",";
0502 }
0503 if (len != 0) {
0504 ss << values[len-1];
0505 }
0506 return ss.str();
0507 }
0508
0509
0510
0511
0512 template <typename T>
0513 inline bool JParameterManager::Equals(const T& lhs, const T& rhs) {
0514 return lhs == rhs;
0515 }
0516
0517
0518
0519