00001
00015 #ifndef USER_INFO_H
00016 #define USER_INFO_H
00017
00018 #include <stdio.h>
00019 #include <string>
00020 #include <typeinfo>
00021 #include <map>
00022 #include <stdexcept>
00023
00024 #include "libconfig/libconfig.h++"
00025 #include "../bdmroot.h"
00026 #include "itpp/itbase.h"
00027
00028
00029 using std::string;
00030 using namespace std;
00031 using namespace libconfig;
00032
00033 namespace bdm {
00034
00038 class UIException : public std::exception {
00039
00040 public:
00042 const string message;
00043
00045 const string path;
00046
00048 UIException ( const string &message, const Setting &element )
00049 : message ( "UI error: " + message + "." ), path ( "Check path \"" + string ( element.getPath() ) + "\"." ) {
00050 }
00051
00053 UIException ( const string &message, const string &path )
00054 : message ( "UI error: " + message + "." ), path ( "Check path \"" + path + "\"." ) {
00055 }
00056
00058 virtual const char* what() const throw() {
00059 return ( message + " " + path ).c_str();
00060 }
00061 ~UIException() throw() {};
00062 };
00063
00064
00089 class UIFile : public Config {
00090 public:
00092 UIFile();
00093
00095 UIFile ( const string &file_name );
00096
00098 void save ( const string &file_name );
00099
00101 operator Setting&();
00102 };
00103
00170 class SettingResolver : root {
00171 private:
00173 UIFile *file;
00174
00180 const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00181
00182 public:
00184 const Setting &result;
00185
00187 SettingResolver ( const Setting &potential_link );
00188
00190 ~SettingResolver();
00191 };
00192
00203 class UI {
00204 private:
00210 class MappedUI {
00211 private:
00213 typedef map< const string, const UI* const > StringToUIMap;
00214
00216 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00217
00219 static StringToUIMap& mapped_strings();
00220
00222 static TypeInfoToStringMap& mapped_type_infos();
00223
00225 static void unregistered_class_error ( const string &unregistered_class_name );
00226
00227 public:
00229 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00230
00232 static const UI& retrieve_ui ( const string &class_name );
00233
00235 static const string& retrieve_class_name ( const type_info* const class_type_info );
00236 };
00237
00239 static void assert_type ( const Setting &element, Setting::Type type );
00240
00242 virtual root* new_instance() const = 0;
00243
00245 static const Setting& to_child_setting ( const Setting &element, const int index );
00246
00248 static const Setting& to_child_setting ( const Setting &element, const string &name );
00249
00251 static void from_setting ( mat& matrix, const Setting &element );
00253 static void from_setting ( ivec &vector, const Setting &element );
00255 static void from_setting ( string &str, const Setting &element );
00257 static void from_setting ( vec &vector, const Setting &element );
00259 static void from_setting ( int &integer, const Setting &element );
00261 static void from_setting ( double &real, const Setting &element );
00263 template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00264 const SettingResolver link ( element );
00265 assert_type ( link.result, Setting::TypeGroup );
00266
00267
00268 string class_name;
00269 if ( !link.result.lookupValue ( "class", class_name ) )
00270 throw UIException ( "the obligatory \"class\" identifier is missing", link.result );
00271
00272
00273 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00274
00275 root* typeless_instance = related_UI.new_instance();
00276
00277 instance = dynamic_cast<T*> ( typeless_instance );
00278 if ( !instance )
00279 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 );
00280
00281 try {
00282 instance->from_setting ( link.result );
00283 } catch ( SettingException sttng_xcptn ) {
00284 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00285 throw exception ( msg.c_str() );
00286 } catch ( UIException uixcptn ) {
00287 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\".";
00288 throw exception ( msg.c_str() );
00289 } catch ( exception xcptn ) {
00290 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\".";
00291 throw exception ( msg.c_str() );
00292 }
00293 }
00294
00296 template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00297 const SettingResolver link ( element );
00298
00299 assert_type ( link.result, Setting::TypeList );
00300
00301 int len = link.result.getLength();
00302 array_to_load.set_length ( len );
00303 if ( len == 0 ) return;
00304
00305 for ( int i = 0; i < len; i++ )
00306 from_setting ( array_to_load ( i ), link.result[i] );
00307 }
00308
00313 template<class T> static void from_setting ( T &array_to_load, const Setting &element ) {
00314 throw UIException( "from_setting is not implemented for this type", element );
00315 }
00316
00317
00318 protected:
00320 UI ( const string& class_name, const type_info * const class_type_info ) {
00321 MappedUI::add_class ( class_name, class_type_info, this );
00322 }
00323
00324 public:
00325
00327 enum SettingPresence { optional, compulsory } ;
00328
00332
00336 template<class T> static T* build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00337 if ( !element.exists ( name ) )
00338 {
00339 if( settingPresence == optional )
00340 return NULL;
00341 else
00342 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00343 }
00344
00345 T* instance;
00346 from_setting<T> ( instance, to_child_setting ( element, name ) );
00347 return instance;
00348 }
00349
00353 template<class T> static T* build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00354 if ( element.getLength() <= index )
00355 {
00356 if( settingPresence == optional )
00357 return NULL;
00358 else
00359 {
00360 stringstream stream;
00361 stream << index;
00362 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element );
00363 }
00364 }
00365
00366 T* instance;
00367 from_setting<T> ( instance, to_child_setting ( element, index ) );
00368 return instance;
00369 }
00370
00372 template<class T> static T* build ( const Setting &element ) {
00373 T* instance;
00374 from_setting<T> ( instance, element );
00375 return instance;
00376
00377 }
00378
00380
00384
00387 template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00388 if ( !element.exists ( name ) )
00389 {
00390 if( settingPresence == optional )
00391 return false;
00392 else
00393 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00394 }
00395
00396 from_setting ( instance, to_child_setting ( element, name ) );
00397 return true;
00398 }
00399
00402 template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00403 if ( element.getLength() <= index )
00404 {
00405 if( settingPresence == optional )
00406 return false;
00407 else
00408 {
00409 stringstream stream;
00410 stream << index;
00411 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element );
00412 }
00413 }
00414
00415 from_setting ( instance, to_child_setting ( element, index ) );
00416 return true;
00417 }
00418
00420 template<class T> static bool get ( T &instance, const Setting &element ) {
00421 from_setting ( instance, element );
00422 return true;
00423 }
00425
00429
00432 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00433 if ( !element.exists ( name ) )
00434 return false;
00435
00436 from_setting ( array_to_load, to_child_setting ( element, name ) );
00437 return true;
00438 }
00439
00442 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00443 if ( element.getLength() <= index )
00444 return false;
00445
00446 from_setting ( array_to_load, to_child_setting ( element, index ) );
00447 return true;
00448 }
00449
00451 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00452 from_setting ( array_to_load, element );
00453 return true;
00454 }
00456
00461
00463 template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00464 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00465 : element.add ( name, Setting::TypeGroup );
00466
00467 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00468
00469
00470 Setting &type = set.add ( "class", Setting::TypeString );
00471 type = class_name;
00472
00473 try {
00474 instance->to_setting ( set );
00475 } catch ( SettingException sttng_xcptn ) {
00476 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00477 throw exception ( msg.c_str() );
00478 } catch ( UIException uixcptn ) {
00479 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\".";
00480 throw exception ( msg.c_str() );
00481 } catch ( exception xcptn ) {
00482 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\".";
00483 throw exception ( msg.c_str() );
00484 }
00485 }
00486
00488 template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00489 assert_type ( element, Setting::TypeGroup );
00490 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00491 : element.add ( name, Setting::TypeList );
00492 for ( int i = 0; i < array_to_save.length(); i++ )
00493 save ( array_to_save ( i ), list );
00494 }
00495
00497 static void save ( const mat &matrix, Setting &element, const string &name = "" );
00498
00500 static void save ( const ivec &vec, Setting &element, const string &name = "" );
00501
00503 static void save ( const vec &vector, Setting &element, const string &name = "" );
00504
00506 static void save ( const string &str, Setting &element, const string &name = "" );
00507
00509 static void save ( const int &integer, Setting &element, const string &name = "" );
00510
00512 static void save ( const double &real, Setting &element, const string &name = "" );
00514
00515 };
00516
00517
00520 template<typename T> class ParticularUI : private UI {
00521 private:
00523 ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00524
00525 public:
00527 static const ParticularUI<T>& factory;
00528
00530 root* new_instance() const {
00531 return new T();
00532 }
00533 };
00534
00535 }
00536
00546 #ifndef BDMLIB
00547 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::factory = ParticularUI<class_name>(#class_name)
00548 #else
00549 #define UIREGISTER(class_name)
00550 #endif
00551
00552 #endif // #ifndef USER_INFO_H