Project
Loading...
Searching...
No Matches
ConfigurableParam.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12// first version 8/2018, Sandro Wenzel
13
15#include <cstddef>
20#define BOOST_BIND_GLOBAL_PLACEHOLDERS
21#include <boost/algorithm/string/predicate.hpp>
22#include <boost/property_tree/ptree.hpp>
23#include <boost/property_tree/ini_parser.hpp>
24#include <boost/property_tree/json_parser.hpp>
25#include <boost/tokenizer.hpp>
26#include <boost/lexical_cast.hpp>
27#include <algorithm>
28#include <array>
29#include <cctype>
30#include <cstdlib>
31#include <functional>
32#include <iomanip>
33#include <limits>
34#include <utility>
35#ifdef NDEBUG
36#undef NDEBUG
37#endif
38#include <cassert>
39#include <iostream>
40#include <sstream>
41#include <string>
42#include <fairlogger/Logger.h>
43#include <typeindex>
44#include <typeinfo>
45#include "TDataMember.h"
46#include "TDataType.h"
47#include "TFile.h"
48#include "TEnum.h"
49#include "TEnumConstant.h"
50#include <filesystem>
51#include <map>
52#include <unordered_map>
53#include <set>
54#include <unordered_set>
55#include <deque>
56#include <vector>
57#include <list>
58
59namespace o2
60{
61namespace conf
62{
63std::vector<ConfigurableParam*>* ConfigurableParam::sRegisteredParamClasses = nullptr;
64boost::property_tree::ptree* ConfigurableParam::sPtree = nullptr;
65std::map<std::string, std::pair<std::type_info const&, void*>>* ConfigurableParam::sKeyToStorageMap = nullptr;
66std::map<std::string, ConfigurableParam::EParamProvenance>* ConfigurableParam::sValueProvenanceMap = nullptr;
67std::string ConfigurableParam::sOutputDir = "";
68EnumRegistry* ConfigurableParam::sEnumRegistry = nullptr;
69
70bool ConfigurableParam::sIsFullyInitialized = false;
71bool ConfigurableParam::sRegisterMode = true;
72
73namespace
74{
75std::map<std::string, std::string> sKeyToContainerTypeMap;
76} // namespace
77
78// ------------------------------------------------------------------
79
80std::ostream& operator<<(std::ostream& out, ConfigurableParam const& param)
81{
82 param.output(out);
83 return out;
84}
85
86// Does the given key exist in the boost property tree?
87bool keyInTree(boost::property_tree::ptree* pt, const std::string& key)
88{
89 if (key.size() == 0 || pt == nullptr) {
90 return false;
91 }
92 bool reply = false;
93 try {
94 reply = pt->get_optional<std::string>(key).is_initialized();
95 } catch (std::exception const& e) {
96 LOG(error) << "ConfigurableParam: Exception when checking for key " << key << " : " << e.what();
97 }
98 return reply;
99}
100
101// Convert a type info to the appropriate literal suffix
102std::string getLiteralSuffixFromType(const std::type_info& type)
103{
104 if (type == typeid(float)) {
105 return "f";
106 }
107 if (type == typeid(long double)) {
108 return "l";
109 }
110 if (type == typeid(unsigned int)) {
111 return "u";
112 }
113 if (type == typeid(unsigned long)) {
114 return "ul";
115 }
116 if (type == typeid(long long)) {
117 return "ll";
119 if (type == typeid(unsigned long long)) {
120 return "ull";
121 }
122 return "";
123}
124
125namespace
126{
127
128struct ContainerHandler {
129 std::function<void(void*, const std::string&)> parseAssign;
130 std::function<std::string(const void*)> serialize;
131 std::function<void(void*, const void*)> assign;
132 std::function<bool(const void*, const void*)> equal;
133};
134
135struct ContainerHandlerRegistry {
136 std::map<std::string, ContainerHandler> byName;
137 std::map<std::type_index, ContainerHandler> byType;
138};
139
140template <typename>
141struct IsUnorderedSet : std::false_type {
142};
143
144template <typename T, typename Hash, typename KeyEqual, typename Allocator>
145struct IsUnorderedSet<std::unordered_set<T, Hash, KeyEqual, Allocator>> : std::true_type {
146};
147
148template <typename>
149struct IsUnorderedMap : std::false_type {
150};
151
152template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
153struct IsUnorderedMap<std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {
154};
155
156std::string normalizeContainerTypeName(std::string typeName)
157{
158 typeName = ContainerParser::trim(typeName);
159 for (size_t pos = typeName.find("std::"); pos != std::string::npos; pos = typeName.find("std::", pos)) {
160 typeName.erase(pos, 5);
161 }
162
163 std::string out;
164 bool pendingSpace = false;
165 for (char c : typeName) {
166 if (std::isspace(static_cast<unsigned char>(c))) {
167 if (!out.empty() && out.back() != '<' && out.back() != ',') {
168 pendingSpace = true;
169 }
170 continue;
171 }
172 if ((c == ',' || c == '>') && !out.empty() && out.back() == ' ') {
173 out.pop_back();
174 }
175 if (pendingSpace && c != ',' && c != '>' && !out.empty() && out.back() != '<' && out.back() != ',') {
176 out += ' ';
177 }
178 out += c;
179 pendingSpace = false;
180 }
181 return out;
182}
183
184template <typename T>
185struct TypeName;
186
187#define REGISTER_SCALAR_NAME(TYPE, NAME) \
188 template <> \
189 struct TypeName<TYPE> { \
190 static constexpr const char* value = NAME; \
191 }
192
193REGISTER_SCALAR_NAME(bool, "bool");
194REGISTER_SCALAR_NAME(char, "char");
195REGISTER_SCALAR_NAME(signed char, "signed char");
196REGISTER_SCALAR_NAME(unsigned char, "unsigned char");
197REGISTER_SCALAR_NAME(short, "short");
198REGISTER_SCALAR_NAME(unsigned short, "unsigned short");
199REGISTER_SCALAR_NAME(int, "int");
200REGISTER_SCALAR_NAME(unsigned int, "unsigned int");
201REGISTER_SCALAR_NAME(long, "long");
202REGISTER_SCALAR_NAME(unsigned long, "unsigned long");
203REGISTER_SCALAR_NAME(long long, "long long");
204REGISTER_SCALAR_NAME(unsigned long long, "unsigned long long");
205REGISTER_SCALAR_NAME(float, "float");
206REGISTER_SCALAR_NAME(double, "double");
207REGISTER_SCALAR_NAME(std::string, "string");
208
209#undef REGISTER_SCALAR_NAME
210
211template <typename T>
212std::string scalarAsString(const T& value)
213{
214 if constexpr (std::is_same_v<T, bool>) {
215 return value ? "1" : "0";
216 } else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>) {
217 return std::to_string(static_cast<int>(value));
218 } else if constexpr (std::is_same_v<T, unsigned char>) {
219 return std::to_string(static_cast<unsigned int>(value));
220 } else if constexpr (std::is_same_v<T, std::string>) {
221 return value;
222 } else if constexpr (std::is_floating_point_v<T>) {
223 std::ostringstream out;
224 out << std::setprecision(std::numeric_limits<T>::max_digits10) << value;
225 return out.str();
226 } else {
227 return std::to_string(value);
228 }
229}
230
231template <typename ContainerT>
232std::string sequenceAsString(const ContainerT& container)
233{
234 using ValueType = typename ContainerT::value_type;
235 std::ostringstream out;
236 out << '[';
237 bool first = true;
238 std::vector<std::string> unorderedValues;
239 if constexpr (IsUnorderedSet<ContainerT>::value) {
240 for (const auto& value : container) {
241 unorderedValues.push_back(scalarAsString(static_cast<ValueType>(value)));
242 }
243 std::sort(unorderedValues.begin(), unorderedValues.end());
244 }
245 const auto emitValue = [&out, &first](const std::string& value) {
246 if (!first) {
247 out << ',';
248 }
249 out << value;
250 first = false;
251 };
252 if constexpr (IsUnorderedSet<ContainerT>::value) {
253 for (const auto& value : unorderedValues) {
254 emitValue(value);
255 }
256 } else {
257 for (const auto& value : container) {
258 emitValue(scalarAsString(static_cast<ValueType>(value)));
259 }
260 }
261 out << ']';
262 return out.str();
263}
264
265template <typename MapT>
266std::string mapAsString(const MapT& container)
267{
268 std::ostringstream out;
269 out << '{';
270 bool first = true;
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));
275 }
276 std::sort(unorderedValues.begin(), unorderedValues.end());
277 }
278 const auto emitValue = [&out, &first](const std::string& key, const std::string& value) {
279 if (!first) {
280 out << ',';
281 }
282 out << key << ':' << value;
283 first = false;
284 };
285 if constexpr (IsUnorderedMap<MapT>::value) {
286 for (const auto& [key, value] : unorderedValues) {
287 emitValue(key, value);
288 }
289 } else {
290 for (const auto& [key, value] : container) {
291 emitValue(scalarAsString(key), scalarAsString(value));
292 }
293 }
294 out << '}';
295 return out.str();
296}
297
298template <typename ContainerT>
299ContainerHandler makeSequenceHandler()
300{
301 return {
302 [](void* target, const std::string& value) {
303 *static_cast<ContainerT*>(target) = ContainerParser::parse<ContainerT>(value);
304 },
305 [](const void* source) {
306 return sequenceAsString(*static_cast<const ContainerT*>(source));
307 },
308 [](void* target, const void* source) {
309 *static_cast<ContainerT*>(target) = *static_cast<const ContainerT*>(source);
310 },
311 [](const void* lhs, const void* rhs) {
312 return *static_cast<const ContainerT*>(lhs) == *static_cast<const ContainerT*>(rhs);
313 }};
314}
315
316template <typename MapT>
317ContainerHandler makeMapHandler()
318{
319 return {
320 [](void* target, const std::string& value) {
321 *static_cast<MapT*>(target) = ContainerParser::parse<MapT>(value);
322 },
323 [](const void* source) {
324 return mapAsString(*static_cast<const MapT*>(source));
325 },
326 [](void* target, const void* source) {
327 *static_cast<MapT*>(target) = *static_cast<const MapT*>(source);
328 },
329 [](const void* lhs, const void* rhs) {
330 return *static_cast<const MapT*>(lhs) == *static_cast<const MapT*>(rhs);
331 }};
332}
333
334template <typename ContainerT>
335void addHandler(ContainerHandlerRegistry& registry, const std::string& name, ContainerHandler handler)
336{
337 registry.byName.emplace(normalizeContainerTypeName(name), handler);
338 registry.byType.emplace(std::type_index(typeid(ContainerT)), std::move(handler));
339}
340
341template <typename T>
342void addSequenceHandlers(ContainerHandlerRegistry& registry)
343{
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>>());
350}
351
352template <typename K, typename V>
353void addMapHandlers(ContainerHandlerRegistry& registry)
354{
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>>());
359}
360
361template <typename K>
362void addMapHandlersForKey(ContainerHandlerRegistry& registry)
363{
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);
379}
380
381const ContainerHandlerRegistry& containerHandlers()
382{
383 static const ContainerHandlerRegistry handlers = [] {
384 ContainerHandlerRegistry result;
385
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);
401
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);
417
418 return result;
419 }();
420 return handlers;
421}
422
423const ContainerHandler* getContainerHandler(const std::string& typeName)
424{
425 const auto normalized = normalizeContainerTypeName(typeName);
426 const auto& handlers = containerHandlers().byName;
427 auto iter = handlers.find(normalized);
428 return iter == handlers.end() ? nullptr : &iter->second;
429}
430
431const ContainerHandler* getContainerHandler(const std::type_info& type)
432{
433 const auto& handlers = containerHandlers().byType;
434 auto iter = handlers.find(std::type_index(type));
435 return iter == handlers.end() ? nullptr : &iter->second;
436}
437
438std::pair<std::string_view, std::string_view> splitConfigurableParamKey(std::string_view key)
439{
440 const auto separator = key.find('.');
441 if (separator == std::string_view::npos) {
442 return {key, {}};
443 }
444 return {key.substr(0, separator), key.substr(separator + 1)};
445}
446
447std::string findClosestConfigurableParamKey(const std::string& requestedKey,
448 const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap)
449{
450 if (storageMap.empty()) {
451 return {};
452 }
453
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;
460 break;
461 }
462 }
463
464 std::string closest;
465 std::size_t closestDistance = std::numeric_limits<std::size_t>::max();
466 for (const auto& entry : storageMap) {
467 const auto& key = entry.first;
468 const auto [mainKey, subKey] = splitConfigurableParamKey(key);
469 if (mainKeyExists && mainKey != requestedMainKey) {
470 continue;
471 }
472 const auto distance = mainKeyExists ? damerauLevenshteinDistance(requestedSubKey, subKey) : damerauLevenshteinDistance(requestedKey, key);
473 if (distance < closestDistance || (distance == closestDistance && (closest.empty() || key < closest))) {
474 closest = key;
475 closestDistance = distance;
476 }
477 }
478 return closest;
479}
480
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)
483{
484 std::string message = prefix + key;
485 auto closest = findClosestConfigurableParamKey(key, storageMap);
486 if (!closest.empty()) {
487 message += ". Did you mean '" + closest + "'?";
488 }
489 return message;
490}
491
492} // namespace
493
494// ------------------------------------------------------------------
495
496void EnumRegistry::add(const std::string& key, const TDataMember* dm)
497{
498 if (!dm->IsEnum() || this->contains(key)) {
499 return;
500 }
501
502 EnumLegalValues legalVals;
503 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
504 assert(enumtype != nullptr);
505 auto constantlist = enumtype->GetConstants();
506 assert(constantlist != nullptr);
507 if (enumtype) {
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());
511 legalVals.vvalues.push_back(val);
512 }
513 }
514
515 // The other method of fetching enum constants from TDataMember->GetOptions
516 // stopped working with ROOT6-18-0:
517
518 // auto opts = dm->GetOptions();
519 // for (int i = 0; i < opts->GetEntries(); ++i) {
520 // auto opt = (TOptionListItem*)opts->At(i);
521 // std::pair<std::string, int> val(opt->fOptName, (int)opt->fValue);
522 // legalVals.vvalues.push_back(val);
523 // LOG(info) << "Adding legal value " << val.first << " " << val.second;
524 // }
525
526 auto entry = std::pair<std::string, EnumLegalValues>(key, legalVals);
527 this->entries.insert(entry);
528}
529
530std::string EnumRegistry::toString() const
531{
532 std::string out = "";
533 for (auto& entry : entries) {
534 out.append(entry.first + " => ");
535 out.append(entry.second.toString());
536 out.append("\n");
537 }
538
539 return out;
540}
541
542std::string EnumLegalValues::toString() const
543{
544 std::string out = "";
545
546 for (auto& value : vvalues) {
547 out.append("[");
548 out.append(value.first);
549 out.append(" | ");
550 out.append(std::to_string(value.second));
551 out.append("] ");
552 }
553
554 return out;
555}
556
557// getIntValue takes a string value which is supposed to be
558// a legal enum value and tries to cast it to an int.
559// If it succeeds, and if the int value is legal, it is returned.
560// If it fails, and if it is a legal string enum value, we look up
561// and return the equivalent int value. In any case, if it is not
562// a legal value we return -1 to indicate this fact.
563int EnumLegalValues::getIntValue(const std::string& value) const
564{
565 try {
566 int val = boost::lexical_cast<int>(value);
567 if (isLegal(val)) {
568 return val;
569 }
570 } catch (const boost::bad_lexical_cast& e) {
571 if (isLegal(value)) {
572 for (auto& pair : vvalues) {
573 if (pair.first == value) {
574 return pair.second;
575 }
576 }
577 }
578 }
579
580 return -1;
581}
582
583// -----------------------------------------------------------------
584
585bool ConfigurableParam::isRegisteredContainerType(const std::string& typeName)
586{
587 return getContainerHandler(typeName) != nullptr;
588}
589
590void ConfigurableParam::registerContainerType(const std::string& key, const std::string& typeName)
591{
592 sKeyToContainerTypeMap[key] = typeName;
593}
594
596{
597 auto iter = sKeyToContainerTypeMap.find(key);
598 return iter == sKeyToContainerTypeMap.end() ? std::string{} : iter->second;
599}
600
601bool ConfigurableParam::assignRegisteredContainer(const std::string& typeName, void* target, const void* source)
602{
603 if (const auto* handler = getContainerHandler(typeName)) {
604 handler->assign(target, source);
605 return true;
606 }
607 return false;
608}
609
610bool ConfigurableParam::areRegisteredContainersEqual(const std::string& typeName, const void* lhs, const void* rhs)
611{
612 if (const auto* handler = getContainerHandler(typeName)) {
613 return handler->equal(lhs, rhs);
614 }
615 return false;
616}
617
618std::string ConfigurableParam::registeredContainerAsString(const std::string& typeName, const void* source)
619{
620 if (const auto* handler = getContainerHandler(typeName)) {
621 return handler->serialize(source);
622 }
623 return {};
624}
625
626// -----------------------------------------------------------------
627
628void ConfigurableParam::write(std::string const& filename, std::string const& keyOnly)
629{
630 if (o2::utils::Str::endsWith(filename, ".ini")) {
631 writeINI(filename, keyOnly);
632 } else if (o2::utils::Str::endsWith(filename, ".json")) {
633 writeJSON(filename, keyOnly);
634 } else {
635 throw std::invalid_argument(fmt::format("ConfigurabeParam output file name {} extension is neither .json nor .ini", filename));
636 }
637}
638
639// -----------------------------------------------------------------
640
641void ConfigurableParam::writeINI(std::string const& filename, std::string const& keyOnly)
642{
643 if (sOutputDir == "/dev/null") {
644 LOG(debug) << "ignoring writing of ini file " << filename;
645 return;
646 }
648 initPropertyTree(); // update the boost tree before writing
649 if (!keyOnly.empty()) { // write ini for selected key only
650 try {
651 boost::property_tree::ptree kTree;
652 auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true);
653 for (const auto& k : keys) {
654 kTree.add_child(k, sPtree->get_child(k));
655 }
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";
659 }
660 } else {
661 boost::property_tree::write_ini(outfilename, *sPtree);
662 }
663}
664
665// ------------------------------------------------------------------
666
667bool ConfigurableParam::configFileExists(std::string const& filepath)
668{
669 return std::filesystem::exists(o2::utils::Str::concat_string(ConfigurableParamReaders::getInputDir(), filepath));
670}
671
672// ------------------------------------------------------------------
673
674void ConfigurableParam::setValue(std::string const& key, std::string const& valuestring)
675{
676 if (!sIsFullyInitialized) {
677 initialize();
678 }
679 assert(sPtree);
680 auto setValueImpl = [&](std::string const& value) {
681 sPtree->put(key, value);
683 if (changed != EParamUpdateStatus::Failed) {
684 sValueProvenanceMap->find(key)->second = kRT; // set to runtime
685 }
686 };
687 try {
688 if (sPtree->get_optional<std::string>(key).is_initialized()) {
689 auto iter = sKeyToStorageMap->find(key);
690 if (iter != sKeyToStorageMap->end()) {
691 if (!getRegisteredContainerType(key).empty() || getContainerHandler(iter->second.first)) {
692 setContainerValue(key, valuestring);
693 return;
694 }
695 }
696 try {
697 // try first setting value without stripping a literal suffix
698 setValueImpl(valuestring);
699 } catch (...) {
700 // try second stripping the expected literal suffix value for fundamental types
701 auto iter = sKeyToStorageMap->find(key);
702 if (iter == sKeyToStorageMap->end()) {
703 std::cerr << "Error in setValue (string) key is not known\n";
704 return;
705 }
706 const auto expectedSuffix = getLiteralSuffixFromType(iter->second.first);
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);
713 } else {
714 // check if it has a different suffix and throw
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);
718 }
719 }
720 throw; // just rethrow the original exception
721 }
722 }
723 }
724 }
725 } catch (std::exception const& e) {
726 std::cerr << "Error in setValue (string) " << e.what() << "\n";
727 }
728}
729
730// ------------------------------------------------------------------
731
732void ConfigurableParam::writeJSON(std::string const& filename, std::string const& keyOnly)
733{
734 if (sOutputDir == "/dev/null") {
735 LOG(info) << "ignoring writing of json file " << filename;
736 return;
737 }
738 initPropertyTree(); // update the boost tree before writing
740 if (!keyOnly.empty()) { // write ini for selected key only
741 try {
742 boost::property_tree::ptree kTree;
743 auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true);
744 for (const auto& k : keys) {
745 kTree.add_child(k, sPtree->get_child(k));
746 }
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";
750 }
751 } else {
752 boost::property_tree::write_json(outfilename, *sPtree);
753 }
754}
755
756// ------------------------------------------------------------------
757
758std::string ConfigurableParam::asJSON(std::string const& keyOnly)
759{
760 initPropertyTree(); // update the boost tree before writing
761 std::ostringstream os;
762 if (!keyOnly.empty()) { // write ini for selected key only
763 try {
764 boost::property_tree::ptree kTree;
765 auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true);
766 for (const auto& k : keys) {
767 kTree.add_child(k, sPtree->get_child(k));
768 }
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";
772 }
773 } else {
774 boost::property_tree::write_json(os, *sPtree);
775 }
776 return os.str();
777}
778
779// ------------------------------------------------------------------
780
782{
783 sPtree->clear();
784 for (auto p : *sRegisteredParamClasses) {
785 p->putKeyValues(sPtree);
786 }
787}
788
789// ------------------------------------------------------------------
790
792{
793 if (!sIsFullyInitialized) {
794 initialize();
795 }
796 std::cout << "####\n";
797 for (auto p : *sRegisteredParamClasses) {
798 p->printKeyValues(true, useLogger);
799 }
800 std::cout << "----\n";
801}
802
803// ------------------------------------------------------------------
804
806{
807 if (!sIsFullyInitialized) {
808 initialize();
809 }
810 auto iter = sValueProvenanceMap->find(key);
811 if (iter == sValueProvenanceMap->end()) {
812 throw std::runtime_error(fmt::format("provenace of unknown {:s} parameter is requested", key));
813 }
814 return iter->second;
815}
816
817// ------------------------------------------------------------------
818
819// evidently this could be a local file or an OCDB server
820// ... we need to generalize this ... but ok for demonstration purposes
822{
823 if (!sIsFullyInitialized) {
824 initialize();
825 }
826 TFile file(filename.c_str(), "RECREATE");
827 for (auto p : *sRegisteredParamClasses) {
828 p->serializeTo(&file);
829 }
830 file.Close();
831}
832
833// ------------------------------------------------------------------
834
836{
837 if (!sIsFullyInitialized) {
838 initialize();
839 }
840 TFile file(filename.c_str(), "READ");
841 for (auto p : *sRegisteredParamClasses) {
842 p->initFrom(&file);
843 }
844 file.Close();
845}
846
847// ------------------------------------------------------------------
848
850{
851 if (sRegisteredParamClasses == nullptr) {
852 sRegisteredParamClasses = new std::vector<ConfigurableParam*>;
853 }
854 if (sPtree == nullptr) {
855 sPtree = new boost::property_tree::ptree;
856 }
857 if (sKeyToStorageMap == nullptr) {
858 sKeyToStorageMap = new std::map<std::string, std::pair<std::type_info const&, void*>>;
859 }
860 if (sValueProvenanceMap == nullptr) {
861 sValueProvenanceMap = new std::map<std::string, ConfigurableParam::EParamProvenance>;
862 }
863
864 if (sEnumRegistry == nullptr) {
866 }
867
868 if (sRegisterMode == true) {
869 sRegisteredParamClasses->push_back(this);
870 }
871}
872
873// ------------------------------------------------------------------
874
876{
878 // initialize the provenance map
879 // initially the values come from code
880 for (auto& key : *sKeyToStorageMap) {
881 sValueProvenanceMap->insert(std::pair<std::string, ConfigurableParam::EParamProvenance>(key.first, kCODE));
882 }
883 sIsFullyInitialized = true;
884}
885
886// ------------------------------------------------------------------
887
889{
890 for (auto p : *sRegisteredParamClasses) {
891 std::cout << p->getName() << "\n";
892 }
893}
894
895// ------------------------------------------------------------------
896
897namespace
898{
899void updateFromPropertyTree(boost::property_tree::ptree const& pt, std::string const& source, std::string const& paramsList, bool unchangedOnly)
900{
901 std::vector<std::pair<std::string, std::string>> keyValPairs;
902 auto request = o2::utils::Str::tokenize(paramsList, ',', true);
903 std::unordered_map<std::string, int> requestMap;
904 for (const auto& par : request) {
905 if (!par.empty()) {
906 requestMap[par] = 0;
907 }
908 }
909
910 try {
911 for (auto& section : pt) {
912 std::string mainKey = section.first;
913 if (requestMap.size()) {
914 if (requestMap.find(mainKey) == requestMap.end()) {
915 continue; // if something was requested, ignore everything else
916 } else {
917 requestMap[mainKey] = 1;
918 }
919 }
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;
925 std::pair<std::string, std::string> pair = std::make_pair(key, o2::utils::Str::trim_copy(value));
926 keyValPairs.push_back(pair);
927 }
928 }
929 }
930 } catch (std::exception const& error) {
931 LOG(error) << "Error while updating params " << error.what();
932 } catch (...) {
933 LOG(error) << "Unknown while updating params ";
934 }
935
936 // make sure all requested params were retrieved
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));
940 }
941 }
942
943 try {
944 ConfigurableParam::setValues(keyValPairs);
945 } catch (std::exception const& error) {
946 LOG(error) << "Error while setting values " << error.what();
947 }
948}
949} // namespace
950
951// Update the storage map of params from the given configuration file.
952// It can be in JSON or INI format.
953// If nonempty comma-separated paramsList is provided, only those params will
954// be updated, absence of data for any of requested params will lead to fatal
955// If unchangedOnly is true, then only those parameters whose provenance is kCODE will be updated
956// (to allow preference of run-time settings)
957void ConfigurableParam::updateFromFile(std::string const& configFile, std::string const& paramsList, bool unchangedOnly)
958{
959 if (!sIsFullyInitialized) {
960 initialize();
961 }
962
963 auto cfgfile = o2::utils::Str::trim_copy(configFile);
964
965 if (cfgfile.length() == 0) {
966 return;
967 }
968
969 updateFromPropertyTree(ConfigurableParamReaders::readConfigFile(cfgfile), configFile, paramsList, unchangedOnly);
970}
971
972// ------------------------------------------------------------------
973
974void ConfigurableParam::updateFromJSONString(std::string const& configJSON, std::string const& paramsList, bool unchangedOnly)
975{
976 if (!sIsFullyInitialized) {
977 initialize();
978 }
979
980 auto json = o2::utils::Str::trim_copy(configJSON);
981 if (json.length() == 0) {
982 return;
983 }
984
985 boost::property_tree::ptree pt;
986 std::istringstream input(json);
987 try {
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() << ")";
991 }
992
993 updateFromPropertyTree(pt, "provided JSON string", paramsList, unchangedOnly);
994}
995
996// ------------------------------------------------------------------
997// ------------------------------------------------------------------
998
999void ConfigurableParam::updateFromString(std::string const& configString)
1000{
1001 if (!sIsFullyInitialized) {
1002 initialize();
1003 }
1004
1005 auto cfgStr = o2::utils::Str::trim_copy(configString);
1006 if (cfgStr.length() == 0) {
1007 return;
1008 }
1009
1010 // Take a vector of strings with elements of form a=b, and
1011 // return a vector of pairs with each pair of form <a, b>
1012 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
1013 std::vector<std::pair<std::string, std::string>> pairs;
1014
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;
1019 continue;
1020 }
1021 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
1022 }
1023
1024 return pairs;
1025 };
1026
1027 // Simple check that the string starts/ends with an open square bracket
1028 // Find the maximum index of a given key with array value.
1029 // We store string keys for arrays as a[0]...a[size_of_array]
1030 /*
1031 auto maxIndex = [](std::string baseName) {
1032 bool isFound = true;
1033 int index = -1;
1034 do {
1035 index++;
1036 std::string key = baseName + "[" + std::to_string(index) + "]";
1037 isFound = keyInTree(sPtree, key);
1038 } while (isFound);
1039
1040 return index;
1041 };
1042*/
1043
1044 // ---- end of helper functions --------------------
1045
1046 // Command-line string is a ;-separated list of key=value params
1047 auto params = o2::utils::Str::tokenize(configString, ';', true);
1048
1049 // Now split each key=value string into its std::pair<key, value> parts
1050 auto keyValues = toKeyValPairs(params);
1051
1052 setValues(keyValues);
1053
1054 const auto& kv = o2::conf::KeyValParam::Instance();
1055 if (getProvenance("keyval.input_dir") != kCODE) {
1057 }
1058 if (getProvenance("keyval.output_dir") != kCODE) {
1059 if (kv.output_dir == "/dev/null") {
1060 sOutputDir = kv.output_dir;
1061 } else {
1063 }
1064 }
1065}
1066
1067// setValues takes a vector of pairs where each pair is a key and value
1068// to be set in the storage map
1069void ConfigurableParam::setValues(std::vector<std::pair<std::string, std::string>> const& keyValues)
1070{
1071 auto isArray = [](std::string& el) {
1072 return el.size() > 0 && (el.at(0) == '[') && (el.at(el.size() - 1) == ']');
1073 };
1074
1075 bool nonFatal = getenv("ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") != nullptr;
1076
1077 // Take a vector of param key/value pairs
1078 // and update the storage map for each of them by calling setValue.
1079 // 1. For string/scalar types this is simple.
1080 // 2. For array values we need to iterate over each array element
1081 // and call setValue on the element, using an appropriately constructed key.
1082 // 3. For enum types we check for the existence of the key in the enum registry
1083 // and also confirm that the value is in the list of legal values
1084 for (auto& keyValue : keyValues) {
1085 std::string key = keyValue.first;
1086 std::string value = o2::utils::Str::trim_copy(keyValue.second);
1087
1088 if (!keyInTree(sPtree, key)) {
1089 if (nonFatal) {
1090 LOG(warn) << formatUnknownConfigurableParamKeyMessage("Ignoring non-existent ConfigurableParam key: ", key, *sKeyToStorageMap);
1091 continue;
1092 }
1093 LOG(fatal) << formatUnknownConfigurableParamKeyMessage("Inexistent ConfigurableParam key: ", key, *sKeyToStorageMap);
1094 }
1095
1096 auto iter = sKeyToStorageMap->find(key);
1097 if (iter != sKeyToStorageMap->end()) {
1098 if (!getRegisteredContainerType(key).empty() || getContainerHandler(iter->second.first)) {
1100 continue;
1101 }
1102 }
1103
1104 if (sEnumRegistry->contains(key)) {
1106 } else if (isArray(value)) {
1108 } else {
1109 assert(sKeyToStorageMap->find(key) != sKeyToStorageMap->end());
1110
1111 // If the value is given as a boolean true|false, change to 1|0 int equivalent
1112 if (value == "true") {
1113 value = "1";
1114 } else if (value == "false") {
1115 value = "0";
1116 }
1117
1118 // Non-registered complex types still fall through to scalar conversion and fail there.
1119 setValue(key, value);
1120 }
1121 }
1122}
1123
1124void ConfigurableParam::setArrayValue(const std::string& key, const std::string& value)
1125{
1126 // We remove the lead/trailing square bracket
1127 // value.erase(0, 1).pop_back();
1128 auto elems = o2::utils::Str::tokenize(value.substr(1, value.length() - 2), ',', true);
1129
1130 // TODO:
1131 // 1. Should not assume each array element is a scalar/string. We may need to recurse.
1132 // 2. Should not assume each array element - even if not complex - is correctly written. Validate.
1133 // 3. Validation should include finding same types as in provided defaults.
1134 for (int i = 0; i < elems.size(); ++i) {
1135 std::string indexKey = key + "[" + std::to_string(i) + "]";
1136 setValue(indexKey, elems[i]);
1137 }
1138}
1139
1140void ConfigurableParam::setContainerValue(const std::string& key, const std::string& value)
1141{
1142 auto iter = sKeyToStorageMap->find(key);
1143 if (iter == sKeyToStorageMap->end()) {
1144 LOG(error) << "Container parameter " << key << " not found";
1145 return;
1146 }
1147 void* targetAddress = iter->second.second;
1148 const auto typeName = getRegisteredContainerType(key);
1149 const auto* handler = typeName.empty() ? getContainerHandler(iter->second.first) : getContainerHandler(typeName);
1150 if (!handler) {
1151 LOG(error) << "Unsupported container configuration: " << (typeName.empty() ? iter->second.first.name() : typeName);
1152 return;
1153 }
1154 try {
1155 handler->parseAssign(targetAddress, value);
1156 sPtree->put(key, handler->serialize(targetAddress));
1157 if (auto prov = sValueProvenanceMap->find(key); prov != sValueProvenanceMap->end()) {
1158 prov->second = kRT;
1159 }
1160 } catch (const std::exception& e) {
1161 LOG(error) << "Failed to parse container " << key << ": " << e.what();
1162 }
1163}
1164
1165void ConfigurableParam::setEnumValue(const std::string& key, const std::string& value)
1166{
1167 int val = (*sEnumRegistry)[key]->getIntValue(value);
1168 if (val == -1) {
1169 LOG(fatal) << "Illegal value "
1170 << value << " for enum " << key
1171 << ". Legal string|int values:\n"
1172 << (*sEnumRegistry)[key]->toString() << std::endl;
1173 }
1174
1176}
1177
1178void unsupp() { std::cerr << "currently unsupported\n"; }
1179
1180template <typename T>
1181bool isMemblockDifferent(void const* block1, void const* block2)
1182{
1183 // loop over thing in elements of bytes
1184 for (int i = 0; i < sizeof(T) / sizeof(char); ++i) {
1185 if (((char*)block1)[i] != ((char*)block2)[i]) {
1186 return true;
1187 }
1188 }
1189 return false;
1190}
1191
1192// copies data from one place to other and returns
1193// true of data was actually changed
1194template <typename T>
1195ConfigurableParam::EParamUpdateStatus Copy(void const* addr, void* targetaddr)
1196{
1197 if (isMemblockDifferent<T>(addr, targetaddr)) {
1198 std::memcpy(targetaddr, addr, sizeof(T));
1200 }
1202}
1203
1204ConfigurableParam::EParamUpdateStatus ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string subkey, std::type_info const& tinfo,
1205 void* addr)
1206{
1207 // check if key_exists
1208 auto key = mainkey + "." + subkey;
1209 auto iter = sKeyToStorageMap->find(key);
1210 if (iter == sKeyToStorageMap->end()) {
1211 LOG(warn) << "Cannot update parameter " << key << " not found";
1213 }
1214
1215 // the type we need to convert to
1216 int type = TDataType::GetType(tinfo);
1217
1218 // check that type matches
1219 if (iter->second.first != tinfo) {
1220 LOG(warn) << "Types do not match; cannot update value";
1222 }
1223
1224 auto targetaddress = iter->second.second;
1225 switch (type) {
1226 case kChar_t: {
1227 return Copy<char>(addr, targetaddress);
1228 break;
1229 }
1230 case kUChar_t: {
1231 return Copy<unsigned char>(addr, targetaddress);
1232 break;
1233 }
1234 case kShort_t: {
1235 return Copy<short>(addr, targetaddress);
1236 break;
1237 }
1238 case kUShort_t: {
1239 return Copy<unsigned short>(addr, targetaddress);
1240 break;
1241 }
1242 case kInt_t: {
1243 return Copy<int>(addr, targetaddress);
1244 break;
1245 }
1246 case kUInt_t: {
1247 return Copy<unsigned int>(addr, targetaddress);
1248 break;
1249 }
1250 case kLong_t: {
1251 return Copy<long>(addr, targetaddress);
1252 break;
1253 }
1254 case kULong_t: {
1255 return Copy<unsigned long>(addr, targetaddress);
1256 break;
1257 }
1258 case kFloat_t: {
1259 return Copy<float>(addr, targetaddress);
1260 break;
1261 }
1262 case kDouble_t: {
1263 return Copy<double>(addr, targetaddress);
1264 break;
1265 }
1266 case kDouble32_t: {
1267 return Copy<double>(addr, targetaddress);
1268 break;
1269 }
1270 case kchar: {
1271 unsupp();
1272 break;
1273 }
1274 case kBool_t: {
1275 return Copy<bool>(addr, targetaddress);
1276 break;
1277 }
1278 case kLong64_t: {
1279 return Copy<long long>(addr, targetaddress);
1280 break;
1281 }
1282 case kULong64_t: {
1283 return Copy<unsigned long long>(addr, targetaddress);
1284 break;
1285 }
1286 case kOther_t: {
1287 unsupp();
1288 break;
1289 }
1290 case kNoType_t: {
1291 unsupp();
1292 break;
1293 }
1294 case kFloat16_t: {
1295 unsupp();
1296 break;
1297 }
1298 case kCounter: {
1299 unsupp();
1300 break;
1301 }
1302 case kCharStar: {
1303 return Copy<char*>(addr, targetaddress);
1304 break;
1305 }
1306 case kBits: {
1307 unsupp();
1308 break;
1309 }
1310 case kVoid_t: {
1311 unsupp();
1312 break;
1313 }
1314 case kDataTypeAliasUnsigned_t: {
1315 unsupp();
1316 break;
1317 }
1318 /*
1319 case kDataTypeAliasSignedChar_t: {
1320 unsupp();
1321 break;
1322 }
1323 case kNumDataTypes: {
1324 unsupp();
1325 break;
1326 }*/
1327 default: {
1328 unsupp();
1329 break;
1330 }
1331 }
1333}
1334
1335template <typename T>
1336ConfigurableParam::EParamUpdateStatus ConvertAndCopy(std::string const& valuestring, void* targetaddr)
1337{
1338 auto addr = boost::lexical_cast<T>(valuestring);
1339 if (isMemblockDifferent<T>(targetaddr, (void*)&addr)) {
1340 std::memcpy(targetaddr, (void*)&addr, sizeof(T));
1342 }
1344}
1345
1346// special version for std::string
1347template <>
1348ConfigurableParam::EParamUpdateStatus ConvertAndCopy<std::string>(std::string const& valuestring, void* targetaddr)
1349{
1350 std::string& target = *((std::string*)targetaddr);
1351 if (target.compare(valuestring) != 0) {
1352 // the targetaddr is a std::string to which we can simply assign
1353 // and all the magic will happen internally
1354 target = valuestring;
1356 }
1358}
1359// special version for char and unsigned char since we are interested in the numeric
1360// meaning of char as an 8-bit integer (boost lexical cast is assigning the string as a character i// nterpretation
1361template <>
1362ConfigurableParam::EParamUpdateStatus ConvertAndCopy<char>(std::string const& valuestring, void* targetaddr)
1363{
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";
1368 }
1369 char addr = intvalue;
1370 if (isMemblockDifferent<char>(targetaddr, (void*)&addr)) {
1371 std::memcpy(targetaddr, (void*)&addr, sizeof(char));
1373 }
1375}
1376
1377template <>
1378ConfigurableParam::EParamUpdateStatus ConvertAndCopy<unsigned char>(std::string const& valuestring, void* targetaddr)
1379{
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";
1384 }
1385 unsigned char addr = intvalue;
1386 if (isMemblockDifferent<unsigned char>(targetaddr, (void*)&addr)) {
1387 std::memcpy(targetaddr, (void*)&addr, sizeof(unsigned char));
1389 }
1391}
1392
1394{
1395 // check if key_exists
1396 auto iter = sKeyToStorageMap->find(key);
1397 if (iter == sKeyToStorageMap->end()) {
1398 LOG(warn) << "Cannot update parameter " << key << " (parameter not found) ";
1400 }
1401
1402 auto targetaddress = iter->second.second;
1403
1404 // treat some special cases first:
1405 // the type is actually a std::string
1406 if (iter->second.first == typeid(std::string)) {
1407 return ConvertAndCopy<std::string>(valuestring, targetaddress);
1408 }
1409
1410 // the type (aka ROOT::EDataType which the type identification in the map) we need to convert to
1411 int targettype = TDataType::GetType(iter->second.first);
1412
1413 switch (targettype) {
1414 case kChar_t: {
1415 return ConvertAndCopy<char>(valuestring, targetaddress);
1416 break;
1417 }
1418 case kUChar_t: {
1419 return ConvertAndCopy<unsigned char>(valuestring, targetaddress);
1420 break;
1421 }
1422 case kShort_t: {
1423 return ConvertAndCopy<short>(valuestring, targetaddress);
1424 break;
1425 }
1426 case kUShort_t: {
1427 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
1428 break;
1429 }
1430 case kInt_t: {
1431 return ConvertAndCopy<int>(valuestring, targetaddress);
1432 break;
1433 }
1434 case kUInt_t: {
1435 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
1436 break;
1437 }
1438 case kLong_t: {
1439 return ConvertAndCopy<long>(valuestring, targetaddress);
1440 break;
1441 }
1442 case kULong_t: {
1443 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
1444 break;
1445 }
1446 case kFloat_t: {
1447 return ConvertAndCopy<float>(valuestring, targetaddress);
1448 break;
1449 }
1450 case kDouble_t: {
1451 return ConvertAndCopy<double>(valuestring, targetaddress);
1452 break;
1453 }
1454 case kDouble32_t: {
1455 return ConvertAndCopy<double>(valuestring, targetaddress);
1456 break;
1457 }
1458 case kchar: {
1459 unsupp();
1460 break;
1461 }
1462 case kBool_t: {
1463 return ConvertAndCopy<bool>(valuestring, targetaddress);
1464 break;
1465 }
1466 case kLong64_t: {
1467 return ConvertAndCopy<long long>(valuestring, targetaddress);
1468 break;
1469 }
1470 case kULong64_t: {
1471 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
1472 break;
1473 }
1474 case kOther_t: {
1475 unsupp();
1476 break;
1477 }
1478 case kNoType_t: {
1479 unsupp();
1480 break;
1481 }
1482 case kFloat16_t: {
1483 unsupp();
1484 break;
1485 }
1486 case kCounter: {
1487 unsupp();
1488 break;
1489 }
1490 case kCharStar: {
1491 unsupp();
1492 // return ConvertAndCopy<char*>(valuestring, targetaddress);
1493 break;
1494 }
1495 case kBits: {
1496 unsupp();
1497 break;
1498 }
1499 case kVoid_t: {
1500 unsupp();
1501 break;
1502 }
1503 case kDataTypeAliasUnsigned_t: {
1504 unsupp();
1505 break;
1506 }
1507 /*
1508 case kDataTypeAliasSignedChar_t: {
1509 unsupp();
1510 break;
1511 }
1512 case kNumDataTypes: {
1513 unsupp();
1514 break;
1515 }*/
1516 default: {
1517 unsupp();
1518 break;
1519 }
1520 }
1522}
1523
1524} // namespace conf
1525} // namespace o2
std::function< void(void *, const std::string &)> parseAssign
std::function< bool(const void *, const void *)> equal
std::function< std::string(const void *)> serialize
#define REGISTER_SCALAR_NAME(TYPE, NAME)
std::function< void(void *, const void *)> assign
std::map< std::type_index, ContainerHandler > byType
std::map< std::string, ContainerHandler > byName
std::ostringstream debug
int32_t i
uint16_t pos
Definition RawData.h:3
uint32_t c
Definition RawData.h:2
nlohmann::json json
StringRef key
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 std::string registeredContainerAsString(const std::string &typeName, const void *source)
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 bool areRegisteredContainersEqual(const std::string &typeName, const void *lhs, const void *rhs)
static void registerContainerType(const std::string &key, const std::string &typeName)
static std::string asJSON(std::string const &keyOnly="")
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static void write(std::string const &filename, std::string const &keyOnly="")
static bool isRegisteredContainerType(const std::string &typeName)
static bool assignRegisteredContainer(const std::string &typeName, void *target, const void *source)
static void setArrayValue(const std::string &, const std::string &)
static void setValue(std::string const &mainkey, std::string const &subkey, T x)
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 void setContainerValue(const std::string &, const std::string &)
static void updateFromJSONString(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static EnumRegistry * sEnumRegistry
static std::string getRegisteredContainerType(const std::string &key)
static void fromCCDB(std::string filename)
static void updateFromString(std::string const &)
static std::string trim(const std::string &str)
void add(const std::string &key, const TDataMember *dm)
std::string toString() const
bool contains(const std::string &key) const
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint entry
Definition glcorearb.h:5735
GLuint const GLchar * name
Definition glcorearb.h:781
GLint first
Definition glcorearb.h:399
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLenum const GLfloat * params
Definition glcorearb.h:272
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint GLenum GLboolean normalized
Definition glcorearb.h:867
GLuint GLfloat * val
Definition glcorearb.h:1582
GLuint GLsizei const GLchar * message
Definition glcorearb.h:2517
GLenum GLfloat param
Definition glcorearb.h:271
std::string getLiteralSuffixFromType(const std::type_info &type)
std::size_t damerauLevenshteinDistance(std::string_view a, std::string_view b)
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 &param)
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)
constexpr auto isArray()
Definition Variant.h:59
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:193
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)
Definition common.h:52
std::string filename()
void empty(int)
bool isLegal(const std::string &value) const
std::vector< std::pair< std::string, int > > vvalues
int getIntValue(const std::string &value) 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"