ConfigDictionary.cpp 9.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
#include "ConfigDictionary.h"

ClassImp(ConfigDictionary);

//////////////////////////////////////////////////////////////////////////////
//	BEGIN_HTML
//	<p><font size="4"><b>Config(uration)Dictionary class</b></font></p>
//  <br>
// 	<i>Author: Bartlomiej Hnatio 2012-08-06</i>
//	<br><br>
//	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.
//	<br><br><br>
//	<u>Most simple example of usage:</u>
//	<br><br>Suppose you have two variables fD and fI:
//	<pre>-------------------
//    Double_t fD;
//    Int_t fI;
//
//fD = 3.14;
//fI = 2012;
//-----------------------</pre>
//	To save its parameters into file you can create ConfigDictionary class
//	instance and use <b>SetDouble</b> and <b>SetInt</b> functions to
//	insert parameters values with arbitrarly defined keys (let them be
//	really long and descriptive in this example):
//	<pre>---------------------
//ConfigDictionary CD;
//CD.SetDouble("Most important variable D",fD);
//CD.SetInt("Equally important integer I",fI);
//---------------------</pre>
//	Now configuration string saved in <b>ConfigDictionary</b> CD
//	can be obtained with <b>ToString</b> method and should look like:
//<pre>
//"Most important variable D"="3.14" "Equally important integer I"="2012"
//</pre>
//	<br> It can be easily saved to a file using simplest <i>fstream</i>
//	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.
//	<br>
//	<br>
//	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:
//	<pre>-----------------
//"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"
//(...)
//----------------</pre>
//	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 <b>FromString</b> method. After this, you can
// 	extract parameters (using <b>GetDouble</b> and <b>GetInt</b> methods)
//	with using same keys as were used for saving, and ConfigDictionary
//	will return their values:
//	<pre>----------------------
//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");
//--------------------</pre>
//<br>
//	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 <b>Get</b> 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 <b>Get</b> 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:
//<pre>-------------------
//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!");
//}
//--------------------</pre>
//
// 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<std::string,std::string>::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<<"\""<<it->first<<"\""<<"="<<"\""<<it->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;
	}
}

//_____________________________________________________________________________
Vratislav Chudoba's avatar
Vratislav Chudoba committed
164
std::string ConfigDictionary::GetString(std::string key){
165 166 167 168 169 170
	//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());
Vratislav Chudoba's avatar
Vratislav Chudoba committed
171 172
		// throw(key);
		throw std::runtime_error("Couldn't find the key: " + key);
173 174 175 176 177
	}
	return configMap[key];
}

//_____________________________________________________________________________
Vratislav Chudoba's avatar
Vratislav Chudoba committed
178 179 180 181 182 183 184 185 186
int ConfigDictionary::GetInt(std::string key) {
    // Extracts integer from given key
    // (if it exists, otherwise raises exception)
    try {
        return Get<int>(key);
    } catch (const std::string& message) {
        // Catch the exception thrown by Get<int> and re-throw it as std::runtime_error
        throw std::runtime_error(message);
    }
187 188 189
}

//_____________________________________________________________________________
Vratislav Chudoba's avatar
Vratislav Chudoba committed
190
double ConfigDictionary::GetDouble(std::string key){
191 192
	//Extracts double precision floating number from given key
	//(if it exist, otherwise raises exception)
Vratislav Chudoba's avatar
Vratislav Chudoba committed
193 194 195 196 197 198 199
	try
	{
		return Get<double>(key);
	} catch (const std::string& message) {
        // Catch the exception thrown by Get<int> and re-throw it as std::runtime_error
        throw std::runtime_error(message);
    }
200 201 202
}

//_____________________________________________________________________________
Vratislav Chudoba's avatar
Vratislav Chudoba committed
203
bool ConfigDictionary::GetBool(std::string key){
204 205 206
	//Extracts boolean from given key
	//(if it exist, otherwise raises exception)
	//Differs from template to make it more readable.
Vratislav Chudoba's avatar
Vratislav Chudoba committed
207 208
	
	// Check if the key exists in the config map
209 210 211
	if (configMap.find(key) == configMap.end()){
		Error("ConfigDictionary::GetBool",
				"Couldn't find the key: %s!",key.c_str());
Vratislav Chudoba's avatar
Vratislav Chudoba committed
212
		throw std::runtime_error("Couldn't find the key: " + key);
213 214 215 216
	}
	//Convert string to bool:
	if (configMap[key].compare("true") == 0)
		return true;
Vratislav Chudoba's avatar
Vratislav Chudoba committed
217 218
	else
		return false;
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
}

//_____________________________________________________________________________
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<double>(key,value);
}

//_____________________________________________________________________________
void ConfigDictionary::SetInt(std::string key,int value){
	//Sets value to key, converts int to string first
	Set<int>(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";
}