#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";
}