18#define BOOST_BIND_GLOBAL_PLACEHOLDERS
19#include <boost/algorithm/string/predicate.hpp>
20#include <boost/property_tree/ptree.hpp>
21#include <boost/property_tree/ini_parser.hpp>
22#include <boost/property_tree/json_parser.hpp>
23#include <boost/tokenizer.hpp>
24#include <boost/lexical_cast.hpp>
34#include <fairlogger/Logger.h>
36#include "TDataMember.h"
40#include "TEnumConstant.h"
47std::vector<ConfigurableParam*>* ConfigurableParam::sRegisteredParamClasses =
nullptr;
48boost::property_tree::ptree* ConfigurableParam::sPtree =
nullptr;
54bool ConfigurableParam::sIsFullyInitialized =
false;
55bool ConfigurableParam::sRegisterMode =
true;
66bool keyInTree(boost::property_tree::ptree* pt,
const std::string&
key)
68 if (
key.size() == 0 || pt ==
nullptr) {
73 reply = pt->get_optional<std::string>(
key).is_initialized();
74 }
catch (std::exception
const& e) {
75 LOG(error) <<
"ConfigurableParam: Exception when checking for key " <<
key <<
" : " << e.what();
84 if (!dm->IsEnum() || this->contains(
key)) {
89 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
90 assert(enumtype !=
nullptr);
91 auto constantlist = enumtype->GetConstants();
92 assert(constantlist !=
nullptr);
94 for (
int i = 0;
i < constantlist->GetEntries(); ++
i) {
95 auto e = (TEnumConstant*)(constantlist->At(
i));
96 std::pair<std::string, int>
val(e->GetName(), (
int)e->GetValue());
112 auto entry = std::pair<std::string, EnumLegalValues>(
key, legalVals);
113 this->entries.insert(
entry);
118 std::string out =
"";
119 for (
auto&
entry : entries) {
120 out.append(
entry.first +
" => ");
121 out.append(
entry.second.toString());
130 std::string out =
"";
134 out.append(
value.first);
152 int val = boost::lexical_cast<int>(
value);
156 }
catch (
const boost::bad_lexical_cast& e) {
159 if (pair.first ==
value) {
179 if (!keyOnly.empty()) {
181 boost::property_tree::ptree kTree;
182 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
183 boost::property_tree::write_ini(outfilename, kTree);
184 }
catch (
const boost::property_tree::ptree_bad_path& err) {
185 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeINI";
188 boost::property_tree::write_ini(outfilename, *sPtree);
203 if (!sIsFullyInitialized) {
208 if (sPtree->get_optional<std::string>(
key).is_initialized()) {
209 sPtree->put(
key, valuestring);
215 }
catch (std::exception
const& e) {
216 std::cerr <<
"Error in setValue (string) " << e.what() <<
"\n";
225 LOG(info) <<
"ignoring writing of json file " <<
filename;
230 if (!keyOnly.empty()) {
232 boost::property_tree::ptree kTree;
233 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
234 boost::property_tree::write_json(outfilename, kTree);
235 }
catch (
const boost::property_tree::ptree_bad_path& err) {
236 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
239 boost::property_tree::write_json(outfilename, *sPtree);
248 for (
auto p : *sRegisteredParamClasses) {
249 p->putKeyValues(sPtree);
257 if (!sIsFullyInitialized) {
260 std::cout <<
"####\n";
261 for (
auto p : *sRegisteredParamClasses) {
262 p->printKeyValues(
true, useLogger);
264 std::cout <<
"----\n";
271 if (!sIsFullyInitialized) {
276 throw std::runtime_error(fmt::format(
"provenace of unknown {:s} parameter is requested",
key));
287 if (!sIsFullyInitialized) {
291 for (
auto p : *sRegisteredParamClasses) {
292 p->serializeTo(&
file);
301 if (!sIsFullyInitialized) {
305 for (
auto p : *sRegisteredParamClasses) {
315 if (sRegisteredParamClasses ==
nullptr) {
316 sRegisteredParamClasses =
new std::vector<ConfigurableParam*>;
318 if (sPtree ==
nullptr) {
319 sPtree =
new boost::property_tree::ptree;
322 sKeyToStorageMap =
new std::map<std::string, std::pair<std::type_info const&, void*>>;
332 if (sRegisterMode ==
true) {
333 sRegisteredParamClasses->push_back(
this);
347 sIsFullyInitialized =
true;
354 for (
auto p : *sRegisteredParamClasses) {
355 std::cout << p->getName() <<
"\n";
369 if (!sIsFullyInitialized) {
375 if (cfgfile.length() == 0) {
381 std::vector<std::pair<std::string, std::string>> keyValPairs;
383 std::unordered_map<std::string, int> requestMap;
384 for (
const auto& par : request) {
391 for (
auto& section : pt) {
392 std::string mainKey = section.first;
393 if (requestMap.size()) {
394 if (requestMap.find(mainKey) == requestMap.end()) {
397 requestMap[mainKey] = 1;
400 for (
auto& subKey : section.second) {
401 auto name = subKey.first;
402 auto value = subKey.second.get_value<std::string>();
403 std::string
key = mainKey +
"." +
name;
406 keyValPairs.push_back(pair);
410 }
catch (std::exception
const& error) {
411 LOG(error) <<
"Error while updating params " << error.what();
413 LOG(error) <<
"Unknown while updating params ";
417 for (
const auto& req : requestMap) {
418 if (req.second == 0) {
419 throw std::runtime_error(fmt::format(
"Param {:s} was not found in {:s}", req.first, configFile));
425 }
catch (std::exception
const& error) {
426 LOG(error) <<
"Error while setting values " << error.what();
435 if (!sIsFullyInitialized) {
440 if (cfgStr.length() == 0) {
446 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
447 std::vector<std::pair<std::string, std::string>> pairs;
449 for (
auto& token : tokens) {
450 auto s = token.find(
'=');
451 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
452 LOG(fatal) <<
"Illegal command-line key/value string: " << token;
455 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
484 auto keyValues = toKeyValPairs(
params);
493 if (kv.output_dir ==
"/dev/null") {
505 auto isArray = [](std::string& el) {
506 return el.size() > 0 && (el.at(0) ==
'[') && (el.at(el.size() - 1) ==
']');
509 bool nonFatal = getenv(
"ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") !=
nullptr;
518 for (
auto& keyValue : keyValues) {
519 std::string
key = keyValue.first;
524 LOG(warn) <<
"Ignoring non-existent ConfigurableParam key: " <<
key;
527 LOG(fatal) <<
"Inexistant ConfigurableParam key: " <<
key;
538 if (
value ==
"true") {
540 }
else if (
value ==
"false") {
562 for (
int i = 0;
i < elems.size(); ++
i) {
570 int val = (*sEnumRegistry)[
key]->getIntValue(
value);
572 LOG(fatal) <<
"Illegal value "
574 <<
". Legal string|int values:\n"
575 << (*sEnumRegistry)[
key]->toString() << std::endl;
581void unsupp() { std::cerr <<
"currently unsupported\n"; }
587 for (
int i = 0;
i <
sizeof(T) /
sizeof(
char); ++
i) {
588 if (((
char*)block1)[
i] != ((
char*)block2)[
i]) {
600 if (isMemblockDifferent<T>(addr, targetaddr)) {
601 std::memcpy(targetaddr, addr,
sizeof(T));
611 auto key = mainkey +
"." + subkey;
614 LOG(warn) <<
"Cannot update parameter " <<
key <<
" not found";
619 int type = TDataType::GetType(tinfo);
622 if (iter->second.first != tinfo) {
623 LOG(warn) <<
"Types do not match; cannot update value";
627 auto targetaddress = iter->second.second;
630 return Copy<char>(addr, targetaddress);
634 return Copy<unsigned char>(addr, targetaddress);
638 return Copy<short>(addr, targetaddress);
642 return Copy<unsigned short>(addr, targetaddress);
646 return Copy<int>(addr, targetaddress);
650 return Copy<unsigned int>(addr, targetaddress);
654 return Copy<long>(addr, targetaddress);
658 return Copy<unsigned long>(addr, targetaddress);
662 return Copy<float>(addr, targetaddress);
666 return Copy<double>(addr, targetaddress);
670 return Copy<double>(addr, targetaddress);
678 return Copy<bool>(addr, targetaddress);
682 return Copy<long long>(addr, targetaddress);
686 return Copy<unsigned long long>(addr, targetaddress);
706 return Copy<char*>(addr, targetaddress);
717 case kDataTypeAliasUnsigned_t: {
741 auto addr = boost::lexical_cast<T>(valuestring);
742 if (isMemblockDifferent<T>(targetaddr, (
void*)&addr)) {
743 std::memcpy(targetaddr, (
void*)&addr,
sizeof(T));
753 std::string&
target = *((std::string*)targetaddr);
754 if (
target.compare(valuestring) != 0) {
767 int intvalue = boost::lexical_cast<int>(valuestring);
768 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
769 LOG(error) <<
"Cannot assign " << valuestring <<
" to a char variable";
772 char addr = intvalue;
773 if (isMemblockDifferent<char>(targetaddr, (
void*)&addr)) {
774 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
char));
783 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
784 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
785 LOG(error) <<
"Cannot assign " << valuestring <<
" to an unsigned char variable";
788 unsigned char addr = intvalue;
789 if (isMemblockDifferent<unsigned char>(targetaddr, (
void*)&addr)) {
790 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
unsigned char));
801 LOG(warn) <<
"Cannot update parameter " <<
key <<
" (parameter not found) ";
805 auto targetaddress = iter->second.second;
809 if (iter->second.first ==
typeid(std::string)) {
814 int targettype = TDataType::GetType(iter->second.first);
816 switch (targettype) {
826 return ConvertAndCopy<short>(valuestring, targetaddress);
830 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
834 return ConvertAndCopy<int>(valuestring, targetaddress);
838 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
842 return ConvertAndCopy<long>(valuestring, targetaddress);
846 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
850 return ConvertAndCopy<float>(valuestring, targetaddress);
854 return ConvertAndCopy<double>(valuestring, targetaddress);
858 return ConvertAndCopy<double>(valuestring, targetaddress);
866 return ConvertAndCopy<bool>(valuestring, targetaddress);
870 return ConvertAndCopy<long long>(valuestring, targetaddress);
874 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
906 case kDataTypeAliasUnsigned_t: {
static const KeyValParam & Instance()
static void setInputDir(const std::string &d)
static boost::property_tree::ptree readConfigFile(std::string const &filepath)
static const std::string & getInputDir()
static EParamUpdateStatus updateThroughStorageMapWithConversion(std::string const &, std::string const &)
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)
static std::map< std::string, std::pair< std::type_info const &, void * > > * sKeyToStorageMap
static void printAllRegisteredParamNames()
static void updateFromFile(std::string const &, std::string const ¶msList="", bool unchangedOnly=false)
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 void printAllKeyValuePairs(bool useLogger=false)
static void toCCDB(std::string filename)
static void writeJSON(std::string const &filename, std::string const &keyOnly="")
static EParamUpdateStatus updateThroughStorageMap(std::string, std::string, std::type_info const &, void *)
static EnumRegistry * sEnumRegistry
static void fromCCDB(std::string filename)
static void updateFromString(std::string const &)
void add(const std::string &key, const TDataMember *dm)
std::string toString() const
bool contains(const std::string &key) const
GLuint const GLchar * name
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
GLenum const GLfloat * params
bool keyInTree(boost::property_tree::ptree *pt, const std::string &key)
ConfigurableParam::EParamUpdateStatus ConvertAndCopy< unsigned char >(std::string const &valuestring, void *targetaddr)
bool isMemblockDifferent(void const *block1, void const *block2)
std::ostream & operator<<(std::ostream &out, ConfigurableParam const ¶m)
ConfigurableParam::EParamUpdateStatus ConvertAndCopy< std::string >(std::string const &valuestring, void *targetaddr)
ConfigurableParam::EParamUpdateStatus ConvertAndCopy< char >(std::string const &valuestring, void *targetaddr)
ConfigurableParam::EParamUpdateStatus ConvertAndCopy(std::string const &valuestring, void *targetaddr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
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
static std::string rectifyDirectory(const std::string_view p)
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
static std::string trim_copy(const std::string &s)
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"