#include "ConfigDictionary.h" ClassImp(ConfigDictionary); ////////////////////////////////////////////////////////////////////////////// // BEGIN_HTML //

Config(uration)Dictionary class

//
// Author: Bartlomiej Hnatio 2012-08-06 //

// This is very useful class to convert strings containing pairs "key"="value" // into fast dictionaries. This strings are often read from external files. // From dictionary created in such way one can easily // extract values in few supported formats (integer, double, boolean, string) // It can also be used in opposite direction: when dictionary is created with // given values and keys, one can create config string, which is most // convenient to write in external files. //


// Most simple example of usage: //

Suppose you have two variables fD and fI: //
-------------------
//    Double_t fD;
//    Int_t fI;
//
//fD = 3.14;
//fI = 2012;
//-----------------------
// To save its parameters into file you can create ConfigDictionary class // instance and use SetDouble and SetInt functions to // insert parameters values with arbitrarly defined keys (let them be // really long and descriptive in this example): //
---------------------
//ConfigDictionary CD;
//CD.SetDouble("Most important variable D",fD);
//CD.SetInt("Equally important integer I",fI);
//---------------------
// Now configuration string saved in ConfigDictionary CD // can be obtained with ToString method and should look like: //
//"Most important variable D"="3.14" "Equally important integer I"="2012"
//
//
It can be easily saved to a file using simplest fstream // methods. And the advantage is that as a key one can use any string, // so configuration file created in such way is very self-explanatory. //
//
// Now lets suppose the opposite action - loading config from file. // Imagine, that you have 1000 objects of A class, which config was saved // to file - one object per line: //
-----------------
//"Most important variable D"="3.14" "Equally important integer I"="2012"
//"Equally important integer I"="1011" "Most important variable D"="8.15"
//"Most important variable D"="13.16" "Equally important integer I"="10"
//(...)
//----------------
// Please notice that order in which pairs of keys and values are placed // in file doesn't make any difference to the ConfigDictionary class. // To recreate objects, you just read each line containing single // config string and then create with it ConfigDictionary object // using special constructor with string as argument, // or using FromString method. After this, you can // extract parameters (using GetDouble and GetInt methods) // with using same keys as were used for saving, and ConfigDictionary // will return their values: //
----------------------
//string line;//This line you read from file
//ConfigDictionary CD(line);
//fD = CD.GetDouble("Most important variable D");
//fI = CD.GetInt("Equally important integer I");
//--------------------
//
// And last but not least: what happens, if key requested by user doesn't // exist in dictionary? (This can be caused by many reasons, mostly errors on // user side, but not always). // When you try to extract non-existent key using Get functions, // an exception is risen. In normal program it should end execution and print // some information about where program stopped working. // But lets say that you don't want that, i.e. program may use default // configs instead of those from files, or not all keys were that important. // You can surround all uses of Get methods with try/catch clause. // So when exception is risen, you will catch it, and decide, if you want // the program to stop running, or anything else. Simple example is // shown below: //
-------------------
//ConfigDictionary CD(some_string);
//try{//try to read important variables:
//  double d = CD.GetDouble("crucial var");
//  bool b = CD.GetBool("most important b");
//  int i = CD.GetInt("unique ID");
//  //...and so on
//}catch(std::string & e){//catch any kind of exception
//  Error("Some crucial variable wasn't read, ending program!");
//  return SOME_REALLY_BAD_ERROR_CODE;
//}
//try{//now less important, or optional:
//  string name = CD.GetString("least important variable");
//  double p = CD.GetDouble("optional parameter");
//  //...and so on
//}catch(std::string & f){
//  Info("Some optional variables wasn't read!");
//}
//--------------------
// // ADDED 21.03.2012: // // With use of templates, now ConfigDictionary can handle complex objects // reading and writing instantly as long as proper >> and << operators are // provided for an object initialization. // // END_HTML ////////////////////////////////////////////////////////////////////////////// //_____________________________________________________________________________ ConfigDictionary::ConfigDictionary(){ //Empty map... } //_____________________________________________________________________________ ConfigDictionary::ConfigDictionary(std::string params){ //Creates dictionary using FromString method FromString(params); } //_____________________________________________________________________________ std::string ConfigDictionary::ToString(){ //Builds string that can be easily saved to file. //Same format that can be read from files or from QtGui //This should work same way for all uses std::map::iterator it;//Iterator to map elements std::stringstream ss;//stream helpful with adding strings //iterate whole dictionary: for (it=configMap.begin();it!=configMap.end();++it){ //insert pairs "key"="value": ss<<"\""<first<<"\""<<"="<<"\""<second<<"\""<<" "; } return ss.str(); } //_____________________________________________________________________________ void ConfigDictionary::FromString(std::string params){ //params - TString containing list of key=value pairs // //Changes string formatted: //"key1"="value1" "key2"="value with spaces 2" ... //into map with keys and values //Useful in lots of I/O functions, //when we want to have a nice, readable format of data std::stringstream loading(params); std::string k,v; while(!loading.fail()){ getline(loading,k,'\"');//removes everything to first " getline(loading,k,'\"');//All chars between first two "" are the key getline(loading,v,'\"');//removes all until third " getline(loading,v,'\"');//All between another pair of "" is the value if (!loading.fail()) configMap[k]=v; } } //_____________________________________________________________________________ std::string ConfigDictionary::GetString(std::string key){ //Extracts string from given key //(if it exist, otherwise raises exception) //This works also for long strings with white spaces in it! if (configMap.find(key) == configMap.end()){ Error("ConfigDictionary::GetString", "Couldn't find the key: %s!",key.c_str()); // throw(key); throw std::runtime_error("Couldn't find the key: " + key); } return configMap[key]; } //_____________________________________________________________________________ int ConfigDictionary::GetInt(std::string key) { // Extracts integer from given key // (if it exists, otherwise raises exception) try { return Get(key); } catch (const std::string& message) { // Catch the exception thrown by Get and re-throw it as std::runtime_error throw std::runtime_error(message); } } //_____________________________________________________________________________ double ConfigDictionary::GetDouble(std::string key){ //Extracts double precision floating number from given key //(if it exist, otherwise raises exception) try { return Get(key); } catch (const std::string& message) { // Catch the exception thrown by Get and re-throw it as std::runtime_error throw std::runtime_error(message); } } //_____________________________________________________________________________ bool ConfigDictionary::GetBool(std::string key){ //Extracts boolean from given key //(if it exist, otherwise raises exception) //Differs from template to make it more readable. // Check if the key exists in the config map if (configMap.find(key) == configMap.end()){ Error("ConfigDictionary::GetBool", "Couldn't find the key: %s!",key.c_str()); throw std::runtime_error("Couldn't find the key: " + key); } //Convert string to bool: if (configMap[key].compare("true") == 0) return true; else return false; } //_____________________________________________________________________________ void ConfigDictionary::SetString(std::string key,std::string value){ //Sets value to key, no comments needed here... configMap[key] = value; } //_____________________________________________________________________________ void ConfigDictionary::SetDouble(std::string key,double value){ Set(key,value); } //_____________________________________________________________________________ void ConfigDictionary::SetInt(std::string key,int value){ //Sets value to key, converts int to string first Set(key,value); } //_____________________________________________________________________________ void ConfigDictionary::SetBool(std::string key,bool value){ //Sets value to key, converts bool to string first //Differs from template to make it more readable. if (value == true) configMap[key] = "true"; else configMap[key] = "false"; }