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
18#define BOOST_BIND_GLOBAL_PLACEHOLDERS
19#include <boost/algorithm/string/predicate.hpp>
20#include <boost/property_tree/ptree.hpp>
21#include <boost/property_tree/ini_parser.hpp>
22#include <boost/property_tree/json_parser.hpp>
23#include <boost/tokenizer.hpp>
24#include <boost/lexical_cast.hpp>
25#include <algorithm>
26#include <array>
27#include <limits>
28#ifdef NDEBUG
29#undef NDEBUG
30#endif
31#include <cassert>
32#include <iostream>
33#include <string>
34#include <fairlogger/Logger.h>
35#include <typeinfo>
36#include "TDataMember.h"
37#include "TDataType.h"
38#include "TFile.h"
39#include "TEnum.h"
40#include "TEnumConstant.h"
41#include <filesystem>
42
43namespace o2
44{
45namespace conf
46{
47std::vector<ConfigurableParam*>* ConfigurableParam::sRegisteredParamClasses = nullptr;
48boost::property_tree::ptree* ConfigurableParam::sPtree = nullptr;
49std::map<std::string, std::pair<std::type_info const&, void*>>* ConfigurableParam::sKeyToStorageMap = nullptr;
50std::map<std::string, ConfigurableParam::EParamProvenance>* ConfigurableParam::sValueProvenanceMap = nullptr;
51std::string ConfigurableParam::sOutputDir = "";
52EnumRegistry* ConfigurableParam::sEnumRegistry = nullptr;
53
54bool ConfigurableParam::sIsFullyInitialized = false;
55bool ConfigurableParam::sRegisterMode = true;
56
57// ------------------------------------------------------------------
58
59std::ostream& operator<<(std::ostream& out, ConfigurableParam const& param)
60{
61 param.output(out);
62 return out;
63}
64
65// Does the given key exist in the boost property tree?
66bool keyInTree(boost::property_tree::ptree* pt, const std::string& key)
67{
68 if (key.size() == 0 || pt == nullptr) {
69 return false;
70 }
71 bool reply = false;
72 try {
73 reply = pt->get_optional<std::string>(key).is_initialized();
74 } catch (std::exception const& e) {
75 LOG(error) << "ConfigurableParam: Exception when checking for key " << key << " : " << e.what();
76 }
77 return reply;
78}
79
80// Convert a type info to the appropiate literal suffix
81std::string getLiteralSuffixFromType(const std::type_info& type)
82{
83 if (type == typeid(float)) {
84 return "f";
85 }
86 if (type == typeid(long double)) {
87 return "l";
88 }
89 if (type == typeid(unsigned int)) {
90 return "u";
91 }
92 if (type == typeid(unsigned long)) {
93 return "ul";
94 }
95 if (type == typeid(long long)) {
96 return "ll";
97 }
98 if (type == typeid(unsigned long long)) {
99 return "ull";
100 }
101 return "";
102}
103
104// ------------------------------------------------------------------
105
106void EnumRegistry::add(const std::string& key, const TDataMember* dm)
107{
108 if (!dm->IsEnum() || this->contains(key)) {
109 return;
110 }
111
112 EnumLegalValues legalVals;
113 auto enumtype = TEnum::GetEnum(dm->GetTypeName());
114 assert(enumtype != nullptr);
115 auto constantlist = enumtype->GetConstants();
116 assert(constantlist != nullptr);
117 if (enumtype) {
118 for (int i = 0; i < constantlist->GetEntries(); ++i) {
119 auto e = (TEnumConstant*)(constantlist->At(i));
120 std::pair<std::string, int> val(e->GetName(), (int)e->GetValue());
121 legalVals.vvalues.push_back(val);
122 }
123 }
124
125 // The other method of fetching enum constants from TDataMember->GetOptions
126 // stopped working with ROOT6-18-0:
127
128 // auto opts = dm->GetOptions();
129 // for (int i = 0; i < opts->GetEntries(); ++i) {
130 // auto opt = (TOptionListItem*)opts->At(i);
131 // std::pair<std::string, int> val(opt->fOptName, (int)opt->fValue);
132 // legalVals.vvalues.push_back(val);
133 // LOG(info) << "Adding legal value " << val.first << " " << val.second;
134 // }
135
136 auto entry = std::pair<std::string, EnumLegalValues>(key, legalVals);
137 this->entries.insert(entry);
138}
139
140std::string EnumRegistry::toString() const
141{
142 std::string out = "";
143 for (auto& entry : entries) {
144 out.append(entry.first + " => ");
145 out.append(entry.second.toString());
146 out.append("\n");
147 }
148
149 return out;
150}
151
152std::string EnumLegalValues::toString() const
153{
154 std::string out = "";
155
156 for (auto& value : vvalues) {
157 out.append("[");
158 out.append(value.first);
159 out.append(" | ");
160 out.append(std::to_string(value.second));
161 out.append("] ");
162 }
163
164 return out;
165}
166
167// getIntValue takes a string value which is supposed to be
168// a legal enum value and tries to cast it to an int.
169// If it succeeds, and if the int value is legal, it is returned.
170// If it fails, and if it is a legal string enum value, we look up
171// and return the equivalent int value. In any case, if it is not
172// a legal value we return -1 to indicate this fact.
173int EnumLegalValues::getIntValue(const std::string& value) const
174{
175 try {
176 int val = boost::lexical_cast<int>(value);
177 if (isLegal(val)) {
178 return val;
179 }
180 } catch (const boost::bad_lexical_cast& e) {
181 if (isLegal(value)) {
182 for (auto& pair : vvalues) {
183 if (pair.first == value) {
184 return pair.second;
185 }
186 }
187 }
188 }
189
190 return -1;
191}
192
193// -----------------------------------------------------------------
194
195void ConfigurableParam::write(std::string const& filename, std::string const& keyOnly)
196{
197 if (o2::utils::Str::endsWith(filename, ".ini")) {
198 writeINI(filename, keyOnly);
199 } else if (o2::utils::Str::endsWith(filename, ".json")) {
200 writeJSON(filename, keyOnly);
201 } else {
202 throw std::invalid_argument(fmt::format("ConfigurabeParam output file name {} extension is neither .json nor .ini", filename));
203 }
204}
205
206// -----------------------------------------------------------------
207
208void ConfigurableParam::writeINI(std::string const& filename, std::string const& keyOnly)
209{
210 if (sOutputDir == "/dev/null") {
211 LOG(debug) << "ignoring writing of ini file " << filename;
212 return;
213 }
215 initPropertyTree(); // update the boost tree before writing
216 if (!keyOnly.empty()) { // write ini for selected key only
217 try {
218 boost::property_tree::ptree kTree;
219 auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true);
220 for (const auto& k : keys) {
221 kTree.add_child(k, sPtree->get_child(k));
222 }
223 boost::property_tree::write_ini(outfilename, kTree);
224 } catch (const boost::property_tree::ptree_bad_path& err) {
225 LOG(fatal) << "non-existing key " << keyOnly << " provided to writeINI";
226 }
227 } else {
228 boost::property_tree::write_ini(outfilename, *sPtree);
229 }
230}
231
232// ------------------------------------------------------------------
233
234bool ConfigurableParam::configFileExists(std::string const& filepath)
235{
236 return std::filesystem::exists(o2::utils::Str::concat_string(ConfigurableParamReaders::getInputDir(), filepath));
237}
238
239// ------------------------------------------------------------------
240
241void ConfigurableParam::setValue(std::string const& key, std::string const& valuestring)
242{
243 if (!sIsFullyInitialized) {
244 initialize();
245 }
246 assert(sPtree);
247 auto setValueImpl = [&](std::string const& value) {
248 sPtree->put(key, value);
250 if (changed != EParamUpdateStatus::Failed) {
251 sValueProvenanceMap->find(key)->second = kRT; // set to runtime
252 }
253 };
254 try {
255 if (sPtree->get_optional<std::string>(key).is_initialized()) {
256 try {
257 // try first setting value without stripping a literal suffix
258 setValueImpl(valuestring);
259 } catch (...) {
260 // try second stripping the expected literal suffix value for fundamental types
261 auto iter = sKeyToStorageMap->find(key);
262 if (iter == sKeyToStorageMap->end()) {
263 std::cerr << "Error in setValue (string) key is not known\n";
264 return;
265 }
266 const auto expectedSuffix = getLiteralSuffixFromType(iter->second.first);
267 if (!expectedSuffix.empty()) {
268 auto valuestringLower = valuestring;
269 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), tolower);
270 if (valuestringLower.ends_with(expectedSuffix)) {
271 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
272 setValueImpl(strippedValue);
273 } else {
274 // check if it has a different suffix and throw
275 for (const auto& suffix : {"f", "l", "u", "ul", "ll", "ull"}) {
276 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
277 throw std::invalid_argument("Wrong type suffix: expected " + expectedSuffix + " but got " + suffix);
278 }
279 }
280 throw; // just rethrow the original exception
281 }
282 }
283 }
284 }
285 } catch (std::exception const& e) {
286 std::cerr << "Error in setValue (string) " << e.what() << "\n";
287 }
288}
289
290// ------------------------------------------------------------------
291
292void ConfigurableParam::writeJSON(std::string const& filename, std::string const& keyOnly)
293{
294 if (sOutputDir == "/dev/null") {
295 LOG(info) << "ignoring writing of json file " << filename;
296 return;
297 }
298 initPropertyTree(); // update the boost tree before writing
300 if (!keyOnly.empty()) { // write ini for selected key only
301 try {
302 boost::property_tree::ptree kTree;
303 auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true);
304 for (const auto& k : keys) {
305 kTree.add_child(k, sPtree->get_child(k));
306 }
307 boost::property_tree::write_json(outfilename, kTree);
308 } catch (const boost::property_tree::ptree_bad_path& err) {
309 LOG(fatal) << "non-existing key " << keyOnly << " provided to writeJSON";
310 }
311 } else {
312 boost::property_tree::write_json(outfilename, *sPtree);
313 }
314}
315
316// ------------------------------------------------------------------
317
319{
320 sPtree->clear();
321 for (auto p : *sRegisteredParamClasses) {
322 p->putKeyValues(sPtree);
323 }
324}
325
326// ------------------------------------------------------------------
327
329{
330 if (!sIsFullyInitialized) {
331 initialize();
332 }
333 std::cout << "####\n";
334 for (auto p : *sRegisteredParamClasses) {
335 p->printKeyValues(true, useLogger);
336 }
337 std::cout << "----\n";
338}
339
340// ------------------------------------------------------------------
341
343{
344 if (!sIsFullyInitialized) {
345 initialize();
346 }
347 auto iter = sValueProvenanceMap->find(key);
348 if (iter == sValueProvenanceMap->end()) {
349 throw std::runtime_error(fmt::format("provenace of unknown {:s} parameter is requested", key));
350 }
351 return iter->second;
352}
353
354// ------------------------------------------------------------------
355
356// evidently this could be a local file or an OCDB server
357// ... we need to generalize this ... but ok for demonstration purposes
359{
360 if (!sIsFullyInitialized) {
361 initialize();
362 }
363 TFile file(filename.c_str(), "RECREATE");
364 for (auto p : *sRegisteredParamClasses) {
365 p->serializeTo(&file);
366 }
367 file.Close();
368}
369
370// ------------------------------------------------------------------
371
373{
374 if (!sIsFullyInitialized) {
375 initialize();
376 }
377 TFile file(filename.c_str(), "READ");
378 for (auto p : *sRegisteredParamClasses) {
379 p->initFrom(&file);
380 }
381 file.Close();
382}
383
384// ------------------------------------------------------------------
385
387{
388 if (sRegisteredParamClasses == nullptr) {
389 sRegisteredParamClasses = new std::vector<ConfigurableParam*>;
390 }
391 if (sPtree == nullptr) {
392 sPtree = new boost::property_tree::ptree;
393 }
394 if (sKeyToStorageMap == nullptr) {
395 sKeyToStorageMap = new std::map<std::string, std::pair<std::type_info const&, void*>>;
396 }
397 if (sValueProvenanceMap == nullptr) {
398 sValueProvenanceMap = new std::map<std::string, ConfigurableParam::EParamProvenance>;
399 }
400
401 if (sEnumRegistry == nullptr) {
403 }
404
405 if (sRegisterMode == true) {
406 sRegisteredParamClasses->push_back(this);
407 }
408}
409
410// ------------------------------------------------------------------
411
413{
415 // initialize the provenance map
416 // initially the values come from code
417 for (auto& key : *sKeyToStorageMap) {
418 sValueProvenanceMap->insert(std::pair<std::string, ConfigurableParam::EParamProvenance>(key.first, kCODE));
419 }
420 sIsFullyInitialized = true;
421}
422
423// ------------------------------------------------------------------
424
426{
427 for (auto p : *sRegisteredParamClasses) {
428 std::cout << p->getName() << "\n";
429 }
430}
431
432// ------------------------------------------------------------------
433
434// Update the storage map of params from the given configuration file.
435// It can be in JSON or INI format.
436// If nonempty comma-separated paramsList is provided, only those params will
437// be updated, absence of data for any of requested params will lead to fatal
438// If unchangedOnly is true, then only those parameters whose provenance is kCODE will be updated
439// (to allow prefernce of run-time settings)
440void ConfigurableParam::updateFromFile(std::string const& configFile, std::string const& paramsList, bool unchangedOnly)
441{
442 if (!sIsFullyInitialized) {
443 initialize();
444 }
445
446 auto cfgfile = o2::utils::Str::trim_copy(configFile);
447
448 if (cfgfile.length() == 0) {
449 return;
450 }
451
452 boost::property_tree::ptree pt = ConfigurableParamReaders::readConfigFile(cfgfile);
453
454 std::vector<std::pair<std::string, std::string>> keyValPairs;
455 auto request = o2::utils::Str::tokenize(paramsList, ',', true);
456 std::unordered_map<std::string, int> requestMap;
457 for (const auto& par : request) {
458 if (!par.empty()) {
459 requestMap[par] = 0;
460 }
461 }
462
463 try {
464 for (auto& section : pt) {
465 std::string mainKey = section.first;
466 if (requestMap.size()) {
467 if (requestMap.find(mainKey) == requestMap.end()) {
468 continue; // if something was requested, ignore everything else
469 } else {
470 requestMap[mainKey] = 1;
471 }
472 }
473 for (auto& subKey : section.second) {
474 auto name = subKey.first;
475 auto value = subKey.second.get_value<std::string>();
476 std::string key = mainKey + "." + name;
477 if (!unchangedOnly || getProvenance(key) == kCODE) {
478 std::pair<std::string, std::string> pair = std::make_pair(key, o2::utils::Str::trim_copy(value));
479 keyValPairs.push_back(pair);
480 }
481 }
482 }
483 } catch (std::exception const& error) {
484 LOG(error) << "Error while updating params " << error.what();
485 } catch (...) {
486 LOG(error) << "Unknown while updating params ";
487 }
488
489 // make sure all requested params were retrieved
490 for (const auto& req : requestMap) {
491 if (req.second == 0) {
492 throw std::runtime_error(fmt::format("Param {:s} was not found in {:s}", req.first, configFile));
493 }
494 }
495
496 try {
497 setValues(keyValPairs);
498 } catch (std::exception const& error) {
499 LOG(error) << "Error while setting values " << error.what();
500 }
501}
502
503// ------------------------------------------------------------------
504// ------------------------------------------------------------------
505
506void ConfigurableParam::updateFromString(std::string const& configString)
507{
508 if (!sIsFullyInitialized) {
509 initialize();
510 }
511
512 auto cfgStr = o2::utils::Str::trim_copy(configString);
513 if (cfgStr.length() == 0) {
514 return;
515 }
516
517 // Take a vector of strings with elements of form a=b, and
518 // return a vector of pairs with each pair of form <a, b>
519 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
520 std::vector<std::pair<std::string, std::string>> pairs;
521
522 for (auto& token : tokens) {
523 auto s = token.find('=');
524 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
525 LOG(fatal) << "Illegal command-line key/value string: " << token;
526 continue;
527 }
528 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
529 }
530
531 return pairs;
532 };
533
534 // Simple check that the string starts/ends with an open square bracket
535 // Find the maximum index of a given key with array value.
536 // We store string keys for arrays as a[0]...a[size_of_array]
537 /*
538 auto maxIndex = [](std::string baseName) {
539 bool isFound = true;
540 int index = -1;
541 do {
542 index++;
543 std::string key = baseName + "[" + std::to_string(index) + "]";
544 isFound = keyInTree(sPtree, key);
545 } while (isFound);
546
547 return index;
548 };
549*/
550
551 // ---- end of helper functions --------------------
552
553 // Command-line string is a ;-separated list of key=value params
554 auto params = o2::utils::Str::tokenize(configString, ';', true);
555
556 // Now split each key=value string into its std::pair<key, value> parts
557 auto keyValues = toKeyValPairs(params);
558
559 setValues(keyValues);
560
561 const auto& kv = o2::conf::KeyValParam::Instance();
562 if (getProvenance("keyval.input_dir") != kCODE) {
564 }
565 if (getProvenance("keyval.output_dir") != kCODE) {
566 if (kv.output_dir == "/dev/null") {
567 sOutputDir = kv.output_dir;
568 } else {
570 }
571 }
572}
573
574// setValues takes a vector of pairs where each pair is a key and value
575// to be set in the storage map
576void ConfigurableParam::setValues(std::vector<std::pair<std::string, std::string>> const& keyValues)
577{
578 auto isArray = [](std::string& el) {
579 return el.size() > 0 && (el.at(0) == '[') && (el.at(el.size() - 1) == ']');
580 };
581
582 bool nonFatal = getenv("ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") != nullptr;
583
584 // Take a vector of param key/value pairs
585 // and update the storage map for each of them by calling setValue.
586 // 1. For string/scalar types this is simple.
587 // 2. For array values we need to iterate over each array element
588 // and call setValue on the element, using an appropriately constructed key.
589 // 3. For enum types we check for the existence of the key in the enum registry
590 // and also confirm that the value is in the list of legal values
591 for (auto& keyValue : keyValues) {
592 std::string key = keyValue.first;
593 std::string value = o2::utils::Str::trim_copy(keyValue.second);
594
595 if (!keyInTree(sPtree, key)) {
596 if (nonFatal) {
597 LOG(warn) << "Ignoring non-existent ConfigurableParam key: " << key;
598 continue;
599 }
600 LOG(fatal) << "Inexistant ConfigurableParam key: " << key;
601 }
602
603 if (sEnumRegistry->contains(key)) {
605 } else if (isArray(value)) {
607 } else {
608 assert(sKeyToStorageMap->find(key) != sKeyToStorageMap->end());
609
610 // If the value is given as a boolean true|false, change to 1|0 int equivalent
611 if (value == "true") {
612 value = "1";
613 } else if (value == "false") {
614 value = "0";
615 }
616
617 // TODO: this will trap complex types like maps and structs.
618 // These need to be broken into their own cases, so that we only
619 // get strings and scalars here.
621 }
622 }
623}
624
625void ConfigurableParam::setArrayValue(const std::string& key, const std::string& value)
626{
627 // We remove the lead/trailing square bracket
628 // value.erase(0, 1).pop_back();
629 auto elems = o2::utils::Str::tokenize(value.substr(1, value.length() - 2), ',', true);
630
631 // TODO:
632 // 1. Should not assume each array element is a scalar/string. We may need to recurse.
633 // 2. Should not assume each array element - even if not complex - is correctly written. Validate.
634 // 3. Validation should include finding same types as in provided defaults.
635 for (int i = 0; i < elems.size(); ++i) {
636 std::string indexKey = key + "[" + std::to_string(i) + "]";
637 setValue(indexKey, elems[i]);
638 }
639}
640
641void ConfigurableParam::setEnumValue(const std::string& key, const std::string& value)
642{
643 int val = (*sEnumRegistry)[key]->getIntValue(value);
644 if (val == -1) {
645 LOG(fatal) << "Illegal value "
646 << value << " for enum " << key
647 << ". Legal string|int values:\n"
648 << (*sEnumRegistry)[key]->toString() << std::endl;
649 }
650
652}
653
654void unsupp() { std::cerr << "currently unsupported\n"; }
655
656template <typename T>
657bool isMemblockDifferent(void const* block1, void const* block2)
658{
659 // loop over thing in elements of bytes
660 for (int i = 0; i < sizeof(T) / sizeof(char); ++i) {
661 if (((char*)block1)[i] != ((char*)block2)[i]) {
662 return true;
663 }
664 }
665 return false;
666}
667
668// copies data from one place to other and returns
669// true of data was actually changed
670template <typename T>
671ConfigurableParam::EParamUpdateStatus Copy(void const* addr, void* targetaddr)
672{
673 if (isMemblockDifferent<T>(addr, targetaddr)) {
674 std::memcpy(targetaddr, addr, sizeof(T));
676 }
678}
679
680ConfigurableParam::EParamUpdateStatus ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string subkey, std::type_info const& tinfo,
681 void* addr)
682{
683 // check if key_exists
684 auto key = mainkey + "." + subkey;
685 auto iter = sKeyToStorageMap->find(key);
686 if (iter == sKeyToStorageMap->end()) {
687 LOG(warn) << "Cannot update parameter " << key << " not found";
689 }
690
691 // the type we need to convert to
692 int type = TDataType::GetType(tinfo);
693
694 // check that type matches
695 if (iter->second.first != tinfo) {
696 LOG(warn) << "Types do not match; cannot update value";
698 }
699
700 auto targetaddress = iter->second.second;
701 switch (type) {
702 case kChar_t: {
703 return Copy<char>(addr, targetaddress);
704 break;
705 }
706 case kUChar_t: {
707 return Copy<unsigned char>(addr, targetaddress);
708 break;
709 }
710 case kShort_t: {
711 return Copy<short>(addr, targetaddress);
712 break;
713 }
714 case kUShort_t: {
715 return Copy<unsigned short>(addr, targetaddress);
716 break;
717 }
718 case kInt_t: {
719 return Copy<int>(addr, targetaddress);
720 break;
721 }
722 case kUInt_t: {
723 return Copy<unsigned int>(addr, targetaddress);
724 break;
725 }
726 case kLong_t: {
727 return Copy<long>(addr, targetaddress);
728 break;
729 }
730 case kULong_t: {
731 return Copy<unsigned long>(addr, targetaddress);
732 break;
733 }
734 case kFloat_t: {
735 return Copy<float>(addr, targetaddress);
736 break;
737 }
738 case kDouble_t: {
739 return Copy<double>(addr, targetaddress);
740 break;
741 }
742 case kDouble32_t: {
743 return Copy<double>(addr, targetaddress);
744 break;
745 }
746 case kchar: {
747 unsupp();
748 break;
749 }
750 case kBool_t: {
751 return Copy<bool>(addr, targetaddress);
752 break;
753 }
754 case kLong64_t: {
755 return Copy<long long>(addr, targetaddress);
756 break;
757 }
758 case kULong64_t: {
759 return Copy<unsigned long long>(addr, targetaddress);
760 break;
761 }
762 case kOther_t: {
763 unsupp();
764 break;
765 }
766 case kNoType_t: {
767 unsupp();
768 break;
769 }
770 case kFloat16_t: {
771 unsupp();
772 break;
773 }
774 case kCounter: {
775 unsupp();
776 break;
777 }
778 case kCharStar: {
779 return Copy<char*>(addr, targetaddress);
780 break;
781 }
782 case kBits: {
783 unsupp();
784 break;
785 }
786 case kVoid_t: {
787 unsupp();
788 break;
789 }
790 case kDataTypeAliasUnsigned_t: {
791 unsupp();
792 break;
793 }
794 /*
795 case kDataTypeAliasSignedChar_t: {
796 unsupp();
797 break;
798 }
799 case kNumDataTypes: {
800 unsupp();
801 break;
802 }*/
803 default: {
804 unsupp();
805 break;
806 }
807 }
809}
810
811template <typename T>
812ConfigurableParam::EParamUpdateStatus ConvertAndCopy(std::string const& valuestring, void* targetaddr)
813{
814 auto addr = boost::lexical_cast<T>(valuestring);
815 if (isMemblockDifferent<T>(targetaddr, (void*)&addr)) {
816 std::memcpy(targetaddr, (void*)&addr, sizeof(T));
818 }
820}
821
822// special version for std::string
823template <>
824ConfigurableParam::EParamUpdateStatus ConvertAndCopy<std::string>(std::string const& valuestring, void* targetaddr)
825{
826 std::string& target = *((std::string*)targetaddr);
827 if (target.compare(valuestring) != 0) {
828 // the targetaddr is a std::string to which we can simply assign
829 // and all the magic will happen internally
830 target = valuestring;
832 }
834}
835// special version for char and unsigned char since we are interested in the numeric
836// meaning of char as an 8-bit integer (boost lexical cast is assigning the string as a character i// nterpretation
837template <>
838ConfigurableParam::EParamUpdateStatus ConvertAndCopy<char>(std::string const& valuestring, void* targetaddr)
839{
840 int intvalue = boost::lexical_cast<int>(valuestring);
841 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
842 LOG(error) << "Cannot assign " << valuestring << " to a char variable";
844 }
845 char addr = intvalue;
846 if (isMemblockDifferent<char>(targetaddr, (void*)&addr)) {
847 std::memcpy(targetaddr, (void*)&addr, sizeof(char));
849 }
851}
852
853template <>
854ConfigurableParam::EParamUpdateStatus ConvertAndCopy<unsigned char>(std::string const& valuestring, void* targetaddr)
855{
856 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
857 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
858 LOG(error) << "Cannot assign " << valuestring << " to an unsigned char variable";
860 }
861 unsigned char addr = intvalue;
862 if (isMemblockDifferent<unsigned char>(targetaddr, (void*)&addr)) {
863 std::memcpy(targetaddr, (void*)&addr, sizeof(unsigned char));
865 }
867}
868
870{
871 // check if key_exists
872 auto iter = sKeyToStorageMap->find(key);
873 if (iter == sKeyToStorageMap->end()) {
874 LOG(warn) << "Cannot update parameter " << key << " (parameter not found) ";
876 }
877
878 auto targetaddress = iter->second.second;
879
880 // treat some special cases first:
881 // the type is actually a std::string
882 if (iter->second.first == typeid(std::string)) {
883 return ConvertAndCopy<std::string>(valuestring, targetaddress);
884 }
885
886 // the type (aka ROOT::EDataType which the type identification in the map) we need to convert to
887 int targettype = TDataType::GetType(iter->second.first);
888
889 switch (targettype) {
890 case kChar_t: {
891 return ConvertAndCopy<char>(valuestring, targetaddress);
892 break;
893 }
894 case kUChar_t: {
895 return ConvertAndCopy<unsigned char>(valuestring, targetaddress);
896 break;
897 }
898 case kShort_t: {
899 return ConvertAndCopy<short>(valuestring, targetaddress);
900 break;
901 }
902 case kUShort_t: {
903 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
904 break;
905 }
906 case kInt_t: {
907 return ConvertAndCopy<int>(valuestring, targetaddress);
908 break;
909 }
910 case kUInt_t: {
911 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
912 break;
913 }
914 case kLong_t: {
915 return ConvertAndCopy<long>(valuestring, targetaddress);
916 break;
917 }
918 case kULong_t: {
919 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
920 break;
921 }
922 case kFloat_t: {
923 return ConvertAndCopy<float>(valuestring, targetaddress);
924 break;
925 }
926 case kDouble_t: {
927 return ConvertAndCopy<double>(valuestring, targetaddress);
928 break;
929 }
930 case kDouble32_t: {
931 return ConvertAndCopy<double>(valuestring, targetaddress);
932 break;
933 }
934 case kchar: {
935 unsupp();
936 break;
937 }
938 case kBool_t: {
939 return ConvertAndCopy<bool>(valuestring, targetaddress);
940 break;
941 }
942 case kLong64_t: {
943 return ConvertAndCopy<long long>(valuestring, targetaddress);
944 break;
945 }
946 case kULong64_t: {
947 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
948 break;
949 }
950 case kOther_t: {
951 unsupp();
952 break;
953 }
954 case kNoType_t: {
955 unsupp();
956 break;
957 }
958 case kFloat16_t: {
959 unsupp();
960 break;
961 }
962 case kCounter: {
963 unsupp();
964 break;
965 }
966 case kCharStar: {
967 unsupp();
968 // return ConvertAndCopy<char*>(valuestring, targetaddress);
969 break;
970 }
971 case kBits: {
972 unsupp();
973 break;
974 }
975 case kVoid_t: {
976 unsupp();
977 break;
978 }
979 case kDataTypeAliasUnsigned_t: {
980 unsupp();
981 break;
982 }
983 /*
984 case kDataTypeAliasSignedChar_t: {
985 unsupp();
986 break;
987 }
988 case kNumDataTypes: {
989 unsupp();
990 break;
991 }*/
992 default: {
993 unsupp();
994 break;
995 }
996 }
998}
999
1000} // namespace conf
1001} // namespace o2
std::ostringstream debug
int32_t i
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 void setEnumValue(const std::string &, const std::string &)
static void writeINI(std::string const &filename, std::string const &keyOnly="")
static void setValues(std::vector< std::pair< std::string, std::string > > const &keyValues)
static bool configFileExists(std::string const &filepath)
static std::map< std::string, std::pair< std::type_info const &, void * > > * sKeyToStorageMap
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static void write(std::string const &filename, std::string const &keyOnly="")
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 EnumRegistry * sEnumRegistry
static void fromCCDB(std::string filename)
static void updateFromString(std::string const &)
void add(const std::string &key, const TDataMember *dm)
std::string toString() const
bool contains(const std::string &key) const
GLuint entry
Definition glcorearb.h:5735
GLuint const GLchar * name
Definition glcorearb.h:781
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
GLuint GLfloat * val
Definition glcorearb.h:1582
GLenum GLfloat param
Definition glcorearb.h:271
std::string getLiteralSuffixFromType(const std::type_info &type)
bool keyInTree(boost::property_tree::ptree *pt, const std::string &key)
ConfigurableParam::EParamUpdateStatus ConvertAndCopy< unsigned char >(std::string const &valuestring, void *targetaddr)
bool isMemblockDifferent(void const *block1, void const *block2)
std::ostream & operator<<(std::ostream &out, ConfigurableParam const &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
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()
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"