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_debug ( 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 (...) {
00341 delete instance;
00342 instance = 0;
00343 throw;
00344 }
00345 }
00346
00349 template<class T>
00350 static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00351 T *tmp_inst = 0;
00352 from_setting ( tmp_inst, element );
00353 bdm_assert_debug ( tmp_inst, "UI::from_setting failed" );
00354 instance = tmp_inst;
00355 }
00356
00358 template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00359 const SettingResolver link ( element );
00360
00361 assert_type ( link.result, Setting::TypeList );
00362
00363 int len = link.result.getLength();
00364 array_to_load.set_length ( len );
00365 if ( len == 0 ) return;
00366
00367 for ( int i = 0; i < len; i++ )
00368 from_setting ( array_to_load ( i ), link.result[i] );
00369 }
00370
00375 template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00376 std::string msg = "UIException: from_setting is not implemented for type ";
00377 msg += typeid(T).name();
00378 msg += '.';
00379 throw UISettingException ( msg, element );
00380 }
00381
00382
00383 protected:
00385 UI ( const string& class_name, const type_info * const class_type_info ) {
00386 MappedUI::add_class ( class_name, class_type_info, this );
00387 }
00388
00389 public:
00390
00392 enum SettingPresence { optional, compulsory } ;
00393
00397
00401 template<class T>
00402 static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00403 if ( !element.exists ( name ) ) {
00404 if ( settingPresence == optional )
00405 return shared_ptr<T>();
00406 else
00407 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00408 }
00409
00410 shared_ptr<T> instance;
00411 from_setting<T> ( instance, to_child_setting ( element, name ) );
00412 return instance;
00413 }
00414
00418 template<class T>
00419 static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00420 if ( element.getLength() <= index ) {
00421 if ( settingPresence == optional )
00422 return shared_ptr<T>();
00423 else {
00424 stringstream stream;
00425 stream << index;
00426 throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
00427 }
00428 }
00429
00430 shared_ptr<T> instance;
00431 from_setting<T> ( instance, to_child_setting ( element, index ) );
00432 return instance;
00433 }
00434
00436
00440
00443 template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00444 if ( !element.exists ( name ) ) {
00445 if ( settingPresence == optional )
00446 return false;
00447 else
00448 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00449 }
00450
00451 from_setting ( instance, to_child_setting ( element, name ) );
00452 return true;
00453 }
00454
00457 template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00458 if ( element.getLength() <= index ) {
00459 if ( settingPresence == optional )
00460 return false;
00461 else {
00462 stringstream stream;
00463 stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
00464 stream << index;
00465 throw UISettingException (stream.str(), element );
00466 }
00467 }
00468
00469 from_setting ( instance, to_child_setting ( element, index ) );
00470 return true;
00471 }
00472
00474 template<class T> static bool get ( T &instance, const Setting &element ) {
00475 from_setting ( instance, element );
00476 return true;
00477 }
00479
00483
00486 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00487 if ( !element.exists ( name ) )
00488 return false;
00489
00490 from_setting ( array_to_load, to_child_setting ( element, name ) );
00491 return true;
00492 }
00493
00496 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00497 if ( element.getLength() <= index )
00498 return false;
00499
00500 from_setting ( array_to_load, to_child_setting ( element, index ) );
00501 return true;
00502 }
00503
00505 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00506 from_setting ( array_to_load, element );
00507 return true;
00508 }
00510
00515
00517 template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00518 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00519 : element.add ( name, Setting::TypeGroup );
00520
00521 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00522
00523
00524 Setting &type = set.add ( "class", Setting::TypeString );
00525 type = class_name;
00526
00527 try {
00528 instance->to_setting ( set );
00529 } catch ( SettingException &sttng_xcptn ) {
00530 string msg = "UIException: method ";
00531 msg += class_name;
00532 msg += ".to_setting(Setting&) has thrown a SettingException.";
00533 throw UISettingException(msg, sttng_xcptn.getPath());
00534 }
00535 }
00536
00537 template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00538 save<T> ( instance.get(), element, name );
00539 }
00540
00542 template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00543 assert_type ( element, Setting::TypeGroup );
00544 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00545 : element.add ( name, Setting::TypeList );
00546 for ( int i = 0; i < array_to_save.length(); i++ )
00547 save ( array_to_save ( i ), list );
00548 }
00549
00551 static void save ( const mat &matrix, Setting &element, const string &name = "" );
00552
00554 static void save ( const ivec &vec, Setting &element, const string &name = "" );
00555
00557 static void save ( const vec &vector, Setting &element, const string &name = "" );
00558
00560 static void save ( const string &str, Setting &element, const string &name = "" );
00561
00563 static void save ( const int &integer, Setting &element, const string &name = "" );
00564
00566 static void save ( const double &real, Setting &element, const string &name = "" );
00568
00569 };
00570
00571
00574 template<typename T> class ParticularUI : private UI {
00575 public:
00577 ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00578
00580 root* new_instance() const {
00581 return new T();
00582 }
00583 };
00584
00585 }
00586
00596 #ifndef BDMLIB
00597 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00598 #else
00599 #define UIREGISTER(class_name)
00600 #endif
00601
00603 #define QUOTEME(x) #x
00604
00613 #ifndef BDMLIB
00614 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00615 #else
00616 #define UIREGISTER2(class_name,temp_name)
00617 #endif
00618
00619 #endif // #ifndef USER_INFO_H