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

Revision 394, 13.9 kB (checked in by mido, 15 years ago)

1) UI_File renamed to UIFile
2) part UI's documentation
3) stat/mixtures.h renamed to stat/emix.h and related changes applied

  • Property svn:eol-style set to native
Line 
1#ifndef USER_INFO_H
2#define USER_INFO_H
3
4#include <stdio.h>
5#include <string>
6#include <typeinfo>
7#include <map>
8
9#include "libconfig/libconfig.h++"
10#include "../bdmroot.h"
11#include "itpp/itbase.h"
12
13#include <stdexcept>
14
15using std::string;
16using namespace std;
17using namespace libconfig;
18
19namespace bdm
20{
21       
22/*!
23  \def UIREGISTER(class_name)
24  Macro for registration of class into map of UserInfos -- registered class is scriptable
25
26  TODO napsat i to, ze UIREG musi byt v hacku..
27*/
28#ifndef BDMLIB
29#define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::ui = ParticularUI<class_name>(#class_name)
30#else
31#define UIREGISTER(class_name)
32#endif
33
34//!  macro assertting that the setting SET is of the SettingType TYPE
35#define ASSERT_UITYPE(SET,TYPE) it_assert_debug(SET.getType()==Setting::TYPE, string("Wrong setting type, see input path \"")+string(SET.getPath())+string("\""))
36
37//! exception used in UI::build if it fails it can be caught and handled - see merger_mex.h
38class UIbuildException : public std::invalid_argument {
39        public:
40                UIbuildException() : std::invalid_argument("class name") { }
41};
42
43/*!
44@brief This class serves to load and/or save user-infos into/from
45configuration files stored on a hard-disk.
46
47Firstly, save some user-infos into the new UIFile instance. Then,
48call the save method with a filename as its only argument:
49
50\code
51        CAudi audi;
52        UIFile file;
53        UI::save( audi, file, "TT");
54        file.save("cars.cfg");
55\endcode
56
57In the other way round, when loading object from a configuration file,
58the appropriate code looks like this:
59
60\code
61        UIFile file("cars.cfg");
62        CAudi *audi = UI::build<CAudi>(file,"TT");
63\endcode
64*/
65class UIFile : public Config
66{
67public:
68        //! create empty file instance prepared to store Settings
69        UIFile();
70
71        //! creates instance and fills it from the configuration file file_name
72        UIFile( const string &file_name );
73
74        //! save all the stored Settings into the configuration file file_name
75        void save(const string &file_name);
76
77        //! this operator allows the ability of substituting Setting parameter by UIFile instance
78        operator Setting&();
79};
80
81
82
83/*!
84@brief UI is an abstract class and it is intended for internal purposes only
85
86This class exists mainly to allow pointers to its templated descendant ParticularUI<T>. Next,
87it collects all the auxiliary functions useful to prepare some concret user-infos, see static
88methods 'build', 'get' and 'save'.
89*/
90class UI
91{
92private:
93        //! Atatic class encalupsating two maps, one mapping names to UI instances and the other mapping type_infos to class names
94        //!
95        //! The key property of this class is that it initilaize the internal map immediately
96        //! when it is used for a first time. Therefore, we do not have to care about the
97        //! order of calls to UIREGISTER macro, which operates with both these mappings.
98        class MappedUI
99        {
100        private:
101                //! Type definition of mapping which transforms class names to the related UI instances
102                typedef map< const string, const UI* const > StringToUIMap;
103
104                //! Type definition of mapping which transforms RTTI type_infos to the related class names
105                typedef map< const type_info * const, const string > TypeInfoToStringMap;
106
107                //! immediately initialized instance of type StringToUIMap
108                static StringToUIMap& mapped_strings();
109
110                //! immediately initialized instance of type TypeInfoToStringMap
111                static TypeInfoToStringMap& mapped_type_infos();
112
113                //! method for reporting a error when an attempt to operate with an unregistered class occures
114                static void unregistered_class_error( const string &unregistered_class_name );
115
116        public:
117                //! add a pair key-userinfo into the internal map
118                static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui );
119
120                //! search for an userinfo related to the passed class name within the internal map
121                static const UI& retrieve_ui( const string &class_name );
122
123                //! search for an class name related to the passed type_info within the internal map
124                static const string& retrieve_class_name( const type_info* const class_type_info );
125        };
126
127        //! Method assembling a typeless instance, it is implemented in descendant class ParticularUI<T>
128        virtual root* new_instance() const = 0;
129       
130        //! Method switching from the \a element to its child Setting according the passed \a index, it also does all the necessary error-checking
131        static const Setting& to_child_setting( const Setting &element, const int index );
132
133        //! Method switching from the \a element to its child Setting according the passed \a name, it also does all the necessary error-checking
134        static const Setting& to_child_setting( const Setting &element, const string &name );
135
136        //! This methods converts a Setting into a matrix
137        static void from_setting( mat& matrix, const Setting &element );       
138        //! This methods converts a Setting into an integer vector
139        static void from_setting( ivec &vector, const Setting &element );
140        //! This methods converts a Setting into a string
141        static void from_setting( string &str, const Setting &element );
142        //! This methods converts a Setting into a real vector
143        static void from_setting( vec &vector, const Setting &element );
144        //! This methods converts a Setting into a integer scalar
145        static void from_setting( int &integer, const Setting &element );
146        //! This methods converts a Setting into a real scalar
147        static void from_setting( double &real, const Setting &element );
148        //! This methods converts a Setting into a class T descendant
149        template<class T> static void from_setting( T* &instance, const Setting &element )
150        {                       
151                const SettingResolver link( element );
152
153                ASSERT_UITYPE(link.result,TypeGroup);
154
155                // we get a velue stored in the "class" attribute
156                string class_name;
157                if( !link.result.lookupValue( "class", class_name ) )
158                        ui_error( "the obligatory ""class"" identifier is missing", link.result );
159       
160                // then we find a user-info related to this type
161                const UI& related_UI = MappedUI::retrieve_ui( class_name );
162               
163                root* typeless_instance = related_UI.new_instance();
164
165                instance = NULL;
166                //try catch does not work!!!
167                instance = dynamic_cast<T*>(typeless_instance);
168                if (!instance){
169                        throw UIbuildException();
170                }
171//              catch(...)
172//              {
173                        // TODO pouzit ui_error?
174//                      it_error ( "UI error: class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build function with a different type parameter." );
175//              }
176//             
177                try
178                {
179                        instance->from_setting( link.result );
180                }
181                catch(SettingException xcptn)
182                {
183                        // TODO pouzit ui_error?
184                        it_error ( "UI error: the method " + class_name + ".from_setting(Setting&) has thrown an exception when parsing the setting " + xcptn.getPath() + ". Try to correct this method." );
185                }
186        }       
187
188        //! This methods converts a Setting into a new templated array ,
189        // TODO efektivne jen pro vect, mat a string, pro dalsi je nutne pridat from_setting metodu.. ale to asi necceme
190        template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element )
191        {
192                const SettingResolver link( element );
193
194                ASSERT_UITYPE(link.result,TypeList);
195
196                int len = link.result.getLength();
197                array_to_load.set_length( len );
198                if( len == 0 ) return;
199               
200                for( int i=0; i < len; i++ ) 
201                        from_setting( array_to_load(i), link.result[i] ); 
202        }
203
204        //! Method for reporting user-info errors related to some concrete Setting
205        static void ui_error( string message, const Setting &element );
206
207protected:
208        //! Default constructor for internal use only, see \sa ParticularUI<T>
209        UI( const string& class_name, const type_info * const class_type_info ) 
210        {       
211                MappedUI::add_class( class_name, class_type_info, this );
212        }
213
214public: 
215
216        /*!
217        @brief This class serves to expand links used in configuration file.
218
219        TODO - napsat co dela, a hlavne proc je to takhle implementovany.. otevreny soubor!
220
221        ABSOLUTE PATH..
222
223        Firstly, save some user-infos into the new UIFile instance. Then,
224        call the save method with a filename as its only argument:
225
226        \code
227                CAudi audi;
228                UIFile file;
229                UI::save( audi, file, "TT");
230                file.save("cars.cfg");
231        \endcode
232
233        */
234        class SettingResolver   
235        {
236        private:
237                //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL
238                UIFile *file;
239
240                //! This method initialize result reference, i.e., it executes the main code of SettingResolver class
241                //!
242                //! This code could be also located directly in constructor. The only reason why we made this
243                //! method is the keyword 'const' within the declaration of result reference (TODO funguje odkaz?). Such a reference
244                //! have to be intialized before any other constructor command, exactly in the way it is implemented now.
245                const Setting &initialize_reference( UIFile* &file, const Setting &potential_link);
246
247        public:
248                //! Reference to a resolved link or to the original Setting in the case it does not contain a link
249                const Setting &result;
250
251                //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference result is prepared for use.
252                SettingResolver( const Setting &potential_link );
253               
254                //! An opened UIFile file is closed here if necessary.
255                ~SettingResolver();             
256        };
257
258        //TODO
259        //! \name Initialization of bdm::root descendant classes according the values stored in a Setting variable
260        //!@{
261        //! Return value is by the second argument since it type checking via \c dynamic_cast.
262        template<class T> static T* build( const Setting &element, const int index )
263        {
264                T* instance;
265                from_setting<T>( instance, to_child_setting( element, index ) );
266                return instance;
267        }
268        //! VS: addition for root elements
269        template<class T> static T* build( const Setting &element )
270        {
271                T* instance;
272                from_setting<T>( instance,  element );
273                return instance;
274        }
275
276        template<class T> static T* build( const Setting &element, const string &name )
277        {                       
278                T* instance;
279                from_setting<T>( instance, to_child_setting( element, name ) );
280                return instance;
281        }
282        //!@}
283
284        //! \name Initialization of structures according the values stored in a Setting variable - TODO VYCET?!
285        //!@{
286        //! This methods tries to build a new double matrix
287        template<class T> static void get( T &instance, const Setting &element, const string &name )
288        {
289                from_setting( instance, to_child_setting( element, name ) );
290        }
291
292        //! This methods tries to build a new double matrix
293        template<class T> static void get( T &instance, const Setting &element, const int index )
294        {
295                from_setting( instance, to_child_setting( element, index ) );
296        }
297
298        //! This methods tries to build a new double matrix
299        template<class T> static void get( T &instance, const Setting &element  )
300        {
301                from_setting( instance, element );
302        }
303
304        //! This methods tries to build a new double matrix
305        template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name )
306        {
307                from_setting( array_to_load, to_child_setting( element, name ) );
308        }
309
310        //! This methods tries to build a new double matrix
311        template<class T> static void get( Array<T> &array_to_load, const Setting &element, const int index )
312        {
313                from_setting( array_to_load, to_child_setting( element, index ) );
314        }
315
316        //! This methods tries to build a new double matrix
317        template<class T> static void get( Array<T> &array_to_load, const Setting &element  )
318        {
319                from_setting( array_to_load, element );
320        }
321        //!@}
322
323        template< class T> static void save( const T * const instance, Setting &element, const string &name = "")
324        {
325                Setting &set = (name == "") ? element.add( Setting::TypeGroup )                                                 
326                                                                         : element.add( name, Setting::TypeGroup );             
327
328                const string &class_name = MappedUI::retrieve_class_name( &typeid(*instance) );
329                       
330                // add attribute "class"
331                Setting &type = set.add( "class", Setting::TypeString );
332                type = class_name;
333
334                try
335                {
336                        instance->to_setting( set );
337                }
338                catch(SettingException xcptn)
339                {
340                        it_error ( "UI error: the method " + class_name + ".to_setting(Setting&) has thrown an exception when filling the setting " + xcptn.getPath() + ". Try to correct this method." );
341                }       
342        }
343
344        //! This methods tries to save a double vec
345        template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" )
346        {
347                ASSERT_UITYPE(element,TypeGroup);
348                Setting &list = (name == "") ? element.add( Setting::TypeList )                                                 
349                                                                         : element.add( name, Setting::TypeList );             
350                for( int i=0; i<array_to_save.length(); i++ ) 
351                        save( array_to_save(i), list );
352        }
353
354
355        //! This methods tries to save a double matrix
356        static void save( const mat &matrix, Setting &element, const string &name = "" );
357
358        //! This methods tries to save a double vec
359        static void save( const ivec &vec, Setting &element, const string &name = "" );
360       
361        static void save( const vec &vector, Setting &element, const string &name = "" );
362        //! This methods tries to save a double vec
363        static void save( const string &str, Setting &element, const string &name = "" );
364
365        static void save( const int &integer, Setting &element, const string &name = "" );
366
367        static void save( const double &real, Setting &element, const string &name = "" );     
368
369};
370
371
372/*!
373@brief The main userinfo template class. You should derive this class whenever you need
374a new userinfo of a class which is compound from smaller elements (all having its
375own userinfo class prepared).
376*/
377template<typename T> class ParticularUI : private UI
378{
379        public:
380
381        //! default constructor, which is intentionally declared as private
382        ParticularUI<T>( const string &class_name) : UI( class_name, &typeid(T) ) 
383        {       cout << class_name << endl;
384        };
385
386        //! the only instance of this class (each type T has its own instance)
387        //! which is used as a factory for processing related UI
388        static const ParticularUI<T>& ui;       
389
390        root* new_instance() const
391        {
392                return new T();
393        }
394};
395
396
397
398
399}
400
401/*! Recursive build of objects defined in the same file
402
403\code
404{type="internal";
405path="system.profile.[0]";    // Path from the root
406};
407\endcode
408 */
409
410
411
412/*! Recursive build of objects defined in external file
413
414\code
415{type="external";
416filename="my_file.cfg";       // name of file from which to read
417path="system.profile.[0]";    // Path in the external file
418};
419\endcode
420/
421
422*/
423
424#endif // #ifndef USER_INFO_H
Note: See TracBrowser for help on using the browser.