251 if constexpr (IsUnorderedSet<ContainerT>::value) {
252 for (
const auto&
value : unorderedValues) {
256 for (
const auto&
value : container) {
257 emitValue(scalarAsString(
static_cast<ValueType
>(
value)));
264template <
typename MapT>
265std::string mapAsString(
const MapT& container)
267 std::ostringstream out;
270 std::vector<std::pair<std::string, std::string>> unorderedValues;
271 if constexpr (IsUnorderedMap<MapT>::value) {
272 for (
const auto& [
key,
value] : container) {
273 unorderedValues.emplace_back(scalarAsString(
key), scalarAsString(
value));
275 std::sort(unorderedValues.begin(), unorderedValues.end());
277 const auto emitValue = [&out, &
first](
const std::string&
key,
const std::string&
value) {
284 if constexpr (IsUnorderedMap<MapT>::value) {
285 for (
const auto& [
key,
value] : unorderedValues) {
289 for (
const auto& [
key,
value] : container) {
290 emitValue(scalarAsString(
key), scalarAsString(
value));
297template <
typename ContainerT>
298ContainerHandler makeSequenceHandler()
302 *
static_cast<ContainerT*
>(
target) = ContainerParser::parse<ContainerT>(
value);
305 return sequenceAsString(*
static_cast<const ContainerT*
>(
source));
308 *
static_cast<ContainerT*
>(
target) = *
static_cast<const ContainerT*
>(
source);
310 [](
const void*
lhs,
const void*
rhs) {
311 return *
static_cast<const ContainerT*
>(
lhs) == *
static_cast<const ContainerT*
>(rhs);
315template <
typename MapT>
316ContainerHandler makeMapHandler()
320 *
static_cast<MapT*
>(
target) = ContainerParser::parse<MapT>(
value);
323 return mapAsString(*
static_cast<const MapT*
>(
source));
326 *
static_cast<MapT*
>(
target) = *
static_cast<const MapT*
>(
source);
328 [](
const void*
lhs,
const void*
rhs) {
329 return *
static_cast<const MapT*
>(
lhs) == *
static_cast<const MapT*
>(rhs);
333template <
typename ContainerT>
334void addHandler(ContainerHandlerRegistry& registry,
const std::string&
name, ContainerHandler handler)
336 registry.byName.emplace(normalizeContainerTypeName(
name), handler);
337 registry.byType.emplace(std::type_index(
typeid(ContainerT)), std::move(handler));
341void addSequenceHandlers(ContainerHandlerRegistry& registry)
343 const std::string tname = TypeName<T>::value;
344 addHandler<std::vector<T>>(registry,
"vector<" + tname +
">", makeSequenceHandler<std::vector<T>>());
345 addHandler<std::list<T>>(registry,
"list<" + tname +
">", makeSequenceHandler<std::list<T>>());
346 addHandler<std::deque<T>>(registry,
"deque<" + tname +
">", makeSequenceHandler<std::deque<T>>());
347 addHandler<std::set<T>>(registry,
"set<" + tname +
">", makeSequenceHandler<std::set<T>>());
348 addHandler<std::unordered_set<T>>(registry,
"unordered_set<" + tname +
">", makeSequenceHandler<std::unordered_set<T>>());
351template <
typename K,
typename V>
352void addMapHandlers(ContainerHandlerRegistry& registry)
354 const std::string kname = TypeName<K>::value;
355 const std::string vname = TypeName<V>::value;
356 addHandler<std::map<K, V>>(registry,
"map<" + kname +
"," + vname +
">", makeMapHandler<std::map<K, V>>());
357 addHandler<std::unordered_map<K, V>>(registry,
"unordered_map<" + kname +
"," + vname +
">", makeMapHandler<std::unordered_map<K, V>>());
361void addMapHandlersForKey(ContainerHandlerRegistry& registry)
363 addMapHandlers<K, bool>(registry);
364 addMapHandlers<K, char>(registry);
365 addMapHandlers<K, signed char>(registry);
366 addMapHandlers<K, unsigned char>(registry);
367 addMapHandlers<K, short>(registry);
368 addMapHandlers<K, unsigned short>(registry);
369 addMapHandlers<K, int>(registry);
370 addMapHandlers<K, unsigned int>(registry);
371 addMapHandlers<K, long>(registry);
372 addMapHandlers<K, unsigned long>(registry);
373 addMapHandlers<K, long long>(registry);
374 addMapHandlers<K, unsigned long long>(registry);
375 addMapHandlers<K, float>(registry);
376 addMapHandlers<K, double>(registry);
377 addMapHandlers<K, std::string>(registry);
380const ContainerHandlerRegistry& containerHandlers()
382 static const ContainerHandlerRegistry handlers = [] {
383 ContainerHandlerRegistry
result;
385 addSequenceHandlers<bool>(
result);
386 addSequenceHandlers<char>(
result);
387 addSequenceHandlers<signed char>(
result);
388 addSequenceHandlers<unsigned char>(
result);
389 addSequenceHandlers<short>(
result);
390 addSequenceHandlers<unsigned short>(
result);
391 addSequenceHandlers<int>(
result);
392 addSequenceHandlers<unsigned int>(
result);
393 addSequenceHandlers<long>(
result);
394 addSequenceHandlers<unsigned long>(
result);
395 addSequenceHandlers<long long>(
result);
396 addSequenceHandlers<unsigned long long>(
result);
397 addSequenceHandlers<float>(
result);
398 addSequenceHandlers<double>(
result);
399 addSequenceHandlers<std::string>(
result);
401 addMapHandlersForKey<bool>(
result);
402 addMapHandlersForKey<char>(
result);
403 addMapHandlersForKey<signed char>(
result);
404 addMapHandlersForKey<unsigned char>(
result);
405 addMapHandlersForKey<short>(
result);
406 addMapHandlersForKey<unsigned short>(
result);
407 addMapHandlersForKey<int>(
result);
408 addMapHandlersForKey<unsigned int>(
result);
409 addMapHandlersForKey<long>(
result);
410 addMapHandlersForKey<unsigned long>(
result);
411 addMapHandlersForKey<long long>(
result);
412 addMapHandlersForKey<unsigned long long>(
result);
413 addMapHandlersForKey<float>(
result);
414 addMapHandlersForKey<double>(
result);
415 addMapHandlersForKey<std::string>(
result);
422const ContainerHandler* getContainerHandler(
const std::string& typeName)
424 const auto normalized = normalizeContainerTypeName(typeName);
425 const auto& handlers = containerHandlers().byName;
427 return iter == handlers.end() ? nullptr : &iter->second;
430const ContainerHandler* getContainerHandler(
const std::type_info&
type)
432 const auto& handlers = containerHandlers().byType;
433 auto iter = handlers.find(std::type_index(
type));
434 return iter == handlers.end() ? nullptr : &iter->second;
437std::pair<std::string_view, std::string_view> splitConfigurableParamKey(std::string_view
key)
439 const auto separator =
key.find(
'.');
440 if (separator == std::string_view::npos) {
443 return {
key.substr(0, separator),
key.substr(separator + 1)};
446std::string findClosestConfigurableParamKey(
const std::string& requestedKey,
447 const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap)
449 if (storageMap.empty()) {
453 const auto [requestedMainKey, requestedSubKey] = splitConfigurableParamKey(requestedKey);
454 bool mainKeyExists =
false;
455 for (
const auto&
entry : storageMap) {
456 const auto mainKey = splitConfigurableParamKey(
entry.first).first;
457 if (mainKey == requestedMainKey) {
458 mainKeyExists =
true;
464 std::size_t closestDistance = std::numeric_limits<std::size_t>::max();
465 for (
const auto&
entry : storageMap) {
467 const auto [mainKey, subKey] = splitConfigurableParamKey(
key);
468 if (mainKeyExists && mainKey != requestedMainKey) {
472 if (
distance < closestDistance || (
distance == closestDistance && (closest.empty() ||
key < closest))) {
480std::string formatUnknownConfigurableParamKeyMessage(
const std::string& prefix,
const std::string&
key,
481 const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap)
484 auto closest = findClosestConfigurableParamKey(
key, storageMap);
485 if (!closest.empty()) {
486 message +=
". Did you mean '" + closest +
"'?";
497 if (!dm->IsEnum() || this->contains(
key)) {
502 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
503 assert(enumtype !=
nullptr);
504 auto constantlist = enumtype->GetConstants();
505 assert(constantlist !=
nullptr);
507 for (
int i = 0;
i < constantlist->GetEntries(); ++
i) {
508 auto e = (TEnumConstant*)(constantlist->At(
i));
509 std::pair<std::string, int>
val(e->GetName(), (
int)e->GetValue());
525 auto entry = std::pair<std::string, EnumLegalValues>(
key, legalVals);
526 this->entries.insert(
entry);
531 std::string out =
"";
532 for (
auto&
entry : entries) {
533 out.append(
entry.first +
" => ");
534 out.append(
entry.second.toString());
543 std::string out =
"";
547 out.append(
value.first);
565 int val = boost::lexical_cast<int>(
value);
569 }
catch (
const boost::bad_lexical_cast& e) {
572 if (pair.first ==
value) {
586 return getContainerHandler(typeName) !=
nullptr;
591 sKeyToContainerTypeMap[
key] = typeName;
596 auto iter = sKeyToContainerTypeMap.find(
key);
597 return iter == sKeyToContainerTypeMap.end() ? std::string{} : iter->second;
602 if (
const auto* handler = getContainerHandler(typeName)) {
611 if (
const auto* handler = getContainerHandler(typeName)) {
612 return handler->equal(lhs, rhs);
619 if (
const auto* handler = getContainerHandler(typeName)) {
620 return handler->serialize(
source);
634 throw std::invalid_argument(fmt::format(
"ConfigurabeParam output file name {} extension is neither .json nor .ini",
filename));
648 if (!keyOnly.empty()) {
650 boost::property_tree::ptree kTree;
652 for (
const auto& k : keys) {
653 kTree.add_child(k, sPtree->get_child(k));
655 boost::property_tree::write_ini(outfilename, kTree);
656 }
catch (
const boost::property_tree::ptree_bad_path& err) {
657 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeINI";
660 boost::property_tree::write_ini(outfilename, *sPtree);
675 if (!sIsFullyInitialized) {
679 auto setValueImpl = [&](std::string
const&
value) {
687 if (sPtree->get_optional<std::string>(
key).is_initialized()) {
697 setValueImpl(valuestring);
702 std::cerr <<
"Error in setValue (string) key is not known\n";
706 if (!expectedSuffix.empty()) {
707 auto valuestringLower = valuestring;
708 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
709 if (valuestringLower.ends_with(expectedSuffix)) {
710 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
711 setValueImpl(strippedValue);
714 for (
const auto& suffix : {
"f",
"l",
"u",
"ul",
"ll",
"ull"}) {
715 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
716 throw std::invalid_argument(
"Wrong type suffix: expected " + expectedSuffix +
" but got " + suffix);
724 }
catch (std::exception
const& e) {
725 std::cerr <<
"Error in setValue (string) " << e.what() <<
"\n";
734 LOG(info) <<
"ignoring writing of json file " <<
filename;
739 if (!keyOnly.empty()) {
741 boost::property_tree::ptree kTree;
743 for (
const auto& k : keys) {
744 kTree.add_child(k, sPtree->get_child(k));
746 boost::property_tree::write_json(outfilename, kTree);
747 }
catch (
const boost::property_tree::ptree_bad_path& err) {
748 LOG(fatal) <<
"non-existing key " << keyOnly <<
" provided to writeJSON";
751 boost::property_tree::write_json(outfilename, *sPtree);
760 for (
auto p : *sRegisteredParamClasses) {
761 p->putKeyValues(sPtree);
769 if (!sIsFullyInitialized) {
772 std::cout <<
"####\n";
773 for (
auto p : *sRegisteredParamClasses) {
774 p->printKeyValues(
true, useLogger);
776 std::cout <<
"----\n";
783 if (!sIsFullyInitialized) {
788 throw std::runtime_error(fmt::format(
"provenace of unknown {:s} parameter is requested",
key));
799 if (!sIsFullyInitialized) {
802 TFile file(
filename.c_str(),
"RECREATE");
803 for (
auto p : *sRegisteredParamClasses) {
804 p->serializeTo(&file);
813 if (!sIsFullyInitialized) {
816 TFile file(
filename.c_str(),
"READ");
817 for (
auto p : *sRegisteredParamClasses) {
827 if (sRegisteredParamClasses ==
nullptr) {
828 sRegisteredParamClasses =
new std::vector<ConfigurableParam*>;
830 if (sPtree ==
nullptr) {
831 sPtree =
new boost::property_tree::ptree;
834 sKeyToStorageMap =
new std::map<std::string, std::pair<std::type_info const&, void*>>;
844 if (sRegisterMode ==
true) {
845 sRegisteredParamClasses->push_back(
this);
859 sIsFullyInitialized =
true;
866 for (
auto p : *sRegisteredParamClasses) {
867 std::cout << p->getName() <<
"\n";
881 if (!sIsFullyInitialized) {
887 if (cfgfile.length() == 0) {
893 std::vector<std::pair<std::string, std::string>> keyValPairs;
895 std::unordered_map<std::string, int> requestMap;
896 for (
const auto& par : request) {
903 for (
auto& section : pt) {
904 std::string mainKey = section.first;
905 if (requestMap.size()) {
906 if (requestMap.find(mainKey) == requestMap.end()) {
909 requestMap[mainKey] = 1;
912 for (
auto& subKey : section.second) {
913 auto name = subKey.first;
914 auto value = subKey.second.get_value<std::string>();
915 std::string
key = mainKey +
"." +
name;
918 keyValPairs.push_back(pair);
922 }
catch (std::exception
const& error) {
923 LOG(error) <<
"Error while updating params " << error.what();
925 LOG(error) <<
"Unknown while updating params ";
929 for (
const auto& req : requestMap) {
930 if (req.second == 0) {
931 throw std::runtime_error(fmt::format(
"Param {:s} was not found in {:s}", req.first, configFile));
937 }
catch (std::exception
const& error) {
938 LOG(error) <<
"Error while setting values " << error.what();
947 if (!sIsFullyInitialized) {
952 if (cfgStr.length() == 0) {
958 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
959 std::vector<std::pair<std::string, std::string>> pairs;
961 for (
auto& token : tokens) {
962 auto s = token.find(
'=');
963 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
964 LOG(fatal) <<
"Illegal command-line key/value string: " << token;
967 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
996 auto keyValues = toKeyValPairs(
params);
1005 if (kv.output_dir ==
"/dev/null") {
1017 auto isArray = [](std::string& el) {
1018 return el.size() > 0 && (el.at(0) ==
'[') && (el.at(el.size() - 1) ==
']');
1021 bool nonFatal = getenv(
"ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") !=
nullptr;
1030 for (
auto& keyValue : keyValues) {
1031 std::string
key = keyValue.first;
1036 LOG(warn) << formatUnknownConfigurableParamKeyMessage(
"Ignoring non-existent ConfigurableParam key: ",
key, *
sKeyToStorageMap);
1039 LOG(fatal) << formatUnknownConfigurableParamKeyMessage(
"Inexistent ConfigurableParam key: ",
key, *
sKeyToStorageMap);
1058 if (
value ==
"true") {
1060 }
else if (
value ==
"false") {
1080 for (
int i = 0;
i < elems.size(); ++
i) {
1090 LOG(error) <<
"Container parameter " <<
key <<
" not found";
1093 void* targetAddress = iter->second.second;
1095 const auto* handler = typeName.empty() ? getContainerHandler(iter->second.first) : getContainerHandler(typeName);
1097 LOG(error) <<
"Unsupported container configuration: " << (typeName.empty() ? iter->second.first.name() : typeName);
1101 handler->parseAssign(targetAddress,
value);
1102 sPtree->put(
key, handler->serialize(targetAddress));
1106 }
catch (
const std::exception& e) {
1107 LOG(error) <<
"Failed to parse container " <<
key <<
": " << e.what();
1113 int val = (*sEnumRegistry)[
key]->getIntValue(
value);
1115 LOG(fatal) <<
"Illegal value "
1117 <<
". Legal string|int values:\n"
1118 << (*sEnumRegistry)[
key]->toString() << std::endl;
1124void unsupp() { std::cerr <<
"currently unsupported\n"; }
1126template <
typename T>
1130 for (
int i = 0;
i <
sizeof(T) /
sizeof(
char); ++
i) {
1131 if (((
char*)block1)[
i] != ((
char*)block2)[
i]) {
1140template <
typename T>
1143 if (isMemblockDifferent<T>(addr, targetaddr)) {
1144 std::memcpy(targetaddr, addr,
sizeof(T));
1154 auto key = mainkey +
"." + subkey;
1157 LOG(warn) <<
"Cannot update parameter " <<
key <<
" not found";
1162 int type = TDataType::GetType(tinfo);
1165 if (iter->second.first != tinfo) {
1166 LOG(warn) <<
"Types do not match; cannot update value";
1170 auto targetaddress = iter->second.second;
1173 return Copy<char>(addr, targetaddress);
1177 return Copy<unsigned char>(addr, targetaddress);
1181 return Copy<short>(addr, targetaddress);
1185 return Copy<unsigned short>(addr, targetaddress);
1189 return Copy<int>(addr, targetaddress);
1193 return Copy<unsigned int>(addr, targetaddress);
1197 return Copy<long>(addr, targetaddress);
1201 return Copy<unsigned long>(addr, targetaddress);
1205 return Copy<float>(addr, targetaddress);
1209 return Copy<double>(addr, targetaddress);
1213 return Copy<double>(addr, targetaddress);
1221 return Copy<bool>(addr, targetaddress);
1225 return Copy<long long>(addr, targetaddress);
1229 return Copy<unsigned long long>(addr, targetaddress);
1249 return Copy<char*>(addr, targetaddress);
1260 case kDataTypeAliasUnsigned_t: {
1281template <
typename T>
1284 auto addr = boost::lexical_cast<T>(valuestring);
1285 if (isMemblockDifferent<T>(targetaddr, (
void*)&addr)) {
1286 std::memcpy(targetaddr, (
void*)&addr,
sizeof(T));
1296 std::string&
target = *((std::string*)targetaddr);
1297 if (
target.compare(valuestring) != 0) {
1310 int intvalue = boost::lexical_cast<int>(valuestring);
1311 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
1312 LOG(error) <<
"Cannot assign " << valuestring <<
" to a char variable";
1315 char addr = intvalue;
1316 if (isMemblockDifferent<char>(targetaddr, (
void*)&addr)) {
1317 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
char));
1326 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
1327 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
1328 LOG(error) <<
"Cannot assign " << valuestring <<
" to an unsigned char variable";
1331 unsigned char addr = intvalue;
1332 if (isMemblockDifferent<unsigned char>(targetaddr, (
void*)&addr)) {
1333 std::memcpy(targetaddr, (
void*)&addr,
sizeof(
unsigned char));
1344 LOG(warn) <<
"Cannot update parameter " <<
key <<
" (parameter not found) ";
1348 auto targetaddress = iter->second.second;
1352 if (iter->second.first ==
typeid(std::string)) {
1357 int targettype = TDataType::GetType(iter->second.first);
1359 switch (targettype) {
1369 return ConvertAndCopy<short>(valuestring, targetaddress);
1373 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
1377 return ConvertAndCopy<int>(valuestring, targetaddress);
1381 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
1385 return ConvertAndCopy<long>(valuestring, targetaddress);
1389 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
1393 return ConvertAndCopy<float>(valuestring, targetaddress);
1397 return ConvertAndCopy<double>(valuestring, targetaddress);
1401 return ConvertAndCopy<double>(valuestring, targetaddress);
1409 return ConvertAndCopy<bool>(valuestring, targetaddress);
1413 return ConvertAndCopy<long long>(valuestring, targetaddress);
1417 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
1449 case kDataTypeAliasUnsigned_t: {