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
00041 public:
00043 const string message;
00044
00046 const string path;
00047
00048 private:
00049 string what_message;
00050
00051 public:
00053 UIException ( const string &message, const Setting &element )
00054 : message ( "UI error: " + message + "." ), path ( "Check path \"" + string ( element.getPath() ) + "\"." ) {
00055 init_what_message();
00056 }
00057
00059 UIException ( const string &message, const string &path )
00060 : message ( "UI error: " + message + "." ), path ( "Check path \"" + path + "\"." ) {
00061 init_what_message();
00062 }
00063
00065 virtual const char* what() const throw() {
00066 return what_message.c_str();
00067 }
00068
00069 ~UIException() throw() {};
00070
00071 private:
00072 void init_what_message() {
00073 what_message = message;
00074 what_message += ' ';
00075 what_message += path;
00076 }
00077 };
00078
00079
00104 class UIFile : public Config {
00105 public:
00107 UIFile();
00108
00110 UIFile ( const string &file_name );
00111
00113 void save ( const string &file_name );
00114
00116 operator Setting&();
00117 };
00118
00185 class SettingResolver : root {
00186 private:
00188 UIFile *file;
00189
00195 const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00196
00197 public:
00199 const Setting &result;
00200
00202 SettingResolver ( const Setting &potential_link );
00203
00205 ~SettingResolver();
00206 };
00207
00218 class UI {
00219 private:
00225 class MappedUI {
00226 private:
00228 typedef map< const string, const UI* const > StringToUIMap;
00229
00231 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00232
00234 static StringToUIMap& mapped_strings();
00235
00237 static TypeInfoToStringMap& mapped_type_infos();
00238
00240 static void unregistered_class_error ( const string &unregistered_class_name );
00241
00242 public:
00244 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00245
00247 static const UI& retrieve_ui ( const string &class_name );
00248
00250 static const string& retrieve_class_name ( const type_info* const class_type_info );
00251 };
00252
00254 static void assert_type ( const Setting &element, Setting::Type type );
00255
00264 virtual root* new_instance() const = 0;
00265
00267 static const Setting& to_child_setting ( const Setting &element, const int index );
00268
00270 static const Setting& to_child_setting ( const Setting &element, const string &name );
00271
00273 static void from_setting ( mat& matrix, const Setting &element );
00275 static void from_setting ( ivec &vector, const Setting &element );
00277 static void from_setting ( string &str, const Setting &element );
00279 static void from_setting ( vec &vector, const Setting &element );
00281 static void from_setting ( int &integer, const Setting &element );
00283 static void from_setting ( double &real, const Setting &element );
00284
00286 template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00287 const SettingResolver link ( element );
00288 assert_type ( link.result, Setting::TypeGroup );
00289
00290
00291 string class_name;
00292 if ( !link.result.lookupValue ( "class", class_name ) )
00293 throw UIException ( "the obligatory \"class\" identifier is missing", link.result );
00294
00295
00296 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00297
00298 root *typeless_instance = related_UI.new_instance();
00299 it_assert_debug ( typeless_instance, "UI::new_instance failed" );
00300
00301 instance = dynamic_cast<T*> ( typeless_instance );
00302 if ( !instance ) {
00303 delete typeless_instance;
00304 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 );
00305 }
00306
00307 try {
00308 instance->from_setting ( link.result );
00309 } catch ( SettingException sttng_xcptn ) {
00310 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00311 throw UIException(msg, link.result);
00312 }
00313 }
00314
00317 template<class T>
00318 static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00319 T *tmp_inst = 0;
00320 from_setting ( tmp_inst, element );
00321 it_assert_debug ( tmp_inst, "UI::from_setting failed" );
00322 instance = tmp_inst;
00323 }
00324
00326 template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00327 const SettingResolver link ( element );
00328
00329 assert_type ( link.result, Setting::TypeList );
00330
00331 int len = link.result.getLength();
00332 array_to_load.set_length ( len );
00333 if ( len == 0 ) return;
00334
00335 for ( int i = 0; i < len; i++ )
00336 from_setting ( array_to_load ( i ), link.result[i] );
00337 }
00338
00343 template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00344 std::string msg = "from_setting is not implemented for type ";
00345 msg += typeid(T).name();
00346 throw UIException ( msg, element );
00347 }
00348
00349
00350 protected:
00352 UI ( const string& class_name, const type_info * const class_type_info ) {
00353 MappedUI::add_class ( class_name, class_type_info, this );
00354 }
00355
00356 public:
00357
00359 enum SettingPresence { optional, compulsory } ;
00360
00364
00368 template<class T>
00369 static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00370 if ( !element.exists ( name ) ) {
00371 if ( settingPresence == optional )
00372 return shared_ptr<T>();
00373 else
00374 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00375 }
00376
00377 shared_ptr<T> instance;
00378 from_setting<T> ( instance, to_child_setting ( element, name ) );
00379 return instance;
00380 }
00381
00385 template<class T>
00386 static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00387 if ( element.getLength() <= index ) {
00388 if ( settingPresence == optional )
00389 return shared_ptr<T>();
00390 else {
00391 stringstream stream;
00392 stream << index;
00393 throw UIException ( "the compulsory Setting with the index " + stream.str() + " is missing", element );
00394 }
00395 }
00396
00397 shared_ptr<T> instance;
00398 from_setting<T> ( instance, to_child_setting ( element, index ) );
00399 return instance;
00400 }
00401
00403
00407
00410 template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00411 if ( !element.exists ( name ) ) {
00412 if ( settingPresence == optional )
00413 return false;
00414 else
00415 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00416 }
00417
00418 from_setting ( instance, to_child_setting ( element, name ) );
00419 return true;
00420 }
00421
00424 template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00425 if ( element.getLength() <= index ) {
00426 if ( settingPresence == optional )
00427 return false;
00428 else {
00429 stringstream stream;
00430 stream << index;
00431 throw UIException ( "the compulsory Setting with the index " + stream.str() + " is missing", element );
00432 }
00433 }
00434
00435 from_setting ( instance, to_child_setting ( element, index ) );
00436 return true;
00437 }
00438
00440 template<class T> static bool get ( T &instance, const Setting &element ) {
00441 from_setting ( instance, element );
00442 return true;
00443 }
00445
00449
00452 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00453 if ( !element.exists ( name ) )
00454 return false;
00455
00456 from_setting ( array_to_load, to_child_setting ( element, name ) );
00457 return true;
00458 }
00459
00462 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00463 if ( element.getLength() <= index )
00464 return false;
00465
00466 from_setting ( array_to_load, to_child_setting ( element, index ) );
00467 return true;
00468 }
00469
00471 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00472 from_setting ( array_to_load, element );
00473 return true;
00474 }
00476
00481
00483 template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00484 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00485 : element.add ( name, Setting::TypeGroup );
00486
00487 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00488
00489
00490 Setting &type = set.add ( "class", Setting::TypeString );
00491 type = class_name;
00492
00493 try {
00494 instance->to_setting ( set );
00495 } catch ( SettingException sttng_xcptn ) {
00496 string msg = "the method ";
00497 msg += class_name;
00498 msg += ".to_setting(Setting&) has thrown a SettingException. Try to correct this method.";
00499 throw UIException(msg, sttng_xcptn.getPath());
00500 }
00501 }
00502
00503 template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00504 save<T> ( instance.get(), element, name );
00505 }
00506
00508 template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00509 assert_type ( element, Setting::TypeGroup );
00510 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00511 : element.add ( name, Setting::TypeList );
00512 for ( int i = 0; i < array_to_save.length(); i++ )
00513 save ( array_to_save ( i ), list );
00514 }
00515
00517 static void save ( const mat &matrix, Setting &element, const string &name = "" );
00518
00520 static void save ( const ivec &vec, Setting &element, const string &name = "" );
00521
00523 static void save ( const vec &vector, Setting &element, const string &name = "" );
00524
00526 static void save ( const string &str, Setting &element, const string &name = "" );
00527
00529 static void save ( const int &integer, Setting &element, const string &name = "" );
00530
00532 static void save ( const double &real, Setting &element, const string &name = "" );
00534
00535 };
00536
00537
00540 template<typename T> class ParticularUI : private UI {
00541 public:
00543 ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00544
00546 root* new_instance() const {
00547 return new T();
00548 }
00549 };
00550
00551 }
00552
00562 #ifndef BDMLIB
00563 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00564 #else
00565 #define UIREGISTER(class_name)
00566 #endif
00567
00569 #define QUOTEME(x) #x
00570
00579 #ifndef BDMLIB
00580 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00581 #else
00582 #define UIREGISTER2(class_name,temp_name)
00583 #endif
00584
00585 #endif // #ifndef USER_INFO_H