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 "../shared_ptr.h"
00027 #include "itpp/itbase.h"
00028
00029
00030 using std::string;
00031 using namespace std;
00032 using namespace libconfig;
00033
00034 namespace bdm {
00035
00039 class UIException : public std::exception {
00040 private:
00042 const string message;
00043
00044 public:
00049 UIException ( const string &message ) :
00050 message ( message ) {
00051 }
00052
00054 virtual const char* what() const throw() {
00055 return message.c_str();
00056 }
00057
00058 ~UIException() throw() {};
00059
00060 protected:
00065 static string format_message( const string &reason, const string &path );
00066 };
00067
00071 class UISettingException : public UIException {
00072 public:
00074 UISettingException ( const string &message, const Setting &element ):
00075 UIException ( format_message ( message, string ( element.getPath() ) ) ) {
00076 }
00077
00079 UISettingException ( const string &message, const string &path ):
00080 UIException ( format_message ( message, path ) ) {
00081 }
00082
00083 ~UISettingException() throw() {};
00084 };
00085
00089 class UIClassException : public UIException {
00090 public:
00092 UIClassException ( const string &message, const Setting &element ):
00093 UIException ( format_message ( message, string ( element.getPath() ) ) ) {
00094 }
00095
00097 UIClassException ( const string &message, const string &path ):
00098 UIException ( format_message ( message, path ) ) {
00099 }
00100
00101 ~UIClassException() throw() {};
00102 };
00103
00128 class UIFile : public Config {
00129 public:
00131 UIFile();
00132
00134 UIFile ( const string &file_name );
00135
00137 void save ( const string &file_name );
00138
00140 operator Setting&();
00141 };
00142
00209 class SettingResolver : root {
00210 private:
00212 UIFile *file;
00213
00219 const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00220
00221 public:
00223 const Setting &result;
00224
00226 SettingResolver ( const Setting &potential_link );
00227
00229 ~SettingResolver();
00230 };
00231
00242 class UI {
00243 private:
00249 class MappedUI {
00250 private:
00252 typedef map< const string, const UI* const > StringToUIMap;
00253
00255 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00256
00258 static StringToUIMap& mapped_strings();
00259
00261 static TypeInfoToStringMap& mapped_type_infos();
00262
00264 static void unregistered_class_error ( const string &unregistered_class_name );
00265
00266 public:
00268 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00269
00271 static const UI& retrieve_ui ( const string &class_name );
00272
00274 static const string& retrieve_class_name ( const type_info* const class_type_info );
00275 };
00276
00278 static void assert_type ( const Setting &element, Setting::Type type );
00279
00288 virtual root* new_instance() const = 0;
00289
00291 static const Setting& to_child_setting ( const Setting &element, const int index );
00292
00294 static const Setting& to_child_setting ( const Setting &element, const string &name );
00295
00297 static void from_setting ( mat& matrix, const Setting &element );
00299 static void from_setting ( ivec &vector, const Setting &element );
00301 static void from_setting ( string &str, const Setting &element );
00303 static void from_setting ( vec &vector, const Setting &element );
00305 static void from_setting ( int &integer, const Setting &element );
00307 static void from_setting ( double &real, const Setting &element );
00308
00310 template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00311 const SettingResolver link ( element );
00312 assert_type ( link.result, Setting::TypeGroup );
00313
00314
00315 string class_name;
00316 if ( !link.result.lookupValue ( "class", class_name ) )
00317 throw UIClassException ( "UIException: the obligatory \"class\" identifier is missing.", link.result );
00318
00319
00320 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00321
00322 root *typeless_instance = related_UI.new_instance();
00323 bdm_assert ( typeless_instance, "UI::new_instance failed" );
00324
00325 instance = dynamic_cast<T*> ( typeless_instance );
00326 if ( !instance ) {
00327 delete typeless_instance;
00328 throw UIClassException ( "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 );
00329 }
00330
00331 try {
00332 instance->from_setting ( link.result );
00333 } catch ( SettingException &sttng_xcptn ) {
00334 delete instance;
00335 instance = 0;
00336 string msg = "UIException: method ";
00337 msg += class_name;
00338 msg += ".from_setting(Setting&) has thrown a SettingException.";
00339 throw UISettingException(msg, sttng_xcptn.getPath());
00340 } catch (std::runtime_error &e) {
00341 delete instance;
00342 instance = 0;
00343 string msg = "UIException: method ";
00344 msg += class_name;
00345 msg += " says: ";
00346 msg += e.what();
00347 throw UISettingException(msg, link.result);
00348 } catch (...) {
00349 delete instance;
00350 instance = 0;
00351 throw;
00352 }
00353 }
00354
00357 template<class T>
00358 static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00359 T *tmp_inst = 0;
00360 from_setting ( tmp_inst, element );
00361 bdm_assert ( tmp_inst, "UI::from_setting failed" );
00362 instance = tmp_inst;
00363 }
00364
00366 template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00367 const SettingResolver link ( element );
00368
00369 assert_type ( link.result, Setting::TypeList );
00370
00371 int len = link.result.getLength();
00372 array_to_load.set_length ( len );
00373 if ( len == 0 ) return;
00374
00375 for ( int i = 0; i < len; i++ )
00376 from_setting ( array_to_load ( i ), link.result[i] );
00377 }
00378
00383 template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00384 std::string msg = "UIException: from_setting is not implemented for type ";
00385 msg += typeid(T).name();
00386 msg += '.';
00387 throw UISettingException ( msg, element );
00388 }
00389
00390
00391 protected:
00393 UI ( const string& class_name, const type_info * const class_type_info ) {
00394 MappedUI::add_class ( class_name, class_type_info, this );
00395 }
00396
00397 public:
00398
00400 enum SettingPresence { optional, compulsory } ;
00401
00405
00409 template<class T>
00410 static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00411 if ( !element.exists ( name ) ) {
00412 if ( settingPresence == optional )
00413 return shared_ptr<T>();
00414 else
00415 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00416 }
00417
00418 shared_ptr<T> instance;
00419 from_setting<T> ( instance, to_child_setting ( element, name ) );
00420 return instance;
00421 }
00422
00426 template<class T>
00427 static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00428 if ( element.getLength() <= index ) {
00429 if ( settingPresence == optional )
00430 return shared_ptr<T>();
00431 else {
00432 stringstream stream;
00433 stream << index;
00434 throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
00435 }
00436 }
00437
00438 shared_ptr<T> instance;
00439 from_setting<T> ( instance, to_child_setting ( element, index ) );
00440 return instance;
00441 }
00442
00444
00448
00451 template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00452 if ( !element.exists ( name ) ) {
00453 if ( settingPresence == optional )
00454 return false;
00455 else
00456 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00457 }
00458
00459 from_setting ( instance, to_child_setting ( element, name ) );
00460 return true;
00461 }
00462
00465 template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00466 if ( element.getLength() <= index ) {
00467 if ( settingPresence == optional )
00468 return false;
00469 else {
00470 stringstream stream;
00471 stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
00472 stream << index;
00473 throw UISettingException (stream.str(), element );
00474 }
00475 }
00476
00477 from_setting ( instance, to_child_setting ( element, index ) );
00478 return true;
00479 }
00480
00482 template<class T> static bool get ( T &instance, const Setting &element ) {
00483 from_setting ( instance, element );
00484 return true;
00485 }
00487
00491
00494 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00495 if ( !element.exists ( name ) )
00496 return false;
00497
00498 from_setting ( array_to_load, to_child_setting ( element, name ) );
00499 return true;
00500 }
00501
00504 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00505 if ( element.getLength() <= index )
00506 return false;
00507
00508 from_setting ( array_to_load, to_child_setting ( element, index ) );
00509 return true;
00510 }
00511
00513 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00514 from_setting ( array_to_load, element );
00515 return true;
00516 }
00518
00523
00525 template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00526 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00527 : element.add ( name, Setting::TypeGroup );
00528
00529 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00530
00531
00532 Setting &type = set.add ( "class", Setting::TypeString );
00533 type = class_name;
00534
00535 try {
00536 instance->to_setting ( set );
00537 } catch ( SettingException &sttng_xcptn ) {
00538 string msg = "UIException: method ";
00539 msg += class_name;
00540 msg += ".to_setting(Setting&) has thrown a SettingException.";
00541 throw UISettingException(msg, sttng_xcptn.getPath());
00542 }
00543 }
00544
00545 template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00546 save<T> ( instance.get(), element, name );
00547 }
00548
00550 template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00551 assert_type ( element, Setting::TypeGroup );
00552 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00553 : element.add ( name, Setting::TypeList );
00554 for ( int i = 0; i < array_to_save.length(); i++ )
00555 save ( array_to_save ( i ), list );
00556 }
00557
00559 static void save ( const mat &matrix, Setting &element, const string &name = "" );
00560
00562 static void save ( const ivec &vec, Setting &element, const string &name = "" );
00563
00565 static void save ( const vec &vector, Setting &element, const string &name = "" );
00566
00568 static void save ( const string &str, Setting &element, const string &name = "" );
00569
00571 static void save ( const int &integer, Setting &element, const string &name = "" );
00572
00574 static void save ( const double &real, Setting &element, const string &name = "" );
00576
00577 };
00578
00579
00582 template<typename T> class ParticularUI : private UI {
00583 public:
00585 ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00586
00588 root* new_instance() const {
00589 return new T();
00590 }
00591 };
00592
00593 }
00594
00604 #ifndef BDMLIB
00605 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00606 #else
00607 #define UIREGISTER(class_name)
00608 #endif
00609
00611 #define QUOTEME(x) #x
00612
00621 #ifndef BDMLIB
00622 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00623 #else
00624 #define UIREGISTER2(class_name,temp_name)
00625 #endif
00626
00627 #endif // #ifndef USER_INFO_H