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) {
203 if (!keyOnly.empty()) {
205 boost::property_tree::ptree kTree;
206 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
207 boost::property_tree::write_ini(outfilename, kTree);
208 }
catch (
const boost::property_tree::ptree_bad_path& err) {
209 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeINI";
212 boost::property_tree::write_ini(outfilename, *sPtree);
227 if (!sIsFullyInitialized) {
231 auto setValueImpl = [&](std::string
const&
value) {
239 if (sPtree->get_optional<std::string>(
key).is_initialized()) {
242 setValueImpl(valuestring);
247 std::cerr <<
"Error in setValue (string) key is not known\n";
251 if (!expectedSuffix.empty()) {
252 auto valuestringLower = valuestring;
253 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), tolower);
254 if (valuestringLower.ends_with(expectedSuffix)) {
255 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
256 setValueImpl(strippedValue);
259 for (
const auto& suffix : {
"f",
"l",
"u",
"ul",
"ll",
"ull"}) {
260 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
261 throw std::invalid_argument(
"Wrong type suffix: expected " + expectedSuffix +
" but got " + suffix);
269 }
catch (std::exception
const& e) {
270 std::cerr <<
"Error in setValue (string) " << e.what() <<
"\n";
279 LOG(info) <<
"ignoring writing of json file " <<
filename;
284 if (!keyOnly.empty()) {
286 boost::property_tree::ptree kTree;
287 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
288 boost::property_tree::write_json(outfilename, kTree);
289 }
catch (
const boost::property_tree::ptree_bad_path& err) {
290 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
293 boost::property_tree::write_json(outfilename, *sPtree);
302 for (
auto p : *sRegisteredParamClasses) {
303 p->putKeyValues(sPtree);
311 if (!sIsFullyInitialized) {
314 std::cout <<
"####\n";
315 for (
auto p : *sRegisteredParamClasses) {
316 p->printKeyValues(
true, useLogger);
318 std::cout <<
"----\n";
325 if (!sIsFullyInitialized) {
330 throw std::runtime_error(fmt::format(
"provenace of unknown {:s} parameter is requested",
key));
341 if (!sIsFullyInitialized) {
345 for (
auto p : *sRegisteredParamClasses) {
346 p->serializeTo(&
file);
355 if (!sIsFullyInitialized) {
359 for (
auto p : *sRegisteredParamClasses) {
369 if (sRegisteredParamClasses ==
nullptr) {
370 sRegisteredParamClasses =
new std::vector<ConfigurableParam*>;
372 if (sPtree ==
nullptr) {
373 sPtree =
new boost::property_tree::ptree;
376 sKeyToStorageMap =
new std::map<std::string, std::pair<std::type_info const&, void*>>;
386 if (sRegisterMode ==
true) {
387 sRegisteredParamClasses->push_back(
this);
401 sIsFullyInitialized =
true;
408 for (
auto p : *sRegisteredParamClasses) {
409 std::cout << p->getName() <<
"\n";
423 if (!sIsFullyInitialized) {
429 if (cfgfile.length() == 0) {
435 std::vector<std::pair<std::string, std::string>> keyValPairs;
437 std::unordered_map<std::string, int> requestMap;
438 for (
const auto& par : request) {
445 for (
auto& section : pt) {
446 std::string mainKey = section.first;
447 if (requestMap.size()) {
448 if (requestMap.find(mainKey) == requestMap.end()) {
451 requestMap[mainKey] = 1;
454 for (
auto& subKey : section.second) {
455 auto name = subKey.first;
456 auto value = subKey.second.get_value<std::string>();
457 std::string
key = mainKey +
"." +
name;
460 keyValPairs.push_back(pair);
464 }
catch (std::exception
const& error) {
465 LOG(error) <<
"Error while updating params " << error.what();
467 LOG(error) <<
"Unknown while updating params ";
471 for (
const auto& req : requestMap) {
472 if (req.second == 0) {
473 throw std::runtime_error(fmt::format(
"Param {:s} was not found in {:s}", req.first, configFile));
479 }
catch (std::exception
const& error) {
480 LOG(error) <<
"Error while setting values " << error.what();
489 if (!sIsFullyInitialized) {
494 if (cfgStr.length() == 0) {
500 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
501 std::vector<std::pair<std::string, std::string>> pairs;
503 for (
auto& token : tokens) {
504 auto s = token.find(
'=');
505 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
506 LOG(fatal) <<
"Illegal command-line key/value string: " << token;
509 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
538 auto keyValues = toKeyValPairs(
params);
547 if (kv.output_dir ==
"/dev/null") {
559 auto isArray = [](std::string& el) {
560 return el.size() > 0 && (el.at(0) ==
'[') && (el.at(el.size() - 1) ==
']');
563 bool nonFatal = getenv(
"ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") !=
nullptr;
572 for (
auto& keyValue : keyValues) {
573 std::string
key = keyValue.first;
578 LOG(warn) <<
"Ignoring non-existent ConfigurableParam key: " <<
key;
581 LOG(fatal) <<
"Inexistant ConfigurableParam key: " <<
key;
592 if (
value ==
"true") {
594 }
else if (
value ==
"false") {
616 for (
int i = 0;
i < elems.size(); ++
i) {
624 int val = (*sEnumRegistry)[
key]->getIntValue(
value);
626 LOG(fatal) <<
"Illegal value "
628 <<
". Legal string|int values:\n"
629 << (*sEnumRegistry)[
key]->toString() << std::endl;
635void unsupp() { std::cerr <<
"currently unsupported\n"; }
641 for (
int i = 0;
i <
sizeof(T) /
sizeof(
char); ++
i) {
642 if (((
char*)block1)[
i] != ((
char*)block2)[
i]) {
654 if (isMemblockDifferent<T>(addr, targetaddr)) {
655 std::memcpy(targetaddr, addr,
sizeof(T));
665 auto key = mainkey +
"." + subkey;
668 LOG(warn) <<
"Cannot update parameter " <<
key <<
" not found";
673 int type = TDataType::GetType(tinfo);
676 if (iter->second.first != tinfo) {
677 LOG(warn) <<
"Types do not match; cannot update value";
681 auto targetaddress = iter->second.second;
684 return Copy<char>(addr, targetaddress);
688 return Copy<unsigned char>(addr, targetaddress);
692 return Copy<short>(addr, targetaddress);
696 return Copy<unsigned short>(addr, targetaddress);
700 return Copy<int>(addr, targetaddress);
704 return Copy<unsigned int>(addr, targetaddress);
708 return Copy<long>(addr, targetaddress);
712 return Copy<unsigned long>(addr, targetaddress);
716 return Copy<float>(addr, targetaddress);
720 return Copy<double>(addr, targetaddress);
724 return Copy<double>(addr, targetaddress);
732 return Copy<bool>(addr, targetaddress);
736 return Copy<long long>(addr, targetaddress);
740 return Copy<unsigned long long>(addr, targetaddress);
760 return Copy<char*>(addr, targetaddress);
771 case kDataTypeAliasUnsigned_t: {
795 auto addr = boost::lexical_cast<T>(valuestring);
796 if (isMemblockDifferent<T>(targetaddr, (
void*)&addr)) {
797 std::memcpy(targetaddr, (
void*)&addr,
sizeof(T));
807 std::string&
target = *((std::string*)targetaddr);
808 if (
target.compare(valuestring) != 0) {
821 int intvalue = boost::lexical_cast<int>(valuestring);
822 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
823 LOG(error) <<
"Cannot assign " << valuestring <<
" to a char variable";
826 char addr = intvalue;
827 if (isMemblockDifferent<char>(targetaddr, (
void*)&addr)) {
828 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
char));
837 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
838 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
839 LOG(error) <<
"Cannot assign " << valuestring <<
" to an unsigned char variable";
842 unsigned char addr = intvalue;
843 if (isMemblockDifferent<unsigned char>(targetaddr, (
void*)&addr)) {
844 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
unsigned char));
855 LOG(warn) <<
"Cannot update parameter " <<
key <<
" (parameter not found) ";
859 auto targetaddress = iter->second.second;
863 if (iter->second.first ==
typeid(std::string)) {
868 int targettype = TDataType::GetType(iter->second.first);
870 switch (targettype) {
880 return ConvertAndCopy<short>(valuestring, targetaddress);
884 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
888 return ConvertAndCopy<int>(valuestring, targetaddress);
892 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
896 return ConvertAndCopy<long>(valuestring, targetaddress);
900 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
904 return ConvertAndCopy<float>(valuestring, targetaddress);
908 return ConvertAndCopy<double>(valuestring, targetaddress);
912 return ConvertAndCopy<double>(valuestring, targetaddress);
920 return ConvertAndCopy<bool>(valuestring, targetaddress);
924 return ConvertAndCopy<long long>(valuestring, targetaddress);
928 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
960 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
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)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"