252 if constexpr (IsUnorderedSet<ContainerT>::value) {
253 for (
const auto&
value : unorderedValues) {
257 for (
const auto&
value : container) {
258 emitValue(scalarAsString(
static_cast<ValueType
>(
value)));
265template <
typename MapT>
266std::string mapAsString(
const MapT& container)
268 std::ostringstream out;
271 std::vector<std::pair<std::string, std::string>> unorderedValues;
272 if constexpr (IsUnorderedMap<MapT>::value) {
273 for (
const auto& [
key,
value] : container) {
274 unorderedValues.emplace_back(scalarAsString(
key), scalarAsString(
value));
276 std::sort(unorderedValues.begin(), unorderedValues.end());
278 const auto emitValue = [&out, &
first](
const std::string&
key,
const std::string&
value) {
285 if constexpr (IsUnorderedMap<MapT>::value) {
286 for (
const auto& [
key,
value] : unorderedValues) {
290 for (
const auto& [
key,
value] : container) {
291 emitValue(scalarAsString(
key), scalarAsString(
value));
298template <
typename ContainerT>
299ContainerHandler makeSequenceHandler()
303 *
static_cast<ContainerT*
>(
target) = ContainerParser::parse<ContainerT>(
value);
306 return sequenceAsString(*
static_cast<const ContainerT*
>(
source));
309 *
static_cast<ContainerT*
>(
target) = *
static_cast<const ContainerT*
>(
source);
311 [](
const void*
lhs,
const void*
rhs) {
312 return *
static_cast<const ContainerT*
>(
lhs) == *
static_cast<const ContainerT*
>(rhs);
316template <
typename MapT>
317ContainerHandler makeMapHandler()
321 *
static_cast<MapT*
>(
target) = ContainerParser::parse<MapT>(
value);
324 return mapAsString(*
static_cast<const MapT*
>(
source));
327 *
static_cast<MapT*
>(
target) = *
static_cast<const MapT*
>(
source);
329 [](
const void*
lhs,
const void*
rhs) {
330 return *
static_cast<const MapT*
>(
lhs) == *
static_cast<const MapT*
>(rhs);
334template <
typename ContainerT>
335void addHandler(ContainerHandlerRegistry& registry,
const std::string&
name, ContainerHandler handler)
337 registry.byName.emplace(normalizeContainerTypeName(
name), handler);
338 registry.byType.emplace(std::type_index(
typeid(ContainerT)), std::move(handler));
342void addSequenceHandlers(ContainerHandlerRegistry& registry)
344 const std::string tname = TypeName<T>::value;
345 addHandler<std::vector<T>>(registry,
"vector<" + tname +
">", makeSequenceHandler<std::vector<T>>());
346 addHandler<std::list<T>>(registry,
"list<" + tname +
">", makeSequenceHandler<std::list<T>>());
347 addHandler<std::deque<T>>(registry,
"deque<" + tname +
">", makeSequenceHandler<std::deque<T>>());
348 addHandler<std::set<T>>(registry,
"set<" + tname +
">", makeSequenceHandler<std::set<T>>());
349 addHandler<std::unordered_set<T>>(registry,
"unordered_set<" + tname +
">", makeSequenceHandler<std::unordered_set<T>>());
352template <
typename K,
typename V>
353void addMapHandlers(ContainerHandlerRegistry& registry)
355 const std::string kname = TypeName<K>::value;
356 const std::string vname = TypeName<V>::value;
357 addHandler<std::map<K, V>>(registry,
"map<" + kname +
"," + vname +
">", makeMapHandler<std::map<K, V>>());
358 addHandler<std::unordered_map<K, V>>(registry,
"unordered_map<" + kname +
"," + vname +
">", makeMapHandler<std::unordered_map<K, V>>());
362void addMapHandlersForKey(ContainerHandlerRegistry& registry)
364 addMapHandlers<K, bool>(registry);
365 addMapHandlers<K, char>(registry);
366 addMapHandlers<K, signed char>(registry);
367 addMapHandlers<K, unsigned char>(registry);
368 addMapHandlers<K, short>(registry);
369 addMapHandlers<K, unsigned short>(registry);
370 addMapHandlers<K, int>(registry);
371 addMapHandlers<K, unsigned int>(registry);
372 addMapHandlers<K, long>(registry);
373 addMapHandlers<K, unsigned long>(registry);
374 addMapHandlers<K, long long>(registry);
375 addMapHandlers<K, unsigned long long>(registry);
376 addMapHandlers<K, float>(registry);
377 addMapHandlers<K, double>(registry);
378 addMapHandlers<K, std::string>(registry);
381const ContainerHandlerRegistry& containerHandlers()
383 static const ContainerHandlerRegistry handlers = [] {
384 ContainerHandlerRegistry
result;
386 addSequenceHandlers<bool>(
result);
387 addSequenceHandlers<char>(
result);
388 addSequenceHandlers<signed char>(
result);
389 addSequenceHandlers<unsigned char>(
result);
390 addSequenceHandlers<short>(
result);
391 addSequenceHandlers<unsigned short>(
result);
392 addSequenceHandlers<int>(
result);
393 addSequenceHandlers<unsigned int>(
result);
394 addSequenceHandlers<long>(
result);
395 addSequenceHandlers<unsigned long>(
result);
396 addSequenceHandlers<long long>(
result);
397 addSequenceHandlers<unsigned long long>(
result);
398 addSequenceHandlers<float>(
result);
399 addSequenceHandlers<double>(
result);
400 addSequenceHandlers<std::string>(
result);
402 addMapHandlersForKey<bool>(
result);
403 addMapHandlersForKey<char>(
result);
404 addMapHandlersForKey<signed char>(
result);
405 addMapHandlersForKey<unsigned char>(
result);
406 addMapHandlersForKey<short>(
result);
407 addMapHandlersForKey<unsigned short>(
result);
408 addMapHandlersForKey<int>(
result);
409 addMapHandlersForKey<unsigned int>(
result);
410 addMapHandlersForKey<long>(
result);
411 addMapHandlersForKey<unsigned long>(
result);
412 addMapHandlersForKey<long long>(
result);
413 addMapHandlersForKey<unsigned long long>(
result);
414 addMapHandlersForKey<float>(
result);
415 addMapHandlersForKey<double>(
result);
416 addMapHandlersForKey<std::string>(
result);
423const ContainerHandler* getContainerHandler(
const std::string& typeName)
425 const auto normalized = normalizeContainerTypeName(typeName);
426 const auto& handlers = containerHandlers().byName;
428 return iter == handlers.end() ? nullptr : &iter->second;
431const ContainerHandler* getContainerHandler(
const std::type_info&
type)
433 const auto& handlers = containerHandlers().byType;
434 auto iter = handlers.find(std::type_index(
type));
435 return iter == handlers.end() ? nullptr : &iter->second;
438std::pair<std::string_view, std::string_view> splitConfigurableParamKey(std::string_view
key)
440 const auto separator =
key.find(
'.');
441 if (separator == std::string_view::npos) {
444 return {
key.substr(0, separator),
key.substr(separator + 1)};
447std::string findClosestConfigurableParamKey(
const std::string& requestedKey,
448 const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap)
450 if (storageMap.empty()) {
454 const auto [requestedMainKey, requestedSubKey] = splitConfigurableParamKey(requestedKey);
455 bool mainKeyExists =
false;
456 for (
const auto&
entry : storageMap) {
457 const auto mainKey = splitConfigurableParamKey(
entry.first).first;
458 if (mainKey == requestedMainKey) {
459 mainKeyExists =
true;
465 std::size_t closestDistance = std::numeric_limits<std::size_t>::max();
466 for (
const auto&
entry : storageMap) {
468 const auto [mainKey, subKey] = splitConfigurableParamKey(
key);
469 if (mainKeyExists && mainKey != requestedMainKey) {
473 if (
distance < closestDistance || (
distance == closestDistance && (closest.empty() ||
key < closest))) {
481std::string formatUnknownConfigurableParamKeyMessage(
const std::string& prefix,
const std::string&
key,
482 const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap)
485 auto closest = findClosestConfigurableParamKey(
key, storageMap);
486 if (!closest.empty()) {
487 message +=
". Did you mean '" + closest +
"'?";
498 if (!dm->IsEnum() || this->contains(
key)) {
503 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
504 assert(enumtype !=
nullptr);
505 auto constantlist = enumtype->GetConstants();
506 assert(constantlist !=
nullptr);
508 for (
int i = 0;
i < constantlist->GetEntries(); ++
i) {
509 auto e = (TEnumConstant*)(constantlist->At(
i));
510 std::pair<std::string, int>
val(e->GetName(), (
int)e->GetValue());
526 auto entry = std::pair<std::string, EnumLegalValues>(
key, legalVals);
527 this->entries.insert(
entry);
532 std::string out =
"";
533 for (
auto&
entry : entries) {
534 out.append(
entry.first +
" => ");
535 out.append(
entry.second.toString());
544 std::string out =
"";
548 out.append(
value.first);
566 int val = boost::lexical_cast<int>(
value);
570 }
catch (
const boost::bad_lexical_cast& e) {
573 if (pair.first ==
value) {
587 return getContainerHandler(typeName) !=
nullptr;
592 sKeyToContainerTypeMap[
key] = typeName;
597 auto iter = sKeyToContainerTypeMap.find(
key);
598 return iter == sKeyToContainerTypeMap.end() ? std::string{} : iter->second;
603 if (
const auto* handler = getContainerHandler(typeName)) {
612 if (
const auto* handler = getContainerHandler(typeName)) {
613 return handler->equal(lhs, rhs);
620 if (
const auto* handler = getContainerHandler(typeName)) {
621 return handler->serialize(
source);
635 throw std::invalid_argument(fmt::format(
"ConfigurabeParam output file name {} extension is neither .json nor .ini",
filename));
649 if (!keyOnly.empty()) {
651 boost::property_tree::ptree kTree;
653 for (
const auto& k : keys) {
654 kTree.add_child(k, sPtree->get_child(k));
656 boost::property_tree::write_ini(outfilename, kTree);
657 }
catch (
const boost::property_tree::ptree_bad_path& err) {
658 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeINI";
661 boost::property_tree::write_ini(outfilename, *sPtree);
676 if (!sIsFullyInitialized) {
680 auto setValueImpl = [&](std::string
const&
value) {
688 if (sPtree->get_optional<std::string>(
key).is_initialized()) {
698 setValueImpl(valuestring);
703 std::cerr <<
"Error in setValue (string) key is not known\n";
707 if (!expectedSuffix.empty()) {
708 auto valuestringLower = valuestring;
709 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
710 if (valuestringLower.ends_with(expectedSuffix)) {
711 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
712 setValueImpl(strippedValue);
715 for (
const auto& suffix : {
"f",
"l",
"u",
"ul",
"ll",
"ull"}) {
716 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
717 throw std::invalid_argument(
"Wrong type suffix: expected " + expectedSuffix +
" but got " + suffix);
725 }
catch (std::exception
const& e) {
726 std::cerr <<
"Error in setValue (string) " << e.what() <<
"\n";
735 LOG(info) <<
"ignoring writing of json file " <<
filename;
740 if (!keyOnly.empty()) {
742 boost::property_tree::ptree kTree;
744 for (
const auto& k : keys) {
745 kTree.add_child(k, sPtree->get_child(k));
747 boost::property_tree::write_json(outfilename, kTree);
748 }
catch (
const boost::property_tree::ptree_bad_path& err) {
749 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
752 boost::property_tree::write_json(outfilename, *sPtree);
761 std::ostringstream os;
762 if (!keyOnly.empty()) {
764 boost::property_tree::ptree kTree;
766 for (
const auto& k : keys) {
767 kTree.add_child(k, sPtree->get_child(k));
769 boost::property_tree::write_json(os, kTree);
770 }
catch (
const boost::property_tree::ptree_bad_path& err) {
771 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
774 boost::property_tree::write_json(os, *sPtree);
784 for (
auto p : *sRegisteredParamClasses) {
785 p->putKeyValues(sPtree);
793 if (!sIsFullyInitialized) {
796 std::cout <<
"####\n";
797 for (
auto p : *sRegisteredParamClasses) {
798 p->printKeyValues(
true, useLogger);
800 std::cout <<
"----\n";
807 if (!sIsFullyInitialized) {
812 throw std::runtime_error(fmt::format(
"provenace of unknown {:s} parameter is requested",
key));
823 if (!sIsFullyInitialized) {
826 TFile file(
filename.c_str(),
"RECREATE");
827 for (
auto p : *sRegisteredParamClasses) {
828 p->serializeTo(&file);
837 if (!sIsFullyInitialized) {
840 TFile file(
filename.c_str(),
"READ");
841 for (
auto p : *sRegisteredParamClasses) {
851 if (sRegisteredParamClasses ==
nullptr) {
852 sRegisteredParamClasses =
new std::vector<ConfigurableParam*>;
854 if (sPtree ==
nullptr) {
855 sPtree =
new boost::property_tree::ptree;
858 sKeyToStorageMap =
new std::map<std::string, std::pair<std::type_info const&, void*>>;
868 if (sRegisterMode ==
true) {
869 sRegisteredParamClasses->push_back(
this);
883 sIsFullyInitialized =
true;
890 for (
auto p : *sRegisteredParamClasses) {
891 std::cout << p->getName() <<
"\n";
899void updateFromPropertyTree(boost::property_tree::ptree
const& pt, std::string
const&
source, std::string
const& paramsList,
bool unchangedOnly)
901 std::vector<std::pair<std::string, std::string>> keyValPairs;
903 std::unordered_map<std::string, int> requestMap;
904 for (
const auto& par : request) {
911 for (
auto& section : pt) {
912 std::string mainKey = section.first;
913 if (requestMap.size()) {
914 if (requestMap.find(mainKey) == requestMap.end()) {
917 requestMap[mainKey] = 1;
920 for (
auto& subKey : section.second) {
921 auto name = subKey.first;
922 auto value = subKey.second.get_value<std::string>();
923 std::string
key = mainKey +
"." +
name;
926 keyValPairs.push_back(pair);
930 }
catch (std::exception
const& error) {
931 LOG(error) <<
"Error while updating params " <<
error.what();
933 LOG(error) <<
"Unknown while updating params ";
937 for (
const auto& req : requestMap) {
938 if (req.second == 0) {
939 throw std::runtime_error(fmt::format(
"Param {:s} was not found in {:s}", req.first,
source));
945 }
catch (std::exception
const& error) {
946 LOG(error) <<
"Error while setting values " <<
error.what();
959 if (!sIsFullyInitialized) {
965 if (cfgfile.length() == 0) {
976 if (!sIsFullyInitialized) {
981 if (
json.length() == 0) {
985 boost::property_tree::ptree pt;
986 std::istringstream input(
json);
988 boost::property_tree::read_json(input, pt);
989 }
catch (
const boost::property_tree::ptree_error& e) {
990 LOG(fatal) <<
"Failed to read JSON config string (" << e.what() <<
")";
993 updateFromPropertyTree(pt,
"provided JSON string", paramsList, unchangedOnly);
1001 if (!sIsFullyInitialized) {
1006 if (cfgStr.length() == 0) {
1012 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
1013 std::vector<std::pair<std::string, std::string>> pairs;
1015 for (
auto& token : tokens) {
1016 auto s = token.find(
'=');
1017 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
1018 LOG(fatal) <<
"Illegal command-line key/value string: " << token;
1021 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
1050 auto keyValues = toKeyValPairs(
params);
1059 if (kv.output_dir ==
"/dev/null") {
1071 auto isArray = [](std::string& el) {
1072 return el.size() > 0 && (el.at(0) ==
'[') && (el.at(el.size() - 1) ==
']');
1075 bool nonFatal = getenv(
"ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") !=
nullptr;
1084 for (
auto& keyValue : keyValues) {
1085 std::string
key = keyValue.first;
1090 LOG(warn) << formatUnknownConfigurableParamKeyMessage(
"Ignoring non-existent ConfigurableParam key: ",
key, *
sKeyToStorageMap);
1093 LOG(fatal) << formatUnknownConfigurableParamKeyMessage(
"Inexistent ConfigurableParam key: ",
key, *
sKeyToStorageMap);
1112 if (
value ==
"true") {
1114 }
else if (
value ==
"false") {
1134 for (
int i = 0;
i < elems.size(); ++
i) {
1144 LOG(error) <<
"Container parameter " <<
key <<
" not found";
1147 void* targetAddress = iter->second.second;
1149 const auto* handler = typeName.empty() ? getContainerHandler(iter->second.first) : getContainerHandler(typeName);
1151 LOG(error) <<
"Unsupported container configuration: " << (typeName.empty() ? iter->second.first.name() : typeName);
1155 handler->parseAssign(targetAddress,
value);
1156 sPtree->put(
key, handler->serialize(targetAddress));
1160 }
catch (
const std::exception& e) {
1161 LOG(error) <<
"Failed to parse container " <<
key <<
": " << e.what();
1167 int val = (*sEnumRegistry)[
key]->getIntValue(
value);
1169 LOG(fatal) <<
"Illegal value "
1171 <<
". Legal string|int values:\n"
1172 << (*sEnumRegistry)[
key]->toString() << std::endl;
1178void unsupp() { std::cerr <<
"currently unsupported\n"; }
1180template <
typename T>
1184 for (
int i = 0;
i <
sizeof(T) /
sizeof(
char); ++
i) {
1185 if (((
char*)block1)[
i] != ((
char*)block2)[
i]) {
1194template <
typename T>
1197 if (isMemblockDifferent<T>(addr, targetaddr)) {
1198 std::memcpy(targetaddr, addr,
sizeof(T));
1208 auto key = mainkey +
"." + subkey;
1211 LOG(warn) <<
"Cannot update parameter " <<
key <<
" not found";
1216 int type = TDataType::GetType(tinfo);
1219 if (iter->second.first != tinfo) {
1220 LOG(warn) <<
"Types do not match; cannot update value";
1224 auto targetaddress = iter->second.second;
1227 return Copy<char>(addr, targetaddress);
1231 return Copy<unsigned char>(addr, targetaddress);
1235 return Copy<short>(addr, targetaddress);
1239 return Copy<unsigned short>(addr, targetaddress);
1243 return Copy<int>(addr, targetaddress);
1247 return Copy<unsigned int>(addr, targetaddress);
1251 return Copy<long>(addr, targetaddress);
1255 return Copy<unsigned long>(addr, targetaddress);
1259 return Copy<float>(addr, targetaddress);
1263 return Copy<double>(addr, targetaddress);
1267 return Copy<double>(addr, targetaddress);
1275 return Copy<bool>(addr, targetaddress);
1279 return Copy<long long>(addr, targetaddress);
1283 return Copy<unsigned long long>(addr, targetaddress);
1303 return Copy<char*>(addr, targetaddress);
1314 case kDataTypeAliasUnsigned_t: {
1335template <
typename T>
1338 auto addr = boost::lexical_cast<T>(valuestring);
1339 if (isMemblockDifferent<T>(targetaddr, (
void*)&addr)) {
1340 std::memcpy(targetaddr, (
void*)&addr,
sizeof(T));
1350 std::string&
target = *((std::string*)targetaddr);
1351 if (
target.compare(valuestring) != 0) {
1364 int intvalue = boost::lexical_cast<int>(valuestring);
1365 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
1366 LOG(error) <<
"Cannot assign " << valuestring <<
" to a char variable";
1369 char addr = intvalue;
1370 if (isMemblockDifferent<char>(targetaddr, (
void*)&addr)) {
1371 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
char));
1380 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
1381 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
1382 LOG(error) <<
"Cannot assign " << valuestring <<
" to an unsigned char variable";
1385 unsigned char addr = intvalue;
1386 if (isMemblockDifferent<unsigned char>(targetaddr, (
void*)&addr)) {
1387 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
unsigned char));
1398 LOG(warn) <<
"Cannot update parameter " <<
key <<
" (parameter not found) ";
1402 auto targetaddress = iter->second.second;
1406 if (iter->second.first ==
typeid(std::string)) {
1411 int targettype = TDataType::GetType(iter->second.first);
1413 switch (targettype) {
1423 return ConvertAndCopy<short>(valuestring, targetaddress);
1427 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
1431 return ConvertAndCopy<int>(valuestring, targetaddress);
1435 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
1439 return ConvertAndCopy<long>(valuestring, targetaddress);
1443 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
1447 return ConvertAndCopy<float>(valuestring, targetaddress);
1451 return ConvertAndCopy<double>(valuestring, targetaddress);
1455 return ConvertAndCopy<double>(valuestring, targetaddress);
1463 return ConvertAndCopy<bool>(valuestring, targetaddress);
1467 return ConvertAndCopy<long long>(valuestring, targetaddress);
1471 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
1503 case kDataTypeAliasUnsigned_t: {