14#ifndef COMMON_SIMCONFIG_INCLUDE_SIMCONFIG_CONFIGURABLEPARAM_H_
15#define COMMON_SIMCONFIG_INCLUDE_SIMCONFIG_CONFIGURABLEPARAM_H_
28#include <unordered_map>
30#include <boost/property_tree/ptree_fwd.hpp>
100 std::vector<std::pair<std::string, int>>
vvalues;
129 void add(
const std::string&
key,
const TDataMember* dm);
133 return entries.count(
key) > 0;
140 auto iter = entries.find(
key);
141 return iter != entries.end() ? &iter->second :
nullptr;
145 std::unordered_map<std::string, EnumLegalValues> entries;
149concept Container = !std::is_same_v<std::remove_cvref_t<T>, std::string> &&
requires(T t) {
150 typename T::value_type;
151 typename T::iterator;
152 { t.begin() } -> std::same_as<typename T::iterator>;
153 { t.end() } -> std::same_as<typename T::iterator>;
158 typename T::key_type;
159 typename T::mapped_type;
171 template <
typename T>
175 return parseMap<T>(
str);
182 return parseSequence<T>(
str);
184 return parseScalar<T>(
str);
188 static std::string
trim(
const std::string&
str)
190 auto start =
str.find_first_not_of(
" \t\n\r\f\v");
191 if (
start == std::string::npos) {
194 auto end =
str.find_last_not_of(
" \t\n\r\f\v");
200 template <SequenceContainer SequenceT>
201 static SequenceT parseSequence(
const std::string&
str)
204 using ValueType =
typename SequenceT::value_type;
205 std::string cleaned =
str;
206 if (!cleaned.empty() && cleaned.front() ==
'[' && cleaned.back() ==
']') {
207 cleaned = cleaned.substr(1, cleaned.length() - 2);
209 if (cleaned.empty() || cleaned ==
"{}") {
212 if constexpr (Container<ValueType>) {
213 static_assert(AlwaysFalse<ValueType>,
"Nested containers are not supported as configurable parameters");
215 auto tokens = split(cleaned,
',');
216 for (
const auto& token : tokens) {
217 std::string trimmed =
trim(token);
218 result.insert(
result.end(), parseScalar<ValueType>(trimmed));
224 template <MapLike MapT>
225 static MapT parseMap(
const std::string&
str)
228 using KeyType =
typename MapT::key_type;
229 using ValueType =
typename MapT::mapped_type;
230 std::string cleaned =
str;
231 if (!cleaned.empty() && cleaned.front() ==
'{' && cleaned.back() ==
'}') {
232 cleaned = cleaned.substr(1, cleaned.length() - 2);
234 if (cleaned.empty()) {
237 if constexpr (Container<KeyType> || Container<ValueType>) {
238 static_assert(AlwaysFalse<MapT>,
"Nested containers are not supported as configurable parameters");
240 auto pairs = split(cleaned,
',');
241 for (
const auto& pair_str : pairs) {
242 auto kv = split(pair_str,
':');
243 if (kv.size() != 2) {
244 throw std::runtime_error(
"Invalid map syntax: " + pair_str +
". Expected 'key:value' format, got ");
246 KeyType
key = parseScalar<KeyType>(
trim(kv[0]));
253 template <
typename T>
254 static T parseScalar(
const std::string&
str)
256 if constexpr (std::is_same_v<T, std::string>) {
258 }
else if constexpr (std::is_same_v<T, bool>) {
259 std::string lower =
str;
260 std::transform(lower.begin(), lower.end(), lower.begin(), [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
261 if (lower ==
"true" || lower ==
"1") {
264 if (lower ==
"false" || lower ==
"0") {
267 throw std::runtime_error(
"Invalid boolean value: " +
str);
268 }
else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>) {
272 throw std::runtime_error(
"Failed to parse '" +
str +
"' as char type");
274 if (
value < std::numeric_limits<T>::min() ||
value > std::numeric_limits<T>::max()) {
275 throw std::runtime_error(
"Value out of range for char type: " +
str);
277 return static_cast<T>(
value);
278 }
else if constexpr (std::is_same_v<T, unsigned char>) {
282 throw std::runtime_error(
"Failed to parse '" +
str +
"' as unsigned char type");
284 if (
value > std::numeric_limits<T>::max()) {
285 throw std::runtime_error(
"Value out of range for unsigned char type: " +
str);
287 return static_cast<T>(
value);
288 }
else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
289 if (!
str.empty() &&
str.front() ==
'-') {
290 throw std::runtime_error(
"Value out of range for unsigned integer type: " +
str);
294 if (
pos !=
str.size() ||
value > std::numeric_limits<T>::max()) {
295 throw std::runtime_error(
"Failed to parse '" +
str +
"' as unsigned integer type");
297 return static_cast<T>(
value);
298 }
else if constexpr (std::is_integral_v<T>) {
301 if (
pos !=
str.size() ||
value < std::numeric_limits<T>::min() ||
value > std::numeric_limits<T>::max()) {
302 throw std::runtime_error(
"Failed to parse '" +
str +
"' as signed integer type");
304 return static_cast<T>(
value);
305 }
else if constexpr (std::is_floating_point_v<T>) {
309 throw std::runtime_error(
"Failed to parse '" +
str +
"' as floating point type");
311 return static_cast<T>(
value);
313 std::istringstream iss(
str);
317 if (iss.fail() || !iss.eof()) {
318 throw std::runtime_error(
"Failed to parse '" +
str +
"' as " +
typeid(T).
name());
325 static std::vector<std::string> split(
const std::string&
str,
char delimiter)
327 std::vector<std::string> tokens;
329 int bracket_depth = 0;
334 }
else if (
c ==
']') {
336 }
else if (
c ==
'{') {
338 }
else if (
c ==
'}') {
340 }
else if (
c == delimiter && bracket_depth == 0 && brace_depth == 0) {
345 tokens.push_back(current);
351 tokens.push_back(current);
374 static std::array<std::string, 3> names = {
"CODE",
"CCDB",
"RT"};
375 return names[(
int)p];
382 virtual void printKeyValues(
bool showprov =
true,
bool useLogger =
false,
bool withPadding =
false,
bool showHash =
false)
const = 0;
403 static void writeJSON(std::string
const&
filename, std::string
const& keyOnly =
"");
405 static void writeINI(std::string
const&
filename, std::string
const& keyOnly =
"");
408 static void write(std::string
const&
filename, std::string
const& keyOnly =
"");
411 template <
typename T>
414 return [](
auto*
tree,
const std::string&
key) -> T {
415 if (!sIsFullyInitialized) {
418 return tree->template get<T>(
key);
422 template <
typename T>
423 static void setValue(std::string
const& mainkey, std::string
const& subkey, T
x)
425 if (!sIsFullyInitialized) {
428 return [&subkey, &
x, &mainkey](
auto*
tree) ->
void {
431 auto key = mainkey +
"." + subkey;
432 if (
tree->template get_optional<std::string>(
key).is_initialized()) {
439 }
catch (std::exception
const& e) {
440 std::cerr <<
"Error in setValue (T) " << e.what() <<
"\n";
447 if (!sIsFullyInitialized) {
448 std::cerr <<
"setProvenance was called on non-initialized ConfigurableParam\n";
452 auto key = mainkey +
"." + subkey;
457 }
catch (std::exception
const& e) {
458 std::cerr <<
"Error in setProvenance (T) " << e.what() <<
"\n";
464 static void setValue(std::string
const&
key, std::string
const& valuestring);
465 static void setEnumValue(
const std::string&,
const std::string&);
466 static void setArrayValue(
const std::string&,
const std::string&);
476 static void setValues(std::vector<std::pair<std::string, std::string>>
const& keyValues);
495 static void updateFromFile(std::string
const&, std::string
const& paramsList =
"",
bool unchangedOnly =
false);
516 virtual void output(std::ostream& out)
const = 0;
540 static std::vector<ConfigurableParam*>* sRegisteredParamClasses;
542 static boost::property_tree::ptree* sPtree;
543 static bool sIsFullyInitialized;
544 static bool sRegisterMode;
551#define O2ParamDef(classname, key) \
553 classname(TRootIOCtor*) {} \
554 classname(classname const&) = delete; \
557 static constexpr char const* const sKey = key; \
558 static classname sInstance; \
559 classname() = default; \
560 template <typename T> \
561 friend class o2::conf::ConfigurableParamHelper; \
562 template <typename T, typename P> \
563 friend class o2::conf::ConfigurableParamPromoter;
566#define O2ParamImpl(classname) classname classname::sInstance;
friend std::ostream & operator<<(std::ostream &out, const ConfigurableParam &me)
virtual ~ConfigurableParam()=default
virtual void printKeyValues(bool showprov=true, bool useLogger=false, bool withPadding=false, bool showHash=false) const =0
static EParamUpdateStatus updateThroughStorageMapWithConversion(std::string const &, std::string const &)
static std::string registeredContainerAsString(const std::string &typeName, const void *source)
virtual void serializeTo(TFile *) const =0
virtual std::string getName() const =0
static void setEnumValue(const std::string &, const std::string &)
static void writeINI(std::string const &filename, std::string const &keyOnly="")
static void setValues(std::vector< std::pair< std::string, std::string > > const &keyValues)
static bool configFileExists(std::string const &filepath)
virtual void putKeyValues(boost::property_tree::ptree *)=0
static std::map< std::string, std::pair< std::type_info const &, void * > > * sKeyToStorageMap
static void printAllRegisteredParamNames()
static bool areRegisteredContainersEqual(const std::string &typeName, const void *lhs, const void *rhs)
static void setProvenance(std::string const &mainkey, std::string const &subkey, EParamProvenance p)
void setRegisterMode(bool b)
static void registerContainerType(const std::string &key, const std::string &typeName)
bool isInitialized() const
static void updateFromFile(std::string const &, std::string const ¶msList="", bool unchangedOnly=false)
static void write(std::string const &filename, std::string const &keyOnly="")
static bool isRegisteredContainerType(const std::string &typeName)
static T getValueAs(std::string key)
static bool assignRegisteredContainer(const std::string &typeName, void *target, const void *source)
virtual size_t getHash() const =0
virtual void initFrom(TFile *)=0
virtual EParamProvenance getMemberProvenance(const std::string &key) const =0
static void setArrayValue(const std::string &, const std::string &)
static void initPropertyTree()
static void setValue(std::string const &mainkey, std::string const &subkey, T x)
static std::string sOutputDir
static std::map< std::string, ConfigurableParam::EParamProvenance > * sValueProvenanceMap
static EParamProvenance getProvenance(const std::string &key)
static const std::string & getOutputDir()
static void printAllKeyValuePairs(bool useLogger=false)
static void toCCDB(std::string filename)
static void writeJSON(std::string const &filename, std::string const &keyOnly="")
static void setOutputDir(const std::string &d)
static std::string toString(EParamProvenance p)
static EParamUpdateStatus updateThroughStorageMap(std::string, std::string, std::type_info const &, void *)
static void setContainerValue(const std::string &, const std::string &)
static EnumRegistry * sEnumRegistry
virtual void output(std::ostream &out) const =0
static std::string getRegisteredContainerType(const std::string &key)
virtual void syncCCDBandRegistry(void *obj)=0
static void fromCCDB(std::string filename)
static void updateFromString(std::string const &)
static T parse(const std::string &str)
static std::string trim(const std::string &str)
void add(const std::string &key, const TDataMember *dm)
std::string toString() const
bool contains(const std::string &key) const
const EnumLegalValues * operator[](const std::string &key) const
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLsizei GLsizei GLchar * source
GLsizei const GLfloat * value
constexpr bool AlwaysFalse
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
bool isLegal(int value) const
bool isLegal(const std::string &value) const
std::vector< std::pair< std::string, int > > vvalues
int getIntValue(const std::string &value) const
std::string toString() const
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))