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