root/library/bdm/base/user_info.h @ 942

Revision 942, 28.2 kB (checked in by mido, 14 years ago)

the functionality of user info was improved, it supports an initialization of root descendant via UI::get directly, however it is save only for static attributes, for dynamically allocated attributes UI::build should be called to handle with intahrence issues

  • Property svn:eol-style set to native
Line 
1/*!
2  \file
3  \brief UI (user info) class for loading/saving objects from/to configuration files.
4  It is designed with use of libconfig C/C++ Configuration File Library
5  \ref ui
6  \author Vaclav Smidl.
7
8  -----------------------------------
9  BDM++ - C++ library for Bayesian Decision Making under Uncertainty
10
11  Using IT++ for numerical operations
12  -----------------------------------
13*/
14
15#ifndef USER_INFO_H
16#define USER_INFO_H
17
18#include <stdio.h>
19#include <string>
20#include <typeinfo>
21#include <map>
22#include <stdexcept>
23
24#include "../bdmroot.h"
25#include "../shared_ptr.h"
26#include "itpp/itbase.h"
27
28using std::string;
29using namespace std;
30using namespace libconfig;
31
32namespace bdm {
33
34//! Generic exception for reporting configuration errors
35//!
36//!  \ref ui
37class UIException : public std::exception {
38private:
39        //! Error message
40        const string message;
41
42public:
43        /*!
44          \brief The constructor
45          \param message the reason for throwing the exception. Should be a complete English sentence (or a couple sentences), starting with "UIException: ".
46        */
47        UIException ( const string &message ) :
48                        message ( message ) {
49        }
50
51        //! Overriden method for reporting the error message
52        virtual const char* what() const throw() {
53                return message.c_str();
54        }
55
56        ~UIException() throw() {};
57
58protected:
59        /*!
60          Formats error messages for derived classes, which use a
61          Setting path in addition to the message.
62        */
63        static string format_message ( const string &reason, const string &path );
64};
65
66//! Exception for reporting configuration errors related to some concrete Setting path
67//!
68//!  \ref ui
69class UISettingException : public UIException {
70public:
71        //! Use this constructor when you can pass the problematical Setting as a parameter
72        UISettingException ( const string &message, const Setting &element ) :
73                        UIException ( format_message ( message, string ( element.getPath() ) ) ) {
74        }
75
76        //! This constructor is for other occasions, when only path of problematical Setting is known
77        UISettingException ( const string &message, const string &path ) :
78                        UIException ( format_message ( message, path ) ) {
79        }
80
81        ~UISettingException() throw() {};
82};
83
84//! Exception for reporting configuration errors in the "class" attribute
85//!
86//!  \ref ui
87class UIClassException : public UIException {
88public:
89        //! Use this constructor when you can pass the problematical Setting as a parameter
90        UIClassException ( const string &message, const Setting &element ) :
91                        UIException ( format_message ( message, string ( element.getPath() ) ) ) {
92        }
93
94        //! This constructor is for other occasions, when only path of problematical Setting is known
95        UIClassException ( const string &message, const string &path ) :
96                        UIException ( format_message ( message, path ) ) {
97        }
98
99        ~UIClassException() throw() {};
100};
101
102/*!
103@brief This class serves to load and/or save user-infos into/from
104configuration files stored on a hard-disk.
105
106Firstly, save some user-infos into the new UIFile instance. Then,
107call the save method with a filename as its only argument:
108
109\code
110        CAudi audi;
111        UIFile file;
112        UI::save( audi, file, "TT");
113        file.save("cars.cfg");
114\endcode
115
116In the other way round, when loading object from a configuration file,
117the appropriate code looks like this:
118
119\code
120        UIFile file("cars.cfg");
121        CAudi *audi = UI::build<CAudi>(file,"TT");
122\endcode
123
124\ref ui
125*/
126class UIFile : public Config {
127public:
128        //! Create empty file instance prepared to store Settings
129        UIFile();
130
131        //! Creates instance and fills it from the configuration file file_name
132        UIFile ( const string &file_name );
133
134        //! Save all the stored Settings into the configuration file file_name
135        void save ( const string &file_name );
136
137        //! This operator allows the ability of substituting Setting parameter by UIFile instance
138        operator Setting&();
139};
140
141/*!
142@brief This class serves to expand links used within configuration files.
143
144Value of any type but string can be linked to some other value of the same type
145defined elsewhere in the current configuration file or even in some different
146configuration file.
147
148Link have three parts, \<name\> : \<path\> \<\@filename\>. Field \<name\> contains the
149name of the new setting, \<path\> is the relative path to the referenced setting, which
150has to be taken from the %root Setting element. The last part \<\@filename\> is optional,
151it contains filename in the case the link should refer to a variable stored in a different
152file. From the previous part \<path\>, it has to be separated by '@'.
153
154\code
155    ...
156        jardovo :
157        {
158          class = "Car";
159          year = 1992;
160          manufacturer = "liaz";
161          kilometers = 1555000;
162        };
163        ondrejovo :
164        {
165          class = "Bike";
166          year = 1996;
167          manufacturer = "author";
168          electricLights = true;
169          matr = ( 2, 2, [ 1.0, 0.0, 0.0, 1.0 ] );
170        };
171
172        #this is the example of local link to another mean of transport
173        elisky = "jardovo";
174
175        ...
176
177        # And this link is external link pointing to the file "other_cars.cfg" stored in the
178        # same directory. In that file, it refers to the local Setting "magic_cars.skubankovo".
179        kati = "magic_cars.skubankovo@other_cars.cfg";
180
181    ...
182\endcode
183
184When you want to expand a possible linked setting "element" within your code, it has to be treated this way:
185
186\code
187        ...
188
189        const SettingResolver link( element );
190
191        ...
192
193        int len = link.result.getLength();
194
195        ...
196\endcode
197
198The whole point is that a resolved link (class member #result, i.e., "link.result" in the previous example) could point
199into a different configuration file. In that case there has to be an UIFile instance managing reading from this
200file. As the libconfig::Config deletes all its Settings when dealocated, UIFile must not be dealocated until all
201the necessary operation on the linked Setting are finished (otherwise, the link #result would be invalid just after
202the UIFile dealocation). And that is exactly the mechanism implemented within SettingResolver class. It assures,
203that the #result Setting reference is valid within the scope of SettingResolver instance.
204
205\ref ui
206 */
207class SettingResolver : root {
208private:
209        //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL
210        UIFile *file;
211
212        //! This method initialize #result reference, i.e., it executes the main code of SettingResolver class
213        //!
214        //! This code could be also located directly in constructor. The only reason why we made this
215        //! method is the keyword 'const' within the declaration of #result reference . Such a reference
216        //! have to be intialized before any other constructor command, exactly in the way it is implemented now.
217        const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
218
219public:
220        //! Reference to a resolved link or to the original Setting in the case it does not contain a link
221        const Setting &result;
222
223        //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference #result is prepared for use.
224        SettingResolver ( const Setting &potential_link );
225
226        //! An opened UIFile file is closed here if necessary.
227        ~SettingResolver();
228};
229
230
231//! This class stores the details which will be logged to a logger
232//!
233//! This is only the first part of the whole declaration, which has to be however separated into
234//! two different classes for allowing the compilation of source code. For more details
235//! see logger::add_setting(...) method and mainly log_level_template<T>::template<class U> void store( const enum T::log_level_enums log_level_enum, const U data ) const
236//! method. For the reason the second one is templated, it was necessary to declare this whole class.
237template<class T> class log_level_base : public root {
238private:
239        //! this is necessary to allow logger to set ids vector appropriately and also to set registered_logger
240        friend class logger; 
241
242protected:
243        //! boolean flags related indicating which details will be logged to a logger
244        bitset<32> values;
245       
246        //! vector of vectors of log IDs - one element for each entry and multiple entries can be stored on the position of one enum
247        Vec<ivec> ids;
248
249        //! internal pointer to the logger to which this log_level is registered
250        //!
251        //! it is set to NULL at the beginning
252        logger * registered_logger;
253
254public:
255
256        //! default constructor
257        log_level_base( ) {
258                registered_logger = NULL;
259                int len = names().length();
260                ids.set_size( len );
261                for( int i = 0; i<len; i++ )
262                {
263                        ids(i).set_size ( 1 );
264                        ids(i) = -1;
265                }
266        }
267
268        //! a general utility transforming a comma-separated sequence of strings into an instance of Array<strings>
269        static Array<string> string2Array( const string &input )
270        {
271                string result = input;
272                string::size_type loc;
273                while( loc = result.find( ',' ), loc != string::npos )
274                        result[loc] = ' ';
275                return Array<string>("{ " + result + " }" );
276        }
277
278
279
280        //! Set log_levels according to the Setting element
281        void from_setting ( const Setting &element )
282        {
283                string raw_log_level;
284                UI::get( raw_log_level, element );
285                Array<string> loaded_log_level = log_level_base::string2Array( raw_log_level );
286       
287                values.reset();
288
289                for( int i = 0; i < loaded_log_level.length(); i++ )
290                        for( int j = 0; j < names().length(); j++ ){
291                                if( loaded_log_level(i) == names()(j)  ) 
292                                {
293                                        values[j] = true;
294                                        break;
295                                } 
296                        }
297        }
298
299        //! Store log_levels into the Setting element
300        void to_setting ( Setting &element ) const 
301        {
302                // HERE WE WANT NOT TO DELETE PREVIOUS DATA STORED BY OTHER LOG_LEVELS, SEE SPECIAL IMPLEMENTATION OF UI::GET(...) FOR THIS CLASS
303                string string_to_write =  ( const char* ) element;
304
305                for( unsigned int i = 0; i < values.size(); i++ )
306                        if( values[i] ) 
307                        {
308                                if( string_to_write.length() > 0 )
309                                        string_to_write = string_to_write + ',';
310                                string_to_write = string_to_write + names()(i);
311                        }
312                       
313                element = string_to_write;
314        }
315
316        //! this method adds new id to its proper position and return the name of this position
317        string store_id_and_give_name( enum T::log_level_enums const log_level_enum,  int enum_subindex, int id ) {
318                if( ids(log_level_enum).length() <= enum_subindex )
319                        ids(log_level_enum).set_size( enum_subindex+1, true );
320                ids(log_level_enum)(enum_subindex) = id; 
321
322                // here we remove a "log" prefix from name, i.e., for instance it transforms "logevidence" to "evidence"
323                ostringstream stream;
324                string name_with_prefix = names()(log_level_enum);
325                string possible_log_prefix = name_with_prefix.substr(0,3);
326                if( possible_log_prefix == "log" )
327                        stream << name_with_prefix.substr(3,name_with_prefix.length()-3);
328                else 
329                        stream << name_with_prefix;
330
331                // add number to name only in the case there are more registered vectors with the same log_level_enum
332                if( ids(log_level_enum).length() > 1 )
333                        stream << "*" << enum_subindex;
334               
335                return stream.str();
336        }
337
338        //! string equivalents of the used enumerations which are filled with a help of #LOG_LEVEL macro within class T
339        const Array<string> &names() const
340        {
341                return T::log_level_names();
342        }
343
344        //! read only operator for testing individual fields of log_level
345        //!
346        //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe
347        bool operator [] (const enum T::log_level_enums &log_level_enum ) const
348        {
349                return values[log_level_enum];
350        }
351
352        //! operator for setting an individual field of log_level
353        //!
354        //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe
355        bitset<32>::reference operator [] (const enum T::log_level_enums &log_level_enum )
356        {
357                return values[log_level_enum];
358        }
359};
360//UIREGISTER IS FORBIDDEN FOR THIS CLASS,  AS IT SHOULD BE LOADED ONLY THROUGH THE SPECIALIZED UI::GET(...) METHOD
361
362/*!
363@brief UI is an abstract class which collects all the auxiliary functions useful to prepare some concrete
364user-infos.
365
366See static methods 'build', 'get' and 'save'. Writing user-infos with these methods is rather simple. The
367rest of this class is intended for internal purposes only. Its meaning is to allow pointers to its templated
368descendant ParticularUI<T>.
369
370\ref ui
371*/
372class UI {
373private:
374        //! Class with state shared across all its instances ("monostate"), encapsulating two maps, one mapping names to UI instances and the other mapping type_infos to class names
375        //!
376        //! The key property of this class is that it initializes the internal maps on global init,
377        //! before the instance is used for a first time. Therefore, we do not have to care about initialization
378        //! during a call of UIREGISTER macro operating with both these mappings.
379        class MappedUI {
380        private:
381                //! Type definition of mapping which transforms class names to the related UI instances
382                typedef map< const string, const UI* const > StringToUIMap;
383
384                //! Type definition of mapping which transforms RTTI type_infos to the related class names
385                typedef map< const type_info * const, const string > TypeInfoToStringMap;
386
387                //! Immediately initialized instance of type StringToUIMap
388                static StringToUIMap& mapped_strings();
389
390                //! Immediately initialized instance of type TypeInfoToStringMap
391                static TypeInfoToStringMap& mapped_type_infos();
392
393                //! Method for reporting a error when an attempt to operate with an unregistered class occures
394                static void unregistered_class_error ( const string &unregistered_class_name );
395
396        public:
397                //! Add a pair key-userinfo into the internal map
398                static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
399
400                //! Search for an userinfo related to the passed class name within the internal map
401                static const UI& retrieve_ui ( const string &class_name );
402
403                //! Search for an class name related to the passed type_info within the internal map
404                static const string& retrieve_class_name ( const type_info* const class_type_info );
405        };
406
407        //! Function assertting that the setting element is of the SettingType type
408        static void assert_type ( const Setting &element, Setting::Type type );
409
410        /*!
411          \brief Method constructing a configured instance
412
413          The returned pointer must be allocated using operator new
414          (it's deleted at the end of its life cycle). The method is
415          implemented in descendant class ParticularUI<T>, which knows
416          the correct type T.
417        */
418        virtual root* new_instance() const = 0;
419
420        //! Method switching from the \a element to its child Setting according the passed \a index, it also does all the necessary error-checking
421        static const Setting& to_child_setting ( const Setting &element, const int index );
422
423        //! Method switching from the \a element to its child Setting according the passed \a name, it also does all the necessary error-checking
424        static const Setting& to_child_setting ( const Setting &element, const string &name );
425
426        //! A shortcut for calling instance.from_setting( set ); with some error catches added
427        static void call_from_setting( root &instance, const Setting &set, string class_name = "unknown");
428
429        //! A shortcut for calling instance.to_setting( set ); with some error catches added
430        static void call_to_setting( const root &instance, Setting &set, string class_name = "unknown" );
431
432        //! This method converts a Setting into a matrix
433        static void from_setting ( mat& matrix, const Setting &element );
434        //! This method converts a Setting into an integer vector
435        static void from_setting ( ivec &vector, const Setting &element );
436        //! This method converts a Setting into a string
437        static void from_setting ( string &str, const Setting &element );
438        //! This method converts a Setting into a real vector
439        static void from_setting ( vec &vector, const Setting &element );
440        //! This method converts a Setting into a integer scalar
441        static void from_setting ( int &integer, const Setting &element );
442        //! This method converts a Setting into a real scalar   
443        static void from_setting ( double &real, const Setting &element );
444        //! This method converts a Setting into a class T descendant
445        static void from_setting ( root &instance, const Setting &element );
446        //! This method converts a Setting into a class T descendant
447        template<class T> static void from_setting ( T* &instance, const Setting &element ) {
448                const SettingResolver link ( element );
449                assert_type( link.result, Setting::TypeGroup );
450
451                // we get a value stored in the "class" attribute
452                string class_name;
453                if ( !link.result.lookupValue ( "class", class_name ) )
454                        throw UIClassException ( "UIException: the obligatory \"class\" identifier is missing.", link.result );
455
456                // then we find a user-info related to this type
457                const UI& related_UI = MappedUI::retrieve_ui ( class_name );
458
459                root *typeless_instance = related_UI.new_instance();
460                bdm_assert ( typeless_instance, "UI::new_instance failed" );
461
462                instance = dynamic_cast<T*> ( typeless_instance );
463                if ( !instance ) {
464                        delete typeless_instance;
465                        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 );
466                }
467
468                try {
469                        call_from_setting( *instance, link.result, class_name );
470                } catch ( ... ) {
471                        delete instance;
472                        instance = 0;
473                        throw;
474                }
475        }
476
477        //! This method converts a Setting into a descendant of class
478        //! T, wrapped in an instance of bdm::shared_ptr<T> .
479        template<class T> static void from_setting ( bdm::shared_ptr<T> &instance, const Setting &element ) {
480                T *tmp_inst = 0;
481                from_setting ( tmp_inst, element );
482                bdm_assert ( tmp_inst, "UI::from_setting failed" );
483                instance = tmp_inst;
484        }
485
486        //! This methods converts a Setting into a new templated array of type Array<T>
487        template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
488                const SettingResolver link ( element );
489
490                assert_type ( link.result, Setting::TypeList );
491
492                int len = link.result.getLength();
493                array_to_load.set_length ( len );
494                if ( len == 0 ) return;
495
496                for ( int i = 0; i < len; i++ )
497                        from_setting ( array_to_load ( i ), link.result[i] );
498        }
499
500protected:
501        //! Constructor for internal use only, see \sa ParticularUI<T>
502        UI ( const string& class_name, const type_info * const class_type_info ) {
503                MappedUI::add_class ( class_name, class_type_info, this );
504        }
505
506public:
507
508        //! Enum type used to determine whether the data for concrete Settingis is compulsory or optional
509        enum SettingPresence { optional, compulsory } ;
510
511        //! \name Initialization of classes
512        //!@{
513        //! The type T has to be a #bdm::root descendant class
514
515        //! The new instance of type T* is constructed and initialized with values stored in the Setting element[name]
516        //!
517        //! If there does not exist any sub-element named #name and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found).
518        template<class T>
519        static bdm::shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
520                if ( !element.exists ( name ) ) {
521                        if ( settingPresence == optional )
522                                return bdm::shared_ptr<T>();
523                        else
524                                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
525                }
526
527                bdm::shared_ptr<T> instance;
528                from_setting<T> ( instance, to_child_setting ( element, name ) );
529                return instance;
530        }
531
532        //! The new instance of type T* is constructed and initialized with values stored in the Setting element[index]
533        //!
534        //! If there does not exist  any sub-element indexed by #index, and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found).
535        template<class T>
536        static bdm::shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
537                if ( element.getLength() <= index ) {
538                        if ( settingPresence == optional )
539                                return bdm::shared_ptr<T>();
540                        else {
541                                stringstream stream;
542                                stream << index;
543                                throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
544                        }
545                }
546
547                bdm::shared_ptr<T> instance;
548                from_setting<T> ( instance, to_child_setting ( element, index ) );
549                return instance;
550        }
551
552//! The new instance of type T* is constructed and initialized with values stored in the given Setting
553//!
554//! Handy in mex files. Use with care.
555        template<class T>
556        static bdm::shared_ptr<T> build ( const Setting &element, SettingPresence settingPresence = optional ) {
557                bdm::shared_ptr<T> instance;
558                from_setting<T> ( instance,  element );
559                return instance;
560        }
561
562        //!@}
563
564        //! \name Initialization of structures
565        //!@{
566        //! The type T has to be int, double, string, vec, ivec or mat.
567
568        //! The existing instance of type T is initialized with values stored in the Setting element[name]
569        //! If there does not exist any sub-element named #name, this method returns false.
570        template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
571                if ( !element.exists ( name ) ) {
572                        if ( settingPresence == optional )
573                                return false;
574                        else
575                                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
576                }
577
578                from_setting ( instance, to_child_setting ( element, name ) );
579                return true;
580        }
581
582        //! The existing instance of type T is initialized with values stored in the Setting element[index]
583        //! If there does not exist any sub-element indexed by #index, this method returns false.
584        template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
585                if ( element.getLength() <= index ) {
586                        if ( settingPresence == optional )
587                                return false;
588                        else {
589                                stringstream stream;
590                                stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
591                                stream << index;
592                                throw UISettingException ( stream.str(), element );
593                        }
594                }
595
596                from_setting ( instance, to_child_setting ( element, index ) );
597                return true;
598        }
599
600        //! The existing instance of type T is initialized with values stored in the Setting element directly
601        template<class T> static bool get ( T &instance, const Setting &element ) {
602                from_setting ( instance, element );
603                return true;
604        }
605        //!@}
606
607        //! \name Initialization of arrays Array<T>
608        //!@{
609        //! The type T has to be int, double, string, vec, ivec or mat, or pointer to any root descendant.
610
611        //! The existing array of type T is initialized with values stored in the Setting element[name]
612        //! If there is not any sub-element named #name, this method returns false.
613        template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
614                if ( !element.exists ( name ) ) {
615                        if ( settingPresence == optional )
616                                return false;
617                        else
618                                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
619                }
620
621                from_setting ( array_to_load, to_child_setting ( element, name ) );
622                return true;
623        }
624
625        //! The existing array of type T is initialized with values stored in the Setting element[index]
626        //! If there is not any sub-element indexed by #index, this method returns false.
627        template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
628                if ( element.getLength() <= index ) {
629                        if ( settingPresence == optional )
630                                return bdm::shared_ptr<T>();
631                        else {
632                                stringstream stream;
633                                stream << index;
634                                throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
635                        }
636                }
637
638                from_setting ( array_to_load, to_child_setting ( element, index ) );
639                return true;
640        }
641
642        //! The existing array of type T is initialized with values stored in the Setting element
643        template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
644                from_setting ( array_to_load, element );
645                return true;
646        }
647        //!@}
648
649        //! \name Serialization of objects and structures into a new Setting
650        //!@{
651        //! The new child Setting can be accessed either by its name - if some name is passed as a parameter -
652        //! or by its integer index. In that case, the new element is added at the very end of the current list of child Settings.
653
654        //! A root descendant is stored in the new child Setting appended to the passed element
655        static void save ( const root &instance, Setting &element, const string &name = "" );
656
657        //! A pointer to root descendant is stored in the new child Setting appended to the passed element
658        static void save ( const root * const instance, Setting &element, const string &name = "" );
659
660        //! A shared pointer to root descendant is stored in the new child Setting appended to the passed element
661        template< class T> static void save ( const bdm::shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
662                save( instance.get(), element, name );
663        }
664
665        //! An Array<T> instance is stored in the new child Setting appended to the passed element
666        template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
667                assert_type ( element, Setting::TypeGroup );
668                Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
669                                : element.add ( name, Setting::TypeList );
670                for ( int i = 0; i < array_to_save.length(); i++ )
671                        save ( array_to_save ( i ), list );
672        }
673
674        //! A matrix(of type mat) is stored in the new child Setting appended to the passed element
675        static void save ( const mat &matrix, Setting &element, const string &name = "" );
676
677        //! An integer vector (of type ivec) is stored in the new child Setting appended to the passed element
678        static void save ( const ivec &vec, Setting &element, const string &name = "" );
679
680        //! A double vector (of type vec) is stored in the new child Setting appended to the passed element
681        static void save ( const vec &vector, Setting &element, const string &name = "" );
682
683        //! A string is stored in the new child Setting appended to the passed element
684        static void save ( const string &str, Setting &element, const string &name = "" );
685
686        //! An integer is stored in the new child Setting appended to the passed element
687        static void save ( const int &integer, Setting &element, const string &name = "" );
688
689        //! A double is stored in the new child Setting appended to the passed element
690        static void save ( const double &real, Setting &element, const string &name = "" );
691
692    // The only difference from classical UserInfo approach here is the fact
693        // that the actual UI element related to log_level_base could possibly exists yet. In this case,
694        // we do not want to throw an exception as usually. We rather append current data into the existig element. This way, it is
695        // possible that more instances of log_level_base  (templated with different classes)
696        // can be stored in only one line in a configuration file
697        template<class T> static void save ( const log_level_base<T> &log_level, Setting &element ) {
698                assert_type ( element, Setting::TypeGroup );           
699                string name = "log_level";
700               
701                if( element.exists( name ) ) 
702                        assert_type ( element[name], Setting::TypeString );
703                else
704                        element.add ( name, Setting::TypeString ); 
705
706                log_level.to_setting( element[name] );
707        }
708
709        //!@}
710
711        //! for future use
712        virtual ~UI() {}
713};
714
715
716//! The only UI descendant class which is not intended for direct use. It should be accessed within the UIREGISTER macro only.
717//! \ref ui
718template<typename T> class ParticularUI : private UI {
719public:
720        //! Constructor used by the UIREGISTER macro.
721        ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
722
723        //! A method returning a brand new instance of class T, this method is the reason why there have to be a parameterless constructor in class T
724        root* new_instance() const {
725                return new T();
726        }
727};
728
729}
730
731/*!
732  \def UIREGISTER(class_name)
733  \brief Macro for registration of class into map of user-infos, registered class is scriptable using UI static methods
734
735  Argument \a class_name has to be a descendant of root class and also to have a default constructor.
736  This macro should be used in header file, immediately after a class declaration.
737
738  \ref ui
739*/
740#ifndef BDMLIB
741#define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
742#else
743#define UIREGISTER(class_name)
744#endif
745
746//! Instrumental macro for UIREGISTER2
747#define QUOTEME(x) #x
748
749/*!
750  \def UIREGISTER2(class_name,template_name)
751  \brief Variant of UIREGISTER for templated classes
752
753  Technical meann of registering UIREGISTER(class_name<template_name>).
754
755  \ref ui
756 */
757#ifndef BDMLIB
758#define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
759#else
760#define UIREGISTER2(class_name,temp_name)
761#endif
762
763#endif // #ifndef USER_INFO_H
Note: See TracBrowser for help on using the browser.