Changeset 396 for library/bdm/base/user_info.h
- Timestamp:
- 06/24/09 13:38:47 (15 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
library/bdm/base/user_info.h
r394 r396 1 /*! 2 \file 3 \brief UI (user info) class for loading/saving objects from/to configuration files. 4 It is designed over with an use of 'libconfig � C/C++ Configuration File Library' 5 \author Vaclav Smidl. 6 7 ----------------------------------- 8 BDM++ - C++ library for Bayesian Decision Making under Uncertainty 9 10 Using IT++ for numerical operations 11 ----------------------------------- 12 */ 13 1 14 #ifndef USER_INFO_H 2 15 #define USER_INFO_H … … 6 19 #include <typeinfo> 7 20 #include <map> 21 #include <stdexcept> 8 22 9 23 #include "libconfig/libconfig.h++" … … 11 25 #include "itpp/itbase.h" 12 26 13 #include <stdexcept>14 27 15 28 using std::string; … … 22 35 /*! 23 36 \def UIREGISTER(class_name) 24 Macro for registration of class into map of UserInfos -- registered class is scriptable 25 26 TODO napsat i to, ze UIREG musi byt v hacku.. 37 \brief Macro for registration of class into map of user-infos, registered class is scriptable using UI static methods 38 39 Argument \a class_name has to be a descendant of root class and also, it has to have parameterless constructor prepared. 40 This macro should be used in header file, immediately after a class declaration. 41 42 \sa TODO MODUL 27 43 */ 28 44 #ifndef BDMLIB 29 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::ui= ParticularUI<class_name>(#class_name)45 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::factory = ParticularUI<class_name>(#class_name) 30 46 #else 31 #define UIREGISTER(class_name)47 #define UIREGISTER(class_name) 32 48 #endif 33 49 34 //! macro assertting that the setting SET is of the SettingType TYPE 35 #define ASSERT_UITYPE(SET,TYPE) it_assert_debug(SET.getType()==Setting::TYPE, string("Wrong setting type, see input path \"")+string(SET.getPath())+string("\"")) 36 37 //! exception used in UI::build if it fails it can be caught and handled - see merger_mex.h 38 class UIbuildException : public std::invalid_argument { 39 public: 40 UIbuildException() : std::invalid_argument("class name") { } 50 //! Exception prepared for reporting user-info errors which are always related to some concrete Setting path 51 class UIException : public std::exception 52 { 53 private: 54 //! Error message 55 const string message; 56 57 public: 58 //! Use this constructor when you can pass the problematical Setting as a parameter 59 UIException( const string &message, const Setting &element ) 60 : message( "UI error: " + message + ". Check path \"" + string(element.getPath()) + "\"." ) 61 { 62 } 63 64 //! This constructor is for other occasions, when only path of problematical Setting is known 65 UIException( const string &message, const string &path ) 66 : message( "UI error: " + message + "! Check path \"" + path + "\"." ) 67 { 68 } 69 70 //! Overriden method for reporting an error message 71 virtual const char* what() const throw() 72 { 73 return message.c_str(); 74 } 41 75 }; 76 42 77 43 78 /*! … … 66 101 { 67 102 public: 68 //! create empty file instance prepared to store Settings103 //! Create empty file instance prepared to store Settings 69 104 UIFile(); 70 105 71 //! creates instance and fills it from the configuration file file_name106 //! Creates instance and fills it from the configuration file file_name 72 107 UIFile( const string &file_name ); 73 108 74 //! save all the stored Settings into the configuration file file_name109 //! Save all the stored Settings into the configuration file file_name 75 110 void save(const string &file_name); 76 111 77 //! this operator allows the ability of substituting Setting parameter by UIFile instance112 //! This operator allows the ability of substituting Setting parameter by UIFile instance 78 113 operator Setting&(); 79 114 }; 80 115 81 116 /*! 117 @brief This class serves to expand links used within configuration files. 118 119 Value of any type but string can be linked to some other value of the same type 120 defined elsewhere in the current configuration file or even in some different 121 configuration file. 122 123 Link have three parts, \<name\> : \<path\> \<\@filename\>. Field \<name\> contains the 124 name of the new setting, \<path\> is the relative path to the referenced setting, which 125 has to be taken from the %root Setting element. The last part \<\@filename\> is optional, 126 it contains filename in the case the link should refer to a variable stored in a different 127 file. From the previous part \<path\>, it has to be separated by '@'. 128 129 \code 130 ... 131 jardovo : 132 { 133 class = "Car"; 134 year = 1992; 135 manufacturer = "liaz"; 136 kilometers = 1555000; 137 }; 138 ondrejovo : 139 { 140 class = "Bike"; 141 year = 1996; 142 manufacturer = "author"; 143 electricLights = true; 144 matr = ( 2, 2, [ 1.0, 0.0, 0.0, 1.0 ] ); 145 }; 146 147 #this is the example of local link to another mean of transport 148 elisky = "jardovo"; 149 150 ... 151 152 # and this link is external link pointing to file "other_cars.cfg" stored in the 153 # same directory, in that file, it refers to the local Setting "magic_cars.skubankovo" 154 kati = "magic_cars.skubankovo@other_cars.cfg"; 155 156 ... 157 \endcode 158 159 When you want to expand a possible linked setting "element" within your code, it has to be treated this way: 160 161 \code 162 ... 163 164 const SettingResolver link( element ); 165 166 ... 167 168 int len = link.result.getLength(); 169 170 ... 171 \endcode 172 173 The whole point is that a resolved link (class member #result, i.e., "link.result" in the previous example) could point 174 into a different configuration file. In that case there has to be an UIFile instance managing reading from this 175 file. As the libconfig::Config deletes all its Settings when dealocated, UIFile must not be dealocated until all 176 the necessary operation on the linked Setting are finished (otherwise, the link #result would be invalid just after 177 the UIFile dealocation). And that is exactly the mechanism implemented within SettingResolver class. It assures, 178 that the #result Setting reference is valid within the scope of SettingResolver instance. 179 */ 180 class SettingResolver : root 181 { 182 private: 183 //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL 184 UIFile *file; 185 186 //! This method initialize #result reference, i.e., it executes the main code of SettingResolver class 187 //! 188 //! This code could be also located directly in constructor. The only reason why we made this 189 //! method is the keyword 'const' within the declaration of #result reference . Such a reference 190 //! have to be intialized before any other constructor command, exactly in the way it is implemented now. 191 const Setting &initialize_reference( UIFile* &file, const Setting &potential_link); 192 193 public: 194 //! Reference to a resolved link or to the original Setting in the case it does not contain a link 195 const Setting &result; 196 197 //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference #result is prepared for use. 198 SettingResolver( const Setting &potential_link ); 199 200 //! An opened UIFile file is closed here if necessary. 201 ~SettingResolver(); 202 }; 82 203 83 204 /*! … … 94 215 //! 95 216 //! The key property of this class is that it initilaize the internal map immediately 96 //! when it is used for a first time. Therefore, we do not have to care about the97 //! order of calls to UIREGISTER macro, which operateswith both these mappings.217 //! when it is used for a first time. Therefore, we do not have to care about initialization 218 //! during a call of UIREGISTER macro operating with both these mappings. 98 219 class MappedUI 99 220 { … … 105 226 typedef map< const type_info * const, const string > TypeInfoToStringMap; 106 227 107 //! immediately initialized instance of type StringToUIMap228 //! Immediately initialized instance of type StringToUIMap 108 229 static StringToUIMap& mapped_strings(); 109 230 110 //! immediately initialized instance of type TypeInfoToStringMap231 //! Immediately initialized instance of type TypeInfoToStringMap 111 232 static TypeInfoToStringMap& mapped_type_infos(); 112 233 113 //! method for reporting a error when an attempt to operate with an unregistered class occures234 //! Method for reporting a error when an attempt to operate with an unregistered class occures 114 235 static void unregistered_class_error( const string &unregistered_class_name ); 115 236 116 237 public: 117 //! add a pair key-userinfo into the internal map238 //! Add a pair key-userinfo into the internal map 118 239 static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui ); 119 240 120 //! search for an userinfo related to the passed class name within the internal map241 //! Search for an userinfo related to the passed class name within the internal map 121 242 static const UI& retrieve_ui( const string &class_name ); 122 243 123 //! search for an class name related to the passed type_info within the internal map244 //! Search for an class name related to the passed type_info within the internal map 124 245 static const string& retrieve_class_name( const type_info* const class_type_info ); 125 246 }; 126 247 248 //! Function assertting that the setting element is of the SettingType type 249 static void assert_type( const Setting &element, Setting::Type type); 250 127 251 //! Method assembling a typeless instance, it is implemented in descendant class ParticularUI<T> 128 252 virtual root* new_instance() const = 0; … … 134 258 static const Setting& to_child_setting( const Setting &element, const string &name ); 135 259 136 //! This method sconverts a Setting into a matrix260 //! This method converts a Setting into a matrix 137 261 static void from_setting( mat& matrix, const Setting &element ); 138 //! This method sconverts a Setting into an integer vector262 //! This method converts a Setting into an integer vector 139 263 static void from_setting( ivec &vector, const Setting &element ); 140 //! This method sconverts a Setting into a string264 //! This method converts a Setting into a string 141 265 static void from_setting( string &str, const Setting &element ); 142 //! This method sconverts a Setting into a real vector266 //! This method converts a Setting into a real vector 143 267 static void from_setting( vec &vector, const Setting &element ); 144 //! This method sconverts a Setting into a integer scalar268 //! This method converts a Setting into a integer scalar 145 269 static void from_setting( int &integer, const Setting &element ); 146 //! This method sconverts a Setting into a real scalar270 //! This method converts a Setting into a real scalar 147 271 static void from_setting( double &real, const Setting &element ); 148 //! This method sconverts a Setting into a class T descendant272 //! This method converts a Setting into a class T descendant 149 273 template<class T> static void from_setting( T* &instance, const Setting &element ) 150 274 { 151 275 const SettingResolver link( element ); 152 153 ASSERT_UITYPE(link.result,TypeGroup); 154 155 // we get a velue stored in the "class" attribute 276 assert_type(link.result,Setting::TypeGroup); 277 278 // we get a value stored in the "class" attribute 156 279 string class_name; 157 280 if( !link.result.lookupValue( "class", class_name ) ) 158 ui_error( "the obligatory ""class"" identifier is missing", link.result );281 throw UIException( "the obligatory \"class\" identifier is missing", link.result ); 159 282 160 283 // then we find a user-info related to this type … … 163 286 root* typeless_instance = related_UI.new_instance(); 164 287 165 instance = NULL;166 //try catch does not work!!!167 288 instance = dynamic_cast<T*>(typeless_instance); 168 if (!instance){ 169 throw UIbuildException(); 170 } 171 // catch(...) 172 // { 173 // TODO pouzit ui_error? 174 // it_error ( "UI error: class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build function with a different type parameter." ); 175 // } 176 // 289 if (!instance) 290 throw UIException( "class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build<T> function with a different type parameter.", link.result ); 291 177 292 try 178 293 { … … 181 296 catch(SettingException xcptn) 182 297 { 183 // TODO pouzit ui_error? 184 it_error ( "UI error: the method " + class_name + ".from_setting(Setting&) has thrown an exception when parsing the setting " + xcptn.getPath() + ". Try to correct this method." ); 298 throw UIException( "the method " + class_name + ".from_setting(Setting&) has thrown an SettingException. Try to correct this method", xcptn.getPath()); 185 299 } 186 300 } 187 301 188 //! This methods converts a Setting into a new templated array , 189 // TODO efektivne jen pro vect, mat a string, pro dalsi je nutne pridat from_setting metodu.. ale to asi necceme 302 //! This methods converts a Setting into a new templated array of type Array<T> 190 303 template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element ) 191 304 { 192 305 const SettingResolver link( element ); 193 306 194 ASSERT_UITYPE(link.result,TypeList);307 assert_type(link.result,Setting::TypeList); 195 308 196 309 int len = link.result.getLength(); … … 202 315 } 203 316 204 //! Method for reporting user-info errors related to some concrete Setting205 static void ui_error( string message, const Setting &element );206 207 317 protected: 208 318 //! Default constructor for internal use only, see \sa ParticularUI<T> … … 214 324 public: 215 325 216 /*! 217 @brief This class serves to expand links used in configuration file. 218 219 TODO - napsat co dela, a hlavne proc je to takhle implementovany.. otevreny soubor! 220 221 ABSOLUTE PATH.. 222 223 Firstly, save some user-infos into the new UIFile instance. Then, 224 call the save method with a filename as its only argument: 225 226 \code 227 CAudi audi; 228 UIFile file; 229 UI::save( audi, file, "TT"); 230 file.save("cars.cfg"); 231 \endcode 232 233 */ 234 class SettingResolver 235 { 236 private: 237 //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL 238 UIFile *file; 239 240 //! This method initialize result reference, i.e., it executes the main code of SettingResolver class 241 //! 242 //! This code could be also located directly in constructor. The only reason why we made this 243 //! method is the keyword 'const' within the declaration of result reference (TODO funguje odkaz?). Such a reference 244 //! have to be intialized before any other constructor command, exactly in the way it is implemented now. 245 const Setting &initialize_reference( UIFile* &file, const Setting &potential_link); 246 247 public: 248 //! Reference to a resolved link or to the original Setting in the case it does not contain a link 249 const Setting &result; 250 251 //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference result is prepared for use. 252 SettingResolver( const Setting &potential_link ); 253 254 //! An opened UIFile file is closed here if necessary. 255 ~SettingResolver(); 256 }; 257 258 //TODO 259 //! \name Initialization of bdm::root descendant classes according the values stored in a Setting variable 326 //! \name Initialization of classes 260 327 //!@{ 261 //! Return value is by the second argument since it type checking via \c dynamic_cast. 262 template<class T> static T* build( const Setting &element, const int index ) 263 { 264 T* instance; 265 from_setting<T>( instance, to_child_setting( element, index ) ); 266 return instance; 267 } 268 //! VS: addition for root elements 269 template<class T> static T* build( const Setting &element ) 270 { 271 T* instance; 272 from_setting<T>( instance, element ); 273 return instance; 274 } 275 328 //! The type T has to be a root descendant class 329 330 //! The new instance of type T* is constructed and initialized with values stored in the Setting element[name] 276 331 template<class T> static T* build( const Setting &element, const string &name ) 277 332 { … … 280 335 return instance; 281 336 } 337 //! The new instance of type T* is constructed and initialized with values stored in the Setting element[index] 338 template<class T> static T* build( const Setting &element, const int index ) 339 { 340 T* instance; 341 from_setting<T>( instance, to_child_setting( element, index ) ); 342 return instance; 343 } 344 //! The new instance of type T* is constructed and initialized with values stored in the Setting element 345 template<class T> static T* build( const Setting &element ) 346 { 347 T* instance; 348 from_setting<T>( instance, element ); 349 return instance; 350 } 282 351 //!@} 283 352 284 //! \name Initialization of structures according the values stored in a Setting variable - TODO VYCET?!353 //! \name Initialization of structures 285 354 //!@{ 286 //! This methods tries to build a new double matrix 355 //! The type T has to be int, double, string, vec, ivec or mat. 356 357 //! The existing instance of type T is initialized with values stored in the Setting element[name] 287 358 template<class T> static void get( T &instance, const Setting &element, const string &name ) 288 359 { … … 290 361 } 291 362 292 //! Th is methods tries to build a new double matrix363 //! The existing instance of type T is initialized with values stored in the Setting element[index] 293 364 template<class T> static void get( T &instance, const Setting &element, const int index ) 294 365 { … … 296 367 } 297 368 298 //! Th is methods tries to build a new double matrix369 //! The existing instance of type T is initialized with values stored in the Setting element directly 299 370 template<class T> static void get( T &instance, const Setting &element ) 300 371 { 301 372 from_setting( instance, element ); 302 373 } 303 304 //! This methods tries to build a new double matrix 374 //!@} 375 376 //! \name Initialization of arrays Array<T> 377 //!@{ 378 //! The type T has to be int, double, string, vec, ivec or mat, or pointer to any root descendant. 379 380 //! The existing array of type T is initialized with values stored in the Setting element[name] 305 381 template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name ) 306 382 { … … 308 384 } 309 385 310 //! Th is methods tries to build a new double matrix386 //! The existing array of type T is initialized with values stored in the Setting element[index] 311 387 template<class T> static void get( Array<T> &array_to_load, const Setting &element, const int index ) 312 388 { … … 314 390 } 315 391 316 //! Th is methods tries to build a new double matrix392 //! The existing array of type T is initialized with values stored in the Setting element 317 393 template<class T> static void get( Array<T> &array_to_load, const Setting &element ) 318 394 { … … 321 397 //!@} 322 398 399 //! \name Serialization of objects and structures into a new Setting 400 //!@{ 401 //! The new child Setting can be accessed either by its name - if some name is passed as a parameter - 402 //! or by its integer index. In that case, the new element is added at the very end of the current list of child Settings. 403 404 //! A root descendant instance is stored in the new child Setting appended to the passed element 323 405 template< class T> static void save( const T * const instance, Setting &element, const string &name = "") 324 406 { … … 338 420 catch(SettingException xcptn) 339 421 { 340 it_error ( "UI error: the method " + class_name + ".to_setting(Setting&) has thrown an exception when filling the setting " + xcptn.getPath() + ". Try to correct this method.");422 throw UIException( "the method " + class_name + ".to_setting(Setting&) has thrown an SettingException. Try to correct this method", xcptn.getPath()); 341 423 } 342 424 } 343 425 344 //! This methods tries to save a double vec426 //! An Array<T> instance is stored in the new child Setting appended to the passed element 345 427 template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" ) 346 428 { 347 ASSERT_UITYPE(element,TypeGroup);429 assert_type(element,Setting::TypeGroup); 348 430 Setting &list = (name == "") ? element.add( Setting::TypeList ) 349 431 : element.add( name, Setting::TypeList ); … … 352 434 } 353 435 354 355 //! This methods tries to save a double matrix 436 //! A matrix(of type mat) is stored in the new child Setting appended to the passed element 356 437 static void save( const mat &matrix, Setting &element, const string &name = "" ); 357 438 358 //! This methods tries to save a double vec439 //! An integer vector (of type ivec) is stored in the new child Setting appended to the passed element 359 440 static void save( const ivec &vec, Setting &element, const string &name = "" ); 360 441 442 //! A double vector (of type vec) is stored in the new child Setting appended to the passed element 361 443 static void save( const vec &vector, Setting &element, const string &name = "" ); 362 //! This methods tries to save a double vec 444 445 //! A string is stored in the new child Setting appended to the passed element 363 446 static void save( const string &str, Setting &element, const string &name = "" ); 364 447 448 //! An integer is stored in the new child Setting appended to the passed element 365 449 static void save( const int &integer, Setting &element, const string &name = "" ); 366 450 451 //! A double is stored in the new child Setting appended to the passed element 367 452 static void save( const double &real, Setting &element, const string &name = "" ); 453 //!@} 368 454 369 455 }; 370 456 371 457 372 /*! 373 @brief The main userinfo template class. You should derive this class whenever you need 374 a new userinfo of a class which is compound from smaller elements (all having its 375 own userinfo class prepared). 376 */ 458 //! The only UI descendant class which is not intended for direct use. It should be accessed within the ::UIREGISTER macro only. 377 459 template<typename T> class ParticularUI : private UI 378 460 { 379 public: 380 381 //! default constructor, which is intentionally declared as private 461 private: 462 //! Default constructor, which is intentionally declared as private 382 463 ParticularUI<T>( const string &class_name) : UI( class_name, &typeid(T) ) 383 { cout << class_name << endl;384 }; 385 386 //! the only instance of this class (each type T has its own instance)387 //! which is used as a factory for processing related UI388 static const ParticularUI<T>& ui; 389 464 {}; 465 466 public: 467 //! The only instance of this class (each type T has its own instance) which is used as a factory for processing related UI 468 static const ParticularUI<T>& factory; 469 470 //! A method returning a brand new instance of class T, this method is the reason why there have to be a parameterless construcotor in class T 390 471 root* new_instance() const 391 472 { … … 394 475 }; 395 476 396 397 398 399 477 } 400 478 401 /*! Recursive build of objects defined in the same file402 403 \code404 {type="internal";405 path="system.profile.[0]"; // Path from the root406 };407 \endcode408 */409 410 411 412 /*! Recursive build of objects defined in external file413 414 \code415 {type="external";416 filename="my_file.cfg"; // name of file from which to read417 path="system.profile.[0]"; // Path in the external file418 };419 \endcode420 /421 422 */423 424 479 #endif // #ifndef USER_INFO_H