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();
83 if (
type ==
typeid(
float)) {
86 if (
type ==
typeid(
long double)) {
89 if (
type ==
typeid(
unsigned int)) {
92 if (
type ==
typeid(
unsigned long)) {
95 if (
type ==
typeid(
long long)) {
98 if (
type ==
typeid(
unsigned long long)) {
108 if (!dm->IsEnum() || this->contains(
key)) {
113 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
114 assert(enumtype !=
nullptr);
115 auto constantlist = enumtype->GetConstants();
116 assert(constantlist !=
nullptr);
118 for (
int i = 0;
i < constantlist->GetEntries(); ++
i) {
119 auto e = (TEnumConstant*)(constantlist->At(
i));
120 std::pair<std::string, int>
val(e->GetName(), (
int)e->GetValue());
136 auto entry = std::pair<std::string, EnumLegalValues>(
key, legalVals);
137 this->entries.insert(
entry);
142 std::string out =
"";
143 for (
auto&
entry : entries) {
144 out.append(
entry.first +
" => ");
145 out.append(
entry.second.toString());
154 std::string out =
"";
158 out.append(
value.first);
176 int val = boost::lexical_cast<int>(
value);
180 }
catch (
const boost::bad_lexical_cast& e) {
183 if (pair.first ==
value) {
202 throw std::invalid_argument(fmt::format(
"ConfigurabeParam output file name {} extension is neither .json nor .ini",
filename));
216 if (!keyOnly.empty()) {
218 boost::property_tree::ptree kTree;
220 for (
const auto& k : keys) {
221 kTree.add_child(k, sPtree->get_child(k));
223 boost::property_tree::write_ini(outfilename, kTree);
224 }
catch (
const boost::property_tree::ptree_bad_path& err) {
225 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeINI";
228 boost::property_tree::write_ini(outfilename, *sPtree);
243 if (!sIsFullyInitialized) {
247 auto setValueImpl = [&](std::string
const&
value) {
255 if (sPtree->get_optional<std::string>(
key).is_initialized()) {
258 setValueImpl(valuestring);
263 std::cerr <<
"Error in setValue (string) key is not known\n";
267 if (!expectedSuffix.empty()) {
268 auto valuestringLower = valuestring;
269 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), tolower);
270 if (valuestringLower.ends_with(expectedSuffix)) {
271 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
272 setValueImpl(strippedValue);
275 for (
const auto& suffix : {
"f",
"l",
"u",
"ul",
"ll",
"ull"}) {
276 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
277 throw std::invalid_argument(
"Wrong type suffix: expected " + expectedSuffix +
" but got " + suffix);
285 }
catch (std::exception
const& e) {
286 std::cerr <<
"Error in setValue (string) " << e.what() <<
"\n";
295 LOG(info) <<
"ignoring writing of json file " <<
filename;
300 if (!keyOnly.empty()) {
302 boost::property_tree::ptree kTree;
304 for (
const auto& k : keys) {
305 kTree.add_child(k, sPtree->get_child(k));
307 boost::property_tree::write_json(outfilename, kTree);
308 }
catch (
const boost::property_tree::ptree_bad_path& err) {
309 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
312 boost::property_tree::write_json(outfilename, *sPtree);
321 for (
auto p : *sRegisteredParamClasses) {
322 p->putKeyValues(sPtree);
330 if (!sIsFullyInitialized) {
333 std::cout <<
"####\n";
334 for (
auto p : *sRegisteredParamClasses) {
335 p->printKeyValues(
true, useLogger);
337 std::cout <<
"----\n";
344 if (!sIsFullyInitialized) {
349 throw std::runtime_error(fmt::format(
"provenace of unknown {:s} parameter is requested",
key));
360 if (!sIsFullyInitialized) {
364 for (
auto p : *sRegisteredParamClasses) {
365 p->serializeTo(&
file);
374 if (!sIsFullyInitialized) {
378 for (
auto p : *sRegisteredParamClasses) {
388 if (sRegisteredParamClasses ==
nullptr) {
389 sRegisteredParamClasses =
new std::vector<ConfigurableParam*>;
391 if (sPtree ==
nullptr) {
392 sPtree =
new boost::property_tree::ptree;
395 sKeyToStorageMap =
new std::map<std::string, std::pair<std::type_info const&, void*>>;
405 if (sRegisterMode ==
true) {
406 sRegisteredParamClasses->push_back(
this);
420 sIsFullyInitialized =
true;
427 for (
auto p : *sRegisteredParamClasses) {
428 std::cout << p->getName() <<
"\n";
442 if (!sIsFullyInitialized) {
448 if (cfgfile.length() == 0) {
454 std::vector<std::pair<std::string, std::string>> keyValPairs;
456 std::unordered_map<std::string, int> requestMap;
457 for (
const auto& par : request) {
464 for (
auto& section : pt) {
465 std::string mainKey = section.first;
466 if (requestMap.size()) {
467 if (requestMap.find(mainKey) == requestMap.end()) {
470 requestMap[mainKey] = 1;
473 for (
auto& subKey : section.second) {
474 auto name = subKey.first;
475 auto value = subKey.second.get_value<std::string>();
476 std::string
key = mainKey +
"." +
name;
479 keyValPairs.push_back(pair);
483 }
catch (std::exception
const& error) {
484 LOG(error) <<
"Error while updating params " << error.what();
486 LOG(error) <<
"Unknown while updating params ";
490 for (
const auto& req : requestMap) {
491 if (req.second == 0) {
492 throw std::runtime_error(fmt::format(
"Param {:s} was not found in {:s}", req.first, configFile));
498 }
catch (std::exception
const& error) {
499 LOG(error) <<
"Error while setting values " << error.what();
508 if (!sIsFullyInitialized) {
513 if (cfgStr.length() == 0) {
519 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
520 std::vector<std::pair<std::string, std::string>> pairs;
522 for (
auto& token : tokens) {
523 auto s = token.find(
'=');
524 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
525 LOG(fatal) <<
"Illegal command-line key/value string: " << token;
528 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
557 auto keyValues = toKeyValPairs(
params);
566 if (kv.output_dir ==
"/dev/null") {
578 auto isArray = [](std::string& el) {
579 return el.size() > 0 && (el.at(0) ==
'[') && (el.at(el.size() - 1) ==
']');
582 bool nonFatal = getenv(
"ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") !=
nullptr;
591 for (
auto& keyValue : keyValues) {
592 std::string
key = keyValue.first;
597 LOG(warn) <<
"Ignoring non-existent ConfigurableParam key: " <<
key;
600 LOG(fatal) <<
"Inexistant ConfigurableParam key: " <<
key;
611 if (
value ==
"true") {
613 }
else if (
value ==
"false") {
635 for (
int i = 0;
i < elems.size(); ++
i) {
643 int val = (*sEnumRegistry)[
key]->getIntValue(
value);
645 LOG(fatal) <<
"Illegal value "
647 <<
". Legal string|int values:\n"
648 << (*sEnumRegistry)[
key]->toString() << std::endl;
654void unsupp() { std::cerr <<
"currently unsupported\n"; }
660 for (
int i = 0;
i <
sizeof(T) /
sizeof(
char); ++
i) {
661 if (((
char*)block1)[
i] != ((
char*)block2)[
i]) {
673 if (isMemblockDifferent<T>(addr, targetaddr)) {
674 std::memcpy(targetaddr, addr,
sizeof(T));
684 auto key = mainkey +
"." + subkey;
687 LOG(warn) <<
"Cannot update parameter " <<
key <<
" not found";
692 int type = TDataType::GetType(tinfo);
695 if (iter->second.first != tinfo) {
696 LOG(warn) <<
"Types do not match; cannot update value";
700 auto targetaddress = iter->second.second;
703 return Copy<char>(addr, targetaddress);
707 return Copy<unsigned char>(addr, targetaddress);
711 return Copy<short>(addr, targetaddress);
715 return Copy<unsigned short>(addr, targetaddress);
719 return Copy<int>(addr, targetaddress);
723 return Copy<unsigned int>(addr, targetaddress);
727 return Copy<long>(addr, targetaddress);
731 return Copy<unsigned long>(addr, targetaddress);
735 return Copy<float>(addr, targetaddress);
739 return Copy<double>(addr, targetaddress);
743 return Copy<double>(addr, targetaddress);
751 return Copy<bool>(addr, targetaddress);
755 return Copy<long long>(addr, targetaddress);
759 return Copy<unsigned long long>(addr, targetaddress);
779 return Copy<char*>(addr, targetaddress);
790 case kDataTypeAliasUnsigned_t: {
814 auto addr = boost::lexical_cast<T>(valuestring);
815 if (isMemblockDifferent<T>(targetaddr, (
void*)&addr)) {
816 std::memcpy(targetaddr, (
void*)&addr,
sizeof(T));
826 std::string&
target = *((std::string*)targetaddr);
827 if (
target.compare(valuestring) != 0) {
840 int intvalue = boost::lexical_cast<int>(valuestring);
841 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
842 LOG(error) <<
"Cannot assign " << valuestring <<
" to a char variable";
845 char addr = intvalue;
846 if (isMemblockDifferent<char>(targetaddr, (
void*)&addr)) {
847 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
char));
856 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
857 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
858 LOG(error) <<
"Cannot assign " << valuestring <<
" to an unsigned char variable";
861 unsigned char addr = intvalue;
862 if (isMemblockDifferent<unsigned char>(targetaddr, (
void*)&addr)) {
863 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
unsigned char));
874 LOG(warn) <<
"Cannot update parameter " <<
key <<
" (parameter not found) ";
878 auto targetaddress = iter->second.second;
882 if (iter->second.first ==
typeid(std::string)) {
887 int targettype = TDataType::GetType(iter->second.first);
889 switch (targettype) {
899 return ConvertAndCopy<short>(valuestring, targetaddress);
903 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
907 return ConvertAndCopy<int>(valuestring, targetaddress);
911 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
915 return ConvertAndCopy<long>(valuestring, targetaddress);
919 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
923 return ConvertAndCopy<float>(valuestring, targetaddress);
927 return ConvertAndCopy<double>(valuestring, targetaddress);
931 return ConvertAndCopy<double>(valuestring, targetaddress);
939 return ConvertAndCopy<bool>(valuestring, targetaddress);
943 return ConvertAndCopy<long long>(valuestring, targetaddress);
947 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
979 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 write(std::string const &filename, std::string const &keyOnly="")
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
std::string getLiteralSuffixFromType(const std::type_info &type)
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)
static bool endsWith(const std::string &s, const std::string &ending)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"