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"