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::writeINI(std::string const& filename, std::string const& keyOnly)
196{
197 if (sOutputDir == "/dev/null") {
198 LOG(debug) << "ignoring writing of ini file " << filename;
199 return;
200 }
202 initPropertyTree(); // update the boost tree before writing
203 if (!keyOnly.empty()) { // write ini for selected key only
204 try {
205 boost::property_tree::ptree kTree;
206 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
207 boost::property_tree::write_ini(outfilename, kTree);
208 } catch (const boost::property_tree::ptree_bad_path& err) {
209 LOG(fatal) << "non-existing key " << keyOnly << " provided to writeINI";
211 } else {
212 boost::property_tree::write_ini(outfilename, *sPtree);
213 }
214}
215
216// ------------------------------------------------------------------
217
218bool ConfigurableParam::configFileExists(std::string const& filepath)
219{
220 return std::filesystem::exists(o2::utils::Str::concat_string(ConfigurableParamReaders::getInputDir(), filepath));
221}
222
223// ------------------------------------------------------------------
224
225void ConfigurableParam::setValue(std::string const& key, std::string const& valuestring)
226{
227 if (!sIsFullyInitialized) {
228 initialize();
229 }
230 assert(sPtree);
231 auto setValueImpl = [&](std::string const& value) {
232 sPtree->put(key, value);
234 if (changed != EParamUpdateStatus::Failed) {
235 sValueProvenanceMap->find(key)->second = kRT; // set to runtime
236 }
237 };
238 try {
239 if (sPtree->get_optional<std::string>(key).is_initialized()) {
240 try {
241 // try first setting value without stripping a literal suffix
242 setValueImpl(valuestring);
243 } catch (...) {
244 // try second stripping the expected literal suffix value for fundamental types
245 auto iter = sKeyToStorageMap->find(key);
246 if (iter == sKeyToStorageMap->end()) {
247 std::cerr << "Error in setValue (string) key is not known\n";
248 return;
249 }
250 const auto expectedSuffix = getLiteralSuffixFromType(iter->second.first);
251 if (!expectedSuffix.empty()) {
252 auto valuestringLower = valuestring;
253 std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), tolower);
254 if (valuestringLower.ends_with(expectedSuffix)) {
255 std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length());
256 setValueImpl(strippedValue);
257 } else {
258 // check if it has a different suffix and throw
259 for (const auto& suffix : {"f", "l", "u", "ul", "ll", "ull"}) {
260 if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) {
261 throw std::invalid_argument("Wrong type suffix: expected " + expectedSuffix + " but got " + suffix);
262 }
263 }
264 throw; // just rethrow the original exception
265 }
266 }
267 }
268 }
269 } catch (std::exception const& e) {
270 std::cerr << "Error in setValue (string) " << e.what() << "\n";
271 }
272}
273
274// ------------------------------------------------------------------
275
276void ConfigurableParam::writeJSON(std::string const& filename, std::string const& keyOnly)
278 if (sOutputDir == "/dev/null") {
279 LOG(info) << "ignoring writing of json file " << filename;
280 return;
281 }
282 initPropertyTree(); // update the boost tree before writing
284 if (!keyOnly.empty()) { // write ini for selected key only
285 try {
286 boost::property_tree::ptree kTree;
287 kTree.add_child(keyOnly, sPtree->get_child(keyOnly));
288 boost::property_tree::write_json(outfilename, kTree);
289 } catch (const boost::property_tree::ptree_bad_path& err) {
290 LOG(fatal) << "non-existing key " << keyOnly << " provided to writeJSON";
291 }
292 } else {
293 boost::property_tree::write_json(outfilename, *sPtree);
294 }
295}
296
297// ------------------------------------------------------------------
298
300{
301 sPtree->clear();
302 for (auto p : *sRegisteredParamClasses) {
303 p->putKeyValues(sPtree);
304 }
305}
306
307// ------------------------------------------------------------------
308
310{
311 if (!sIsFullyInitialized) {
312 initialize();
313 }
314 std::cout << "####\n";
315 for (auto p : *sRegisteredParamClasses) {
316 p->printKeyValues(true, useLogger);
317 }
318 std::cout << "----\n";
319}
320
321// ------------------------------------------------------------------
322
324{
325 if (!sIsFullyInitialized) {
326 initialize();
327 }
328 auto iter = sValueProvenanceMap->find(key);
329 if (iter == sValueProvenanceMap->end()) {
330 throw std::runtime_error(fmt::format("provenace of unknown {:s} parameter is requested", key));
331 }
332 return iter->second;
333}
334
335// ------------------------------------------------------------------
336
337// evidently this could be a local file or an OCDB server
338// ... we need to generalize this ... but ok for demonstration purposes
340{
341 if (!sIsFullyInitialized) {
342 initialize();
343 }
344 TFile file(filename.c_str(), "RECREATE");
345 for (auto p : *sRegisteredParamClasses) {
346 p->serializeTo(&file);
347 }
348 file.Close();
349}
350
351// ------------------------------------------------------------------
352
354{
355 if (!sIsFullyInitialized) {
356 initialize();
357 }
358 TFile file(filename.c_str(), "READ");
359 for (auto p : *sRegisteredParamClasses) {
360 p->initFrom(&file);
361 }
362 file.Close();
363}
364
365// ------------------------------------------------------------------
366
368{
369 if (sRegisteredParamClasses == nullptr) {
370 sRegisteredParamClasses = new std::vector<ConfigurableParam*>;
371 }
372 if (sPtree == nullptr) {
373 sPtree = new boost::property_tree::ptree;
374 }
375 if (sKeyToStorageMap == nullptr) {
376 sKeyToStorageMap = new std::map<std::string, std::pair<std::type_info const&, void*>>;
377 }
378 if (sValueProvenanceMap == nullptr) {
379 sValueProvenanceMap = new std::map<std::string, ConfigurableParam::EParamProvenance>;
380 }
381
382 if (sEnumRegistry == nullptr) {
384 }
385
386 if (sRegisterMode == true) {
387 sRegisteredParamClasses->push_back(this);
388 }
389}
390
391// ------------------------------------------------------------------
392
394{
396 // initialize the provenance map
397 // initially the values come from code
398 for (auto& key : *sKeyToStorageMap) {
399 sValueProvenanceMap->insert(std::pair<std::string, ConfigurableParam::EParamProvenance>(key.first, kCODE));
400 }
401 sIsFullyInitialized = true;
402}
403
404// ------------------------------------------------------------------
405
407{
408 for (auto p : *sRegisteredParamClasses) {
409 std::cout << p->getName() << "\n";
410 }
411}
412
413// ------------------------------------------------------------------
414
415// Update the storage map of params from the given configuration file.
416// It can be in JSON or INI format.
417// If nonempty comma-separated paramsList is provided, only those params will
418// be updated, absence of data for any of requested params will lead to fatal
419// If unchangedOnly is true, then only those parameters whose provenance is kCODE will be updated
420// (to allow prefernce of run-time settings)
421void ConfigurableParam::updateFromFile(std::string const& configFile, std::string const& paramsList, bool unchangedOnly)
422{
423 if (!sIsFullyInitialized) {
424 initialize();
425 }
426
427 auto cfgfile = o2::utils::Str::trim_copy(configFile);
428
429 if (cfgfile.length() == 0) {
430 return;
431 }
432
433 boost::property_tree::ptree pt = ConfigurableParamReaders::readConfigFile(cfgfile);
434
435 std::vector<std::pair<std::string, std::string>> keyValPairs;
436 auto request = o2::utils::Str::tokenize(paramsList, ',', true);
437 std::unordered_map<std::string, int> requestMap;
438 for (const auto& par : request) {
439 if (!par.empty()) {
440 requestMap[par] = 0;
441 }
442 }
443
444 try {
445 for (auto& section : pt) {
446 std::string mainKey = section.first;
447 if (requestMap.size()) {
448 if (requestMap.find(mainKey) == requestMap.end()) {
449 continue; // if something was requested, ignore everything else
450 } else {
451 requestMap[mainKey] = 1;
452 }
453 }
454 for (auto& subKey : section.second) {
455 auto name = subKey.first;
456 auto value = subKey.second.get_value<std::string>();
457 std::string key = mainKey + "." + name;
458 if (!unchangedOnly || getProvenance(key) == kCODE) {
459 std::pair<std::string, std::string> pair = std::make_pair(key, o2::utils::Str::trim_copy(value));
460 keyValPairs.push_back(pair);
461 }
462 }
463 }
464 } catch (std::exception const& error) {
465 LOG(error) << "Error while updating params " << error.what();
466 } catch (...) {
467 LOG(error) << "Unknown while updating params ";
468 }
469
470 // make sure all requested params were retrieved
471 for (const auto& req : requestMap) {
472 if (req.second == 0) {
473 throw std::runtime_error(fmt::format("Param {:s} was not found in {:s}", req.first, configFile));
474 }
475 }
476
477 try {
478 setValues(keyValPairs);
479 } catch (std::exception const& error) {
480 LOG(error) << "Error while setting values " << error.what();
481 }
482}
483
484// ------------------------------------------------------------------
485// ------------------------------------------------------------------
486
487void ConfigurableParam::updateFromString(std::string const& configString)
488{
489 if (!sIsFullyInitialized) {
490 initialize();
491 }
492
493 auto cfgStr = o2::utils::Str::trim_copy(configString);
494 if (cfgStr.length() == 0) {
495 return;
496 }
497
498 // Take a vector of strings with elements of form a=b, and
499 // return a vector of pairs with each pair of form <a, b>
500 auto toKeyValPairs = [](std::vector<std::string>& tokens) {
501 std::vector<std::pair<std::string, std::string>> pairs;
502
503 for (auto& token : tokens) {
504 auto s = token.find('=');
505 if (s == 0 || s == std::string::npos || s == token.size() - 1) {
506 LOG(fatal) << "Illegal command-line key/value string: " << token;
507 continue;
508 }
509 pairs.emplace_back(token.substr(0, s), token.substr(s + 1, token.size()));
510 }
511
512 return pairs;
513 };
514
515 // Simple check that the string starts/ends with an open square bracket
516 // Find the maximum index of a given key with array value.
517 // We store string keys for arrays as a[0]...a[size_of_array]
518 /*
519 auto maxIndex = [](std::string baseName) {
520 bool isFound = true;
521 int index = -1;
522 do {
523 index++;
524 std::string key = baseName + "[" + std::to_string(index) + "]";
525 isFound = keyInTree(sPtree, key);
526 } while (isFound);
527
528 return index;
529 };
530*/
531
532 // ---- end of helper functions --------------------
533
534 // Command-line string is a ;-separated list of key=value params
535 auto params = o2::utils::Str::tokenize(configString, ';', true);
536
537 // Now split each key=value string into its std::pair<key, value> parts
538 auto keyValues = toKeyValPairs(params);
539
540 setValues(keyValues);
541
542 const auto& kv = o2::conf::KeyValParam::Instance();
543 if (getProvenance("keyval.input_dir") != kCODE) {
545 }
546 if (getProvenance("keyval.output_dir") != kCODE) {
547 if (kv.output_dir == "/dev/null") {
548 sOutputDir = kv.output_dir;
549 } else {
551 }
552 }
553}
554
555// setValues takes a vector of pairs where each pair is a key and value
556// to be set in the storage map
557void ConfigurableParam::setValues(std::vector<std::pair<std::string, std::string>> const& keyValues)
558{
559 auto isArray = [](std::string& el) {
560 return el.size() > 0 && (el.at(0) == '[') && (el.at(el.size() - 1) == ']');
561 };
562
563 bool nonFatal = getenv("ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL") != nullptr;
564
565 // Take a vector of param key/value pairs
566 // and update the storage map for each of them by calling setValue.
567 // 1. For string/scalar types this is simple.
568 // 2. For array values we need to iterate over each array element
569 // and call setValue on the element, using an appropriately constructed key.
570 // 3. For enum types we check for the existence of the key in the enum registry
571 // and also confirm that the value is in the list of legal values
572 for (auto& keyValue : keyValues) {
573 std::string key = keyValue.first;
574 std::string value = o2::utils::Str::trim_copy(keyValue.second);
575
576 if (!keyInTree(sPtree, key)) {
577 if (nonFatal) {
578 LOG(warn) << "Ignoring non-existent ConfigurableParam key: " << key;
579 continue;
580 }
581 LOG(fatal) << "Inexistant ConfigurableParam key: " << key;
582 }
583
584 if (sEnumRegistry->contains(key)) {
586 } else if (isArray(value)) {
588 } else {
589 assert(sKeyToStorageMap->find(key) != sKeyToStorageMap->end());
590
591 // If the value is given as a boolean true|false, change to 1|0 int equivalent
592 if (value == "true") {
593 value = "1";
594 } else if (value == "false") {
595 value = "0";
596 }
597
598 // TODO: this will trap complex types like maps and structs.
599 // These need to be broken into their own cases, so that we only
600 // get strings and scalars here.
602 }
603 }
604}
605
606void ConfigurableParam::setArrayValue(const std::string& key, const std::string& value)
607{
608 // We remove the lead/trailing square bracket
609 // value.erase(0, 1).pop_back();
610 auto elems = o2::utils::Str::tokenize(value.substr(1, value.length() - 2), ',', true);
611
612 // TODO:
613 // 1. Should not assume each array element is a scalar/string. We may need to recurse.
614 // 2. Should not assume each array element - even if not complex - is correctly written. Validate.
615 // 3. Validation should include finding same types as in provided defaults.
616 for (int i = 0; i < elems.size(); ++i) {
617 std::string indexKey = key + "[" + std::to_string(i) + "]";
618 setValue(indexKey, elems[i]);
619 }
620}
621
622void ConfigurableParam::setEnumValue(const std::string& key, const std::string& value)
623{
624 int val = (*sEnumRegistry)[key]->getIntValue(value);
625 if (val == -1) {
626 LOG(fatal) << "Illegal value "
627 << value << " for enum " << key
628 << ". Legal string|int values:\n"
629 << (*sEnumRegistry)[key]->toString() << std::endl;
630 }
631
633}
634
635void unsupp() { std::cerr << "currently unsupported\n"; }
636
637template <typename T>
638bool isMemblockDifferent(void const* block1, void const* block2)
639{
640 // loop over thing in elements of bytes
641 for (int i = 0; i < sizeof(T) / sizeof(char); ++i) {
642 if (((char*)block1)[i] != ((char*)block2)[i]) {
643 return true;
644 }
645 }
646 return false;
647}
648
649// copies data from one place to other and returns
650// true of data was actually changed
651template <typename T>
652ConfigurableParam::EParamUpdateStatus Copy(void const* addr, void* targetaddr)
653{
654 if (isMemblockDifferent<T>(addr, targetaddr)) {
655 std::memcpy(targetaddr, addr, sizeof(T));
657 }
659}
660
661ConfigurableParam::EParamUpdateStatus ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string subkey, std::type_info const& tinfo,
662 void* addr)
663{
664 // check if key_exists
665 auto key = mainkey + "." + subkey;
666 auto iter = sKeyToStorageMap->find(key);
667 if (iter == sKeyToStorageMap->end()) {
668 LOG(warn) << "Cannot update parameter " << key << " not found";
670 }
671
672 // the type we need to convert to
673 int type = TDataType::GetType(tinfo);
674
675 // check that type matches
676 if (iter->second.first != tinfo) {
677 LOG(warn) << "Types do not match; cannot update value";
679 }
680
681 auto targetaddress = iter->second.second;
682 switch (type) {
683 case kChar_t: {
684 return Copy<char>(addr, targetaddress);
685 break;
686 }
687 case kUChar_t: {
688 return Copy<unsigned char>(addr, targetaddress);
689 break;
690 }
691 case kShort_t: {
692 return Copy<short>(addr, targetaddress);
693 break;
694 }
695 case kUShort_t: {
696 return Copy<unsigned short>(addr, targetaddress);
697 break;
698 }
699 case kInt_t: {
700 return Copy<int>(addr, targetaddress);
701 break;
702 }
703 case kUInt_t: {
704 return Copy<unsigned int>(addr, targetaddress);
705 break;
706 }
707 case kLong_t: {
708 return Copy<long>(addr, targetaddress);
709 break;
710 }
711 case kULong_t: {
712 return Copy<unsigned long>(addr, targetaddress);
713 break;
714 }
715 case kFloat_t: {
716 return Copy<float>(addr, targetaddress);
717 break;
718 }
719 case kDouble_t: {
720 return Copy<double>(addr, targetaddress);
721 break;
722 }
723 case kDouble32_t: {
724 return Copy<double>(addr, targetaddress);
725 break;
726 }
727 case kchar: {
728 unsupp();
729 break;
730 }
731 case kBool_t: {
732 return Copy<bool>(addr, targetaddress);
733 break;
734 }
735 case kLong64_t: {
736 return Copy<long long>(addr, targetaddress);
737 break;
738 }
739 case kULong64_t: {
740 return Copy<unsigned long long>(addr, targetaddress);
741 break;
742 }
743 case kOther_t: {
744 unsupp();
745 break;
746 }
747 case kNoType_t: {
748 unsupp();
749 break;
750 }
751 case kFloat16_t: {
752 unsupp();
753 break;
754 }
755 case kCounter: {
756 unsupp();
757 break;
758 }
759 case kCharStar: {
760 return Copy<char*>(addr, targetaddress);
761 break;
762 }
763 case kBits: {
764 unsupp();
765 break;
766 }
767 case kVoid_t: {
768 unsupp();
769 break;
770 }
771 case kDataTypeAliasUnsigned_t: {
772 unsupp();
773 break;
774 }
775 /*
776 case kDataTypeAliasSignedChar_t: {
777 unsupp();
778 break;
779 }
780 case kNumDataTypes: {
781 unsupp();
782 break;
783 }*/
784 default: {
785 unsupp();
786 break;
787 }
788 }
790}
791
792template <typename T>
793ConfigurableParam::EParamUpdateStatus ConvertAndCopy(std::string const& valuestring, void* targetaddr)
794{
795 auto addr = boost::lexical_cast<T>(valuestring);
796 if (isMemblockDifferent<T>(targetaddr, (void*)&addr)) {
797 std::memcpy(targetaddr, (void*)&addr, sizeof(T));
799 }
801}
802
803// special version for std::string
804template <>
805ConfigurableParam::EParamUpdateStatus ConvertAndCopy<std::string>(std::string const& valuestring, void* targetaddr)
806{
807 std::string& target = *((std::string*)targetaddr);
808 if (target.compare(valuestring) != 0) {
809 // the targetaddr is a std::string to which we can simply assign
810 // and all the magic will happen internally
811 target = valuestring;
813 }
815}
816// special version for char and unsigned char since we are interested in the numeric
817// meaning of char as an 8-bit integer (boost lexical cast is assigning the string as a character i// nterpretation
818template <>
819ConfigurableParam::EParamUpdateStatus ConvertAndCopy<char>(std::string const& valuestring, void* targetaddr)
820{
821 int intvalue = boost::lexical_cast<int>(valuestring);
822 if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) {
823 LOG(error) << "Cannot assign " << valuestring << " to a char variable";
825 }
826 char addr = intvalue;
827 if (isMemblockDifferent<char>(targetaddr, (void*)&addr)) {
828 std::memcpy(targetaddr, (void*)&addr, sizeof(char));
830 }
832}
833
834template <>
835ConfigurableParam::EParamUpdateStatus ConvertAndCopy<unsigned char>(std::string const& valuestring, void* targetaddr)
836{
837 unsigned int intvalue = boost::lexical_cast<int>(valuestring);
838 if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) {
839 LOG(error) << "Cannot assign " << valuestring << " to an unsigned char variable";
841 }
842 unsigned char addr = intvalue;
843 if (isMemblockDifferent<unsigned char>(targetaddr, (void*)&addr)) {
844 std::memcpy(targetaddr, (void*)&addr, sizeof(unsigned char));
846 }
848}
849
851{
852 // check if key_exists
853 auto iter = sKeyToStorageMap->find(key);
854 if (iter == sKeyToStorageMap->end()) {
855 LOG(warn) << "Cannot update parameter " << key << " (parameter not found) ";
857 }
858
859 auto targetaddress = iter->second.second;
860
861 // treat some special cases first:
862 // the type is actually a std::string
863 if (iter->second.first == typeid(std::string)) {
864 return ConvertAndCopy<std::string>(valuestring, targetaddress);
865 }
866
867 // the type (aka ROOT::EDataType which the type identification in the map) we need to convert to
868 int targettype = TDataType::GetType(iter->second.first);
869
870 switch (targettype) {
871 case kChar_t: {
872 return ConvertAndCopy<char>(valuestring, targetaddress);
873 break;
874 }
875 case kUChar_t: {
876 return ConvertAndCopy<unsigned char>(valuestring, targetaddress);
877 break;
878 }
879 case kShort_t: {
880 return ConvertAndCopy<short>(valuestring, targetaddress);
881 break;
882 }
883 case kUShort_t: {
884 return ConvertAndCopy<unsigned short>(valuestring, targetaddress);
885 break;
886 }
887 case kInt_t: {
888 return ConvertAndCopy<int>(valuestring, targetaddress);
889 break;
890 }
891 case kUInt_t: {
892 return ConvertAndCopy<unsigned int>(valuestring, targetaddress);
893 break;
894 }
895 case kLong_t: {
896 return ConvertAndCopy<long>(valuestring, targetaddress);
897 break;
898 }
899 case kULong_t: {
900 return ConvertAndCopy<unsigned long>(valuestring, targetaddress);
901 break;
902 }
903 case kFloat_t: {
904 return ConvertAndCopy<float>(valuestring, targetaddress);
905 break;
906 }
907 case kDouble_t: {
908 return ConvertAndCopy<double>(valuestring, targetaddress);
909 break;
910 }
911 case kDouble32_t: {
912 return ConvertAndCopy<double>(valuestring, targetaddress);
913 break;
914 }
915 case kchar: {
916 unsupp();
917 break;
918 }
919 case kBool_t: {
920 return ConvertAndCopy<bool>(valuestring, targetaddress);
921 break;
922 }
923 case kLong64_t: {
924 return ConvertAndCopy<long long>(valuestring, targetaddress);
925 break;
926 }
927 case kULong64_t: {
928 return ConvertAndCopy<unsigned long long>(valuestring, targetaddress);
929 break;
930 }
931 case kOther_t: {
932 unsupp();
933 break;
934 }
935 case kNoType_t: {
936 unsupp();
937 break;
938 }
939 case kFloat16_t: {
940 unsupp();
941 break;
942 }
943 case kCounter: {
944 unsupp();
945 break;
946 }
947 case kCharStar: {
948 unsupp();
949 // return ConvertAndCopy<char*>(valuestring, targetaddress);
950 break;
951 }
952 case kBits: {
953 unsupp();
954 break;
955 }
956 case kVoid_t: {
957 unsupp();
958 break;
959 }
960 case kDataTypeAliasUnsigned_t: {
961 unsupp();
962 break;
963 }
964 /*
965 case kDataTypeAliasSignedChar_t: {
966 unsupp();
967 break;
968 }
969 case kNumDataTypes: {
970 unsupp();
971 break;
972 }*/
973 default: {
974 unsupp();
975 break;
976 }
977 }
979}
980
981} // namespace conf
982} // namespace o2
int32_t i
std::ostringstream debug
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 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)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"