AliPhysics  8b695ca (8b695ca)
AliYAMLConfiguration.h
Go to the documentation of this file.
1 #ifndef ALIYAMLCONFIGURATION_H
2 #define ALIYAMLCONFIGURATION_H
3 
4 // CINT can't handle the yaml header because it has c++11!
5 #if !(defined(__CINT__) || defined(__MAKECINT__))
6 #include <yaml-cpp/yaml.h>
7 #endif
8 
9 #include <string>
10 #include <vector>
11 #include <ostream>
12 
13 #include <TObject.h>
14 #include <TString.h>
15 
16 #include <AliLog.h>
17 
136 #if !(defined(__CINT__) || defined(__MAKECINT__))
137 namespace YAML {
138 template<>
139  struct convert<TString> {
140  static Node encode(const TString & str) {
141  return Node(str.Data());
142  }
143  static bool decode(const Node & node, TString & str) {
144  if (!node.IsScalar()) {
145  return false;
146  }
147  str = node.Scalar();
148  return true;
149  }
150  };
151 }
152 #endif
153 
164 template <typename It>
165 class Range
166 {
167  It b, e;
168 
169  public:
170  Range(It b, It e) : b(b), e(e) {}
171  It begin() const { return b; }
172  It end() const { return e; }
173 };
174 
175 template <typename ORange, typename OIt = decltype(std::begin(std::declval<ORange>())),
176  typename It = std::reverse_iterator<OIt>>
177 Range<It> reverse(ORange&& originalRange)
178 {
179  return Range<It>(It(std::end(originalRange)), It(std::begin(originalRange)));
180 }
181 
182 // operator<< has to be forward declared carefully to stay in the global namespace so that it works with CINT.
183 // For generally how to keep the operator in the global namespace, See: https://stackoverflow.com/a/38801633
184 namespace PWG { namespace Tools { class AliYAMLConfiguration; } }
185 std::ostream & operator<< (std::ostream &in, const PWG::Tools::AliYAMLConfiguration &myTask);
186 
187 namespace PWG {
188 namespace Tools {
189 
191  public:
192  AliYAMLConfiguration(const std::string prefixString = "AliEmcalCorrection", const std::string delimiterCharacter = ":");
194 
198  bool Initialize();
199  bool Reinitialize();
205  int AddEmptyConfiguration(const std::string & configurationName);
207  int AddConfiguration(std::string configurationFilename, std::string configurationName = "");
208  #if !(defined(__CINT__) || defined(__MAKECINT__))
209  int AddConfiguration(const YAML::Node node, std::string configurationName = "");
215  bool DoesConfigurationExist(const int i) const { return i >= 0 && static_cast<const unsigned int>(i) < fConfigurations.size(); }
216  bool DoesConfigurationExist(const std::string & name) const { return DoesConfigurationExist(GetConfigurationIndexFromName(name, fConfigurations)); }
217  const std::pair<std::string, YAML::Node> & GetConfiguration(const int i) const { return fConfigurations.at(i); }
218  const std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) const { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
219  std::pair<std::string, YAML::Node> & GetConfiguration(const int i) { return fConfigurations.at(i); }
220  std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
226  std::string GetConfigurationNameFromIndex(const unsigned int i) const { return fConfigurations.at(i).first; }
227  int GetConfigurationIndexFromName(const std::string & name) const { return GetConfigurationIndexFromName(name, fConfigurations); }
233  bool RemoveConfiguration(const unsigned int i);
234  bool RemoveConfiguration(const std::string & name) { return RemoveConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
240  // Helper functions to retrieve property values
241  template<typename T>
242  bool GetProperty(std::vector<std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const;
243  template<typename T>
244  bool GetProperty(const std::vector<std::string> propertyPath, T & property, const bool requiredProperty) const;
245  // Retrieve property driver function.
246  template<typename T>
247  bool GetProperty(std::string propertyName, T & property, const bool requiredProperty = true) const;
253  // Write property driver function.
254  template<typename T>
255  bool WriteProperty(std::string propertyName, T & property, std::string configurationName = "");
257  #endif
258 
262  bool WriteConfiguration(const std::string & filename, const unsigned int i) const;
263  bool WriteConfiguration(const std::string & filename, const std::string & configurationName) const;
269  bool CompareConfigurations(const int config1, const int config2) const;
270  bool CompareConfigurations(const int config1, const std::string & config2) const { return CompareConfigurations(config1, GetConfigurationIndexFromName(config2, fConfigurations)); }
271  bool CompareConfigurations(const std::string & config1, const std::string & config2) const { return CompareConfigurations(GetConfigurationIndexFromName(config1, fConfigurations), GetConfigurationIndexFromName(config2, fConfigurations)); }
272 
278  std::string toString(const int index = -1) const;
279  std::ostream & Print(std::ostream &in, const int index = -1) const;
280  std::ostream & Print(std::ostream &in, const std::string & configurationName) const;
281  friend std::ostream & ::operator<< (std::ostream &in, const AliYAMLConfiguration &myTask);
282  void Print(Option_t* /* opt */ = "") const;
285  protected:
286 
287  // Utility functions
288  // File utilities
289  inline bool DoesFileExist(const std::string & filename) const;
290  void SetupReadingConfigurationFilePath(std::string & filename, const std::string & fileIdentifier) const;
291  void WriteConfigurationToFilePath(const std::string & localFilename, std::string filename) const;
292  #if !(defined(__CINT__) || defined(__MAKECINT__))
293  // Printing
294  void PrintConfiguration(std::ostream & stream, const std::pair<std::string, YAML::Node> & configPair) const;
295  #endif
296  // Configuration utilities
297  template<typename T>
298  unsigned int GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const;
299 
300  bool IsSharedValue(std::string & value) const;
301  #if !(defined(__CINT__) || defined(__MAKECINT__))
302  template<typename T>
303  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void());
304  template<typename T>
305  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void());
306  template<typename T>
307  void PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const;
308  template<typename T>
309  void PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const;
310 
311  template<typename T>
312  bool GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const;
313  template<typename T>
314  bool GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const;
315 
316  template<typename T>
317  void WriteValue(YAML::Node & node, std::string propertyName, T & proeprty);
318 
319  std::vector<std::pair<std::string, YAML::Node> > fConfigurations;
320  #endif
321  std::vector<std::pair<std::string, std::string> > fConfigurationsStrings;
322 
324  std::string fPrefixString;
325  std::string fDelimiter;
326 
328  ClassDef(AliYAMLConfiguration, 1); // YAML Configuration
330 };
331 
332 #if !(defined(__CINT__) || defined(__MAKECINT__))
333 
343 template<typename T>
344 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void())
345 {
346  tempMessage << " with value \"" << property << "\"";
347 }
348 
357 template<typename T>
358 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void())
359 {
360  tempMessage << " with value(s):";
361  for (auto it = property.begin(); it != property.end(); it++) {
362  tempMessage << "\n\t- " << *it;
363  }
364 }
365 
377 template<typename T>
378 void AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const
379 {
380  // Cannot easily print these types, so just note that is the case!
381  tempMessage << " with a value that cannot be trivially printed";
382 }
383 
395 template<typename T>
396 void AliYAMLConfiguration::PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const
397 {
398  // By passing zero, it will first lookup the int, and then the long
399  AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(tempMessage, property, 0);
400 }
401 
411 template<typename T>
412 bool AliYAMLConfiguration::GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const
413 {
414  if (node[propertyName])
415  {
416  property = node[propertyName].as<T>();
417  return true;
418  }
419  return false;
420 }
421 
433 template<typename T>
434 bool AliYAMLConfiguration::GetProperty(std::vector <std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const
435 {
436  propertyPath.push_back(propertyName);
437  return GetProperty(propertyPath, property, requiredProperty);
438 }
439 
450 template<typename T>
451 bool AliYAMLConfiguration::GetProperty(const std::vector <std::string> propertyPath, T & property, const bool requiredProperty) const
452 {
453  // Combine the requested names together
454  std::string requestedName = "";
455  for (auto & str : propertyPath)
456  {
457  if (requestedName.length() > 0) {
458  requestedName += ":" + str;
459  }
460  else {
461  requestedName = str;
462  }
463  }
464 
465  // Pass on the properly requested call
466  return GetProperty(requestedName, property, requiredProperty);
467 }
468 
480 template<typename T>
481 bool AliYAMLConfiguration::GetProperty(std::string propertyName, T & property, const bool requiredProperty) const
482 {
483  // Remove the prefix string if in name
484  std::size_t prefixStringLocation = propertyName.find(fPrefixString);
485  if (prefixStringLocation != std::string::npos)
486  {
487  // Remove the prefix string
488  propertyName.erase(prefixStringLocation, prefixStringLocation + fPrefixString.length());
489  }
490 
491  bool setProperty = false;
492  // Search in reverse so it is possible to override configuration values.
493  for (auto configPair : reverse(fConfigurations))
494  {
495  if (setProperty == true) {
496  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Property \"" << propertyName << "\" found!\n";
497  break;
498  }
499 
500  // IsNull checks is a node is empty. A node is empty if it is created.
501  // IsDefined checks if the node that was requested was not actually created.
502  if (configPair.second.IsNull() != true)
503  {
504  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Looking for parameter \"" << propertyName << "\" in \"" << configPair.first << "\" configuration\n";
505  // NOTE: This may not exist, but that is entirely fine.
506  YAML::Node sharedParameters = configPair.second["sharedParameters"];
507  setProperty = GetProperty(configPair.second, sharedParameters, configPair.first, propertyName, property);
508  }
509  }
510 
511  if (setProperty != true && requiredProperty == true)
512  {
513  std::stringstream message;
514  message << "Failed to retrieve required property \""
515  << propertyName << "\" from available configurations!" << std::endl;
516  AliFatalGeneral("AliYAMLConfiguration", message.str().c_str());
517  }
518 
519  // Return whether the value was actually set
520  return setProperty;
521 }
522 
545 template<typename T>
546 bool AliYAMLConfiguration::GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const
547 {
548  // Used as a buffer for printing complicated messages
549  std::stringstream tempMessage;
550 
551  bool returnValue = false;
552 
553  const std::string specializationDelimiter = "_";
554  size_t delimiterPosition = 0;
555  std::string tempPropertyName = propertyName;
556 
557  if ((delimiterPosition = tempPropertyName.find(fDelimiter)) != std::string::npos)
558  {
559  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
560  tempPropertyName.erase(0, delimiterPosition + fDelimiter.length());
561 
562  // Attempt to use the node name
563  if (node[nodeName].IsDefined() == true)
564  {
565  // Retrieve node and then recurse
566  YAML::Node tempNode = node[nodeName];
567  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper with node \"" << nodeName << "\".\n";
568  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
569  }
570 
571  // Check for the specialization if the nodeName is undefined.
572  // Alternatively, if the value was not returned successfully, we should also check for the specialization
573  // such as inheritnace for input objects.
574  if (node[nodeName].IsDefined() == false || returnValue == false)
575  {
576  // Check for specialization
577  if ((delimiterPosition = nodeName.find(specializationDelimiter)) != std::string::npos)
578  {
579  std::string specializationNodeName = nodeName.substr(0, delimiterPosition);
580  YAML::Node tempNode = node[specializationNodeName];
581  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper through dropping the specializtion and using node \"" << specializationNodeName << "\".\n";
582  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
583  }
584  else {
585  returnValue = false;
586  }
587  }
588  }
589  else
590  {
591  // Check if node exists!
592  if (node[propertyName])
593  {
594  // Handle shared parameters
595  bool isShared = false;
596  // Will contain the name of the property in the sharedParameters section that should be retrieved
597  // if it is requested through the user configuration.
598  std::string sharedValueName = "";
599  // Necessary because it fails on vectors and other complex objects that are YAML sequences.
600  if (std::is_arithmetic<T>::value || std::is_same<T, std::string>::value || std::is_same<T, bool>::value)
601  {
602  // Retrieve value as string to check for shared value
603  sharedValueName = node[propertyName].as<std::string>();
604  // Check for a shared value
605  isShared = IsSharedValue(sharedValueName);
606  }
607 
608  // Setup printable message
609  tempMessage.str("");
610  tempMessage << "property \""
611  << propertyName
612  << "\" using " << ( isShared ? "\"sharedParameters:" + sharedValueName + "\" in " : "" )
613  << "values from the " << configurationName << " configuration";
614 
615  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Retrieveing " << tempMessage.str() << "\n";
616 
617  // Retrieve result
618  bool retrievalResult = false;
619  if (isShared == true) {
620  // Retrieve from the shared parameter node directly.
621  retrievalResult = GetPropertyFromNode(sharedParametersNode, sharedValueName, property);
622  }
623  else {
624  retrievalResult = GetPropertyFromNode(node, propertyName, property);
625  }
626 
627  // Inform about the result
628  if (retrievalResult == true) {
629  // Add the retrieved value to the message (only if trivially printable)
630  AliYAMLConfiguration::PrintRetrievedPropertyValue(tempMessage, property);
631  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Succeeded in retrieveing " << tempMessage.str() << "\n";
632  returnValue = true;
633  }
634  else {
635  returnValue = false;
636  }
637  }
638  }
639 
640  return returnValue;
641 }
642 
653 template<typename T>
654 bool AliYAMLConfiguration::WriteProperty(std::string propertyName, T & property, std::string configurationName)
655 {
656  unsigned int configurationIndex = 0;
657  if (configurationName != "")
658  {
659  configurationIndex = GetConfigurationIndexFromName(configurationName, fConfigurations);
660  }
661 
662  if (fConfigurations.size() == 0) {
663  AliErrorStream() << "No configurations available! Property will not be written!\n";
664  return false;
665  }
666 
667  std::pair<std::string, YAML::Node> & configPair = fConfigurations.at(configurationIndex);
668 
669  WriteValue(configPair.second, propertyName, property);
670  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Final Node:\n" << configPair.second << "\n";
671 
672  return true;
673 }
674 
682 template<typename T>
683 void AliYAMLConfiguration::WriteValue(YAML::Node & node, std::string propertyName, T & property)
684 {
685  // Find the node name we are interested in
686  // Derived from: https://stackoverflow.com/a/14266139
687  const std::string delimiter = ":";
688  size_t delimiterPosition = 0;
689  std::string tempPropertyName = propertyName;
690 
691  if ((delimiterPosition = tempPropertyName.find(delimiter)) != std::string::npos)
692  {
693  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
694  tempPropertyName.erase(0, delimiterPosition + delimiter.length());
695  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "nodeName: " << nodeName << "\n";
696  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node Before:\n" << node << "\n";
697  if (node[nodeName].IsDefined()) {
698  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Using existing node\n";
699  YAML::Node tempNode = node[nodeName];
700  WriteValue(tempNode, tempPropertyName, property);
701  }
702  else {
703  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Creating new node\n";
704  YAML::Node tempNode;
705  node[nodeName] = tempNode;
706  WriteValue(tempNode, tempPropertyName, property);
707  }
708  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node After:\n" << node << "\n";
709  }
710  else {
711  // We have finished the recursion. Now we need to save the actual property.
712  node[propertyName] = property;
713  }
714 }
715 
716 #endif
717 
727 template<typename T>
728 unsigned int AliYAMLConfiguration::GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const
729 {
730  int index = -1;
731  for (const auto & configPair : configurations)
732  {
733  if (configPair.first == name) {
734  // Retrieve index
735  // See: https://stackoverflow.com/a/10962459
736  index = std::addressof(configPair) - std::addressof(configurations[0]);
737  break;
738  }
739  }
740 
741  return index;
742 }
743 
744 } // namespace Tools
745 } // namespace PWG
746 
747 #endif /* ALIYAMLCONFIGURATION_H */
bool RemoveConfiguration(const std::string &name)
const char * filename
Definition: TestFCM.C:1
void Print(std::ostream &o, const char *name, Double_t dT, Double_t dVM, Double_t alldT, Double_t alldVM)
Definition: PlotSysInfo.C:121
bool CompareConfigurations(const int config1, const std::string &config2) const
Range(It b, It e)
It begin() const
const std::pair< std::string, YAML::Node > & GetConfiguration(const int i) const
bool fInitialized
True if the configurations have been initialized.
bool DoesConfigurationExist(const int i) const
int GetConfigurationIndexFromName(const std::string &name) const
UShort_t T(UShort_t m, UShort_t t)
Definition: RingBits.C:60
const std::pair< std::string, YAML::Node > & GetConfiguration(const std::string &name) const
std::string fDelimiter
Delimiter character to separate each level of the request.
bool DoesConfigurationExist(const std::string &name) const
std::ostream & operator<<(std::ostream &in, const PWG::Tools::AliYAMLConfiguration &myTask)
Namespace for PWG framework classes.
Range< It > reverse(ORange &&originalRange)
std::string fPrefixString
Contains the prefix of any names base node names which should be removed.
std::vector< std::pair< std::string, YAML::Node > > fConfigurations
! Contains all YAML configurations. The first element has the highest precedence. ...
bool CompareConfigurations(const std::string &config1, const std::string &config2) const
static Node encode(const TString &str)
std::pair< std::string, YAML::Node > & GetConfiguration(const int i)
std::vector< std::pair< std::string, std::string > > fConfigurationsStrings
Contains all YAML configurations as strings so that they can be streamed.
YAML configuration class for AliPhysics.
static bool decode(const Node &node, TString &str)
const char Option_t
Definition: External.C:48
std::string GetConfigurationNameFromIndex(const unsigned int i) const
It end() const
std::pair< std::string, YAML::Node > & GetConfiguration(const std::string &name)