root/bdm/uibuilder.h @ 344

Revision 344, 17.4 kB (checked in by mido, 15 years ago)

funkcni verze noveho UI, zbyva jeste ucesat

  • Property svn:eol-style set to native
Line 
1#ifndef UIBUILD
2#define UIBUILD
3
4#include <itpp/itbase.h>
5#include "stat/libBM.h"
6#include "libconfig/libconfig.h++"
7
8#include <sstream>
9#include <iostream>
10#include <stdio.h>
11#include <string>
12#include <typeinfo>
13#include <map>
14#include <utility>
15#include <vector>
16#include <iostream>
17
18using std::string;
19using namespace std;
20using namespace libconfig;
21
22#define UIREGISTER(className) template<> ParticularUI<className>& ParticularUI<className>::ui = ParticularUI<className>(#className)
23
24#define ASSERT_UITYPE(S,Type) it_assert_debug(S.getType()==Setting::Type, string("Wrong setting type, see input path \"")+string(S.getPath())+string("\""))
25
26namespace bdm
27{
28
29/*!
30@brief This class serves to load and/or save DOMElements into/from files
31stored on a hard-disk.
32
33Firstly, you associate new RootElement instance with some filename during a time of its
34construtcion. Then, you save some object into the new RootElement instance,
35and save it into the file this way:
36\code
37        CAudi audi;
38        RootElement root("cars.xml");
39        UserInfo::Save( audi, root, "TT");
40        root.Save();
41\endcode
42
43In the other way round, when loading object from a XML file, the appropriate code looks like this:
44\code
45        RootElement root("cars.xml");
46        root.Load();
47        UserInfo::Build<T>(root,"TT");
48\endcode
49*/
50
51class UIFile : public Config
52{
53private:
54        const string fileName;
55
56public:
57        //! attach new RootElement instance to a file (typically with an XML extension)
58        UIFile( const string &file_name );
59
60        //! loads root element from a file
61        void Load();
62
63        //! Save UserInfo to the file (typically with an XML extension)
64        void Save ();
65
66        operator Setting&();
67};
68
69
70/*!
71@brief UserInfo is an abstract is for internal purposes only. Use CompoundUserInfo<T> or ParticularUI<T> instead.
72The raison d'etre of this class is to allow pointers to its templated descendants.
73
74Also, the main functions of the whole UserInfo library are included within this class, see
75static methods 'Build' and 'Save'.
76
77
78/*!\brief Builds computational object from a UserInfo structure
79
80Return value is a pointer to the created object (memory management issue?)
81/
82
83*/
84class UI
85{
86private:
87        //! just a typedef shortuct for a constant pointer to UI
88        typedef UI* pUI;
89
90        //! static class encalupsating map of names to related UserInfos
91        //!
92        //! The key property of this class is that it initilaized the internal map immediately
93        //! when it is used for a first time.
94        class StringToUIMap
95        {
96        private:
97                //! Type definition of mapping which transforms type names to the related user infors
98                typedef map< const string, pUI > MappedString2UI;
99
100                //! immediately initialized instance of type MappedString2UI
101                static MappedString2UI& privateMap();
102
103        public:
104                //! add a pair key-userinfo into the internal map
105                static void Add( const string &className, pUI pInstance );
106
107                //! search for an userinfo related to the passed key within the internal map
108                static pUI Retrieve( const string &className );
109        };
110                               
111        //! internal method assembling a typeless instance from components obtained by the 'AssemblyComponentsFromSetting()' method
112        virtual bdmroot* New() = 0;
113       
114        //! type name defined by user
115        const string className;
116
117protected:
118
119        //! default constructor
120        UI( const string& className ) : className ( className )
121        {       
122                StringToUIMap::Add( className, this );
123        }
124
125        //! Virtual destructor for future use;
126        virtual ~UI(){};
127
128private:
129
130        //! This methods tries to save an instance of type T (or some of its descendant types)
131        //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className
132        //! and connecti it to the passed Setting as a new child node.
133        template<class T> static void ToSetting( T &instance, Setting &element )
134        {
135                string &className = ParticularUI<T>::ui.className;
136                       
137                // add attribute "class"
138                Setting &type = root.add( "class", Setting::TypeString );
139                type = className;
140       
141                try
142                {
143                        // instance disassembling
144                        instance.ToSetting( root );
145                }
146                catch(SettingException xcptn)
147                {
148                        it_error ( "UI: the method " + className + ".ToSetting(Setting&) has thrown an exception when filling the setting " + xcptn.getPath() + ". Try to correct this method." );
149                }       
150        }
151
152        template<class T> static T* FromSetting( const Setting &element )
153        {                       
154                RevealIfLinked revealed_link( element );
155                const Setting &root = revealed_link.root();
156
157                ASSERT_UITYPE(root,TypeGroup);
158
159                // we get a velue stored in the "class" attribute
160                string className;
161                if( !root.lookupValue( "class", className ) )
162                {
163                        stringstream msg;
164                        msg << "UI: the class identifier is missing within the setting """ << root.getPath() <<  """. Check line " 
165                                << root.getSourceLine() << ".";
166                        it_error ( msg.str() );
167                }
168
169       
170                // and finally we find a UserInfo related to this type
171                pUI pRelatedUI = StringToUIMap::Retrieve( className );
172                if( !pRelatedUI)
173                        it_error ( "UI: class " + className + " was not properly registered. Use the macro ""UIREGISTER([class name]);"" within your code." );
174               
175                bdmroot* pTypelessInstance = pRelatedUI->New();
176
177                T* pInstance = NULL;
178                try
179                {
180                        pInstance = (T*) pTypelessInstance ;
181                }
182                catch(...)
183                {
184                        it_error ( "UI: class " + className + " is not a descendant of the desired output class. Try to call the UI::Build function with a different type parameter." );
185                }
186               
187                try
188                {
189                        // instance assembling
190                        pInstance->FromSetting( root );
191                }
192                catch(SettingException xcptn)
193                {
194                        string msg = "UI: the method " + className + ".FromSetting(Setting&) has thrown an exception when parsing the setting " + xcptn.getPath() + ". Try to correct this method.";
195                        it_error ( msg );
196                }
197                return pInstance;
198        }       
199
200
201
202public:
203
204        // vraci true, kdyz to byl platny link, jinak false.. v pripade chyby konci it_errorem..
205        // do elementu vrati setting prislusny po rozbaleni linku, jinak ponecha beze zmeny
206        class RevealIfLinked   
207        {
208        private:
209                UIFile *file;
210                const Setting * result;
211
212        public:
213
214                RevealIfLinked( const Setting &element )
215                {
216                        file = NULL;
217                        result = &element;
218
219                        if( element.getType() !=  Setting::TypeString )
220                                return;
221
222                        string link = (string) element;
223                        size_t aerobase = link.find('@');
224                        if( aerobase != string::npos )
225                        {
226                                string file_name = link.substr( aerobase + 1, link.length() );
227                                file = new UIFile( file_name );
228                                file->Load();
229                                // TODO OSETRIT FALSE, vyhodit iterr
230
231                                result = &(Setting&)(*file);
232
233                                link = link.substr( 0, aerobase );
234                        }
235                        else
236                                while ( !result->isRoot() ) 
237                                        result = &result->getParent();
238
239                        if( !result->exists( link ) )
240                        {
241                                // vyhodi chybu v pripade chyby
242                                printf("");
243                        }
244                        result = &(*result)[link];
245                        return;
246                }
247
248                ~RevealIfLinked()
249                {
250                        if( file ) delete file;
251                }
252
253               
254                const Setting& root()
255                {
256                        return *result;
257                }
258        };
259
260        private:
261                static const Setting* ToChildSetting( const Setting &element, const int index )
262                {
263                        if( !element.isAggregate())
264                                return NULL;
265
266                        if( element.getLength() <= index )
267                                return NULL;
268
269                        return &element[index];
270                }
271
272                static const Setting* ToChildSetting( const Setting &element, const string &name )
273                {
274                        if( !element.isGroup() )
275                                return NULL;
276
277                        if( !element.exists( name ) )
278                                return NULL;
279
280                        return &element[name];
281                }
282
283                static Setting& ToChildSetting( Setting &element, const int index )
284                {
285                        if( !element.isAggregate())
286                        {
287                                // TODO CO ZA TYP? ASI NE GROUP, COZ..
288                        }
289                        if( element.getLength() <= index )
290                        {
291                                stringstream msg;
292                                msg << "UI: there is not any child with index " << index << " in the parsed setting " 
293                                        << element.getPath() <<  ", check line " << element.getSourceLine() << ".";
294
295                                it_error ( msg.str() );
296                        }
297                        return element[index];
298                }
299
300                static Setting& ToChildSetting( Setting &element, const string &name )
301                {
302                        ASSERT_UITYPE(element,TypeGroup);
303                        if( !element.exists( name ) )
304                        {
305                                stringstream msg;
306                                msg << "UI: there is not any child named """ << name << """ in the parsed setting " 
307                                        << element.getPath() <<  ", check line " << element.getSourceLine() << ".";
308
309                                it_error ( msg.str() );
310                        }
311                        return element[name];
312                }
313
314        //! This methods tries to build a new double matrix
315        static bool FromSetting( mat& matrix, const Setting &root )
316        {
317                ASSERT_UITYPE(root,TypeList);
318                if( root.getLength() != 3 )
319                {
320                        stringstream msg;
321                        msg << "UI: the setting " << root.getPath() <<  """ supposed to represent a matrix element has wrong syntax"". Check line " 
322                                << root.getSourceLine() << ".";
323                        it_error ( msg.str() );
324                }
325
326                Setting &cols_setting = root[0];
327                Setting &rows_setting = root[1];
328                Setting &values = root[2];
329
330                ASSERT_UITYPE(cols_setting,TypeInt);
331                ASSERT_UITYPE(rows_setting,TypeInt);
332                ASSERT_UITYPE(values,TypeArray);
333
334                int cols = cols_setting;
335                int rows = rows_setting;
336               
337                if( values.getLength() != cols * rows )
338                {
339                        stringstream msg;
340                        msg << "UI: the lenght of array containing matrix values within setting " << root.getPath() <<  """ is improper, check line " 
341                                << root.getSourceLine() << ".";
342                        it_error ( msg.str() );
343                }
344
345                matrix.set_size( rows, cols );
346
347                if( cols == 0 || rows == 0 )
348                        return true;
349
350                if( !values[0].isNumber() )
351                {
352                        stringstream msg;
353                        msg << "UI: the array containing matrix values within setting " << root.getPath() <<  """ has to contain numeric values only! Check line " 
354                                << root.getSourceLine() << ".";
355                        it_error ( msg.str() );
356                }
357
358                // Build matrix row-wise
359                int k = 0;
360                for( int i=0;i<rows;i++ ) 
361                        for( int j=0; j<cols; j++)
362                                matrix(i,j) = values[k++];
363
364                return true;
365        }
366
367        //! This methods tries to save a double matrix
368        static void ToSetting( mat &matrix, Setting &root )
369        {
370                Setting &cols = root.add( Setting::TypeInt );
371                cols = matrix.cols();
372
373                Setting &rows = root.add( Setting::TypeInt );
374                rows = matrix.rows();
375
376                Setting &values = root.add( Setting::TypeArray );
377
378                // Build matrix row-wise
379                for( int i=0; i<matrix.rows(); i++ ) 
380                        for( int j=0; j<matrix.cols(); j++)
381                        {
382                                Setting &newField = values.add(Setting::TypeFloat);
383                                newField = matrix(i,j);
384                        }
385        }
386
387        //! This methods tries to build a new integer vector
388        static bool FromSetting( ivec &vec, const Setting &root )
389        {
390                ASSERT_UITYPE(root,TypeArray);
391
392                int len = root.getLength();
393                vec.set_length( len );
394                if( len == 0 ) return true;
395                ASSERT_UITYPE(root[0],TypeInt);
396
397                for( int i=0; i < len; i++ ) 
398                        vec(i) = root[i];
399               
400                return true;
401        }
402
403        //! This methods tries to save an integer vector
404        static void ToSetting( ivec &vec, Setting &root )
405        {
406                for( int i=0; i<vec.length(); i++ ) 
407                {
408                        Setting &newField = root.add(Setting::TypeInt);
409                        newField = vec(i);
410                }
411        }
412
413        //! This methods tries to build a new array of strings
414        static bool FromSetting( Array<string> &string_array, const Setting &root)
415        {
416                ASSERT_UITYPE(root,TypeArray);
417
418                int len = root.getLength();
419                string_array.set_length( len );
420                if( len == 0 ) return true;
421                ASSERT_UITYPE(root[0],TypeString);
422
423                for( int i=0; i < len; i++ ) 
424                        string_array(i) = (string)root[i];
425
426                return true;
427        }
428
429        //! This methods tries to save an array of strings
430        static void ToSetting( Array<string> &string_array, Setting &root )
431        {
432                for( int i=0; i<string_array.length(); i++ ) 
433                {
434                        Setting &newField = root.add(Setting::TypeString);
435                        newField = string_array(i);
436                }
437        }
438
439public: 
440
441        //! This methods tries to build a new instance of type T (or some of its descendant types)
442        //! according to a data stored in a DOMNode named className within a child nodes of the passed element.
443        //! If an error occurs, it returns a NULL pointer.
444
445        //! Prototype of a UI builder. Return value is by the second argument since it type checking via \c dynamic_cast.
446        template<class T> static T* Build( Setting &element, const int index )
447        {
448                return FromSetting<T>( ToChildSetting( element, index ) );
449        }
450
451        template<class T> static T* Build( Setting &element, const string &name )
452        {                       
453                return FromSetting<T>( ToChildSetting( element, name ) );
454        }
455
456        //! This methods tries to save an instance of type T (or some of its descendant types)
457        //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className
458        //! and connecti it to the passed Setting as a new child node.
459        template<class T> static void Save( T &instance, Setting &element )
460        {
461                Setting &root = element.add( Setting::TypeGroup );             
462                ToSetting( instance, root );
463        }
464
465        //! This methods tries to save an instance of type T (or some of its descendant types)
466        //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className
467        //! and connecti it to the passed Setting as a new child node.
468        template<class T> static void Save( T &instance, Setting &element, const string &name )
469        {
470                Setting &root = element.add( name, Setting::TypeGroup );               
471                ToSetting( instance, root );
472        }
473
474        //! This methods tries to build a new double matrix
475        static bool Get( mat& matrix, const Setting &element, const string &name )
476        {
477                const Setting *root = ToChildSetting( element, name );
478                if( !root ) return false;                               
479                return FromSetting( matrix, *root );
480        }
481
482        //! This methods tries to build a new double matrix
483        static bool Get( mat& matrix, const Setting &element, const int index )
484        {
485                const Setting *root = ToChildSetting( element, index );
486                if( !root ) return false;                               
487                return FromSetting( matrix, *root );
488        }
489
490        //! This methods tries to save a double matrix
491        static void Save( mat &matrix, Setting &element, const string &name )
492        {
493                Setting &root = element.add( name, Setting::TypeList );         
494                ToSetting( matrix, root );
495        }
496
497        //! This methods tries to save a double matrix
498        static void Save( mat &matrix, Setting &element )
499        {
500                Setting &root = element.add( Setting::TypeList );               
501                ToSetting( matrix, root );
502        }
503
504
505        //! This methods tries to build a new double vec
506        static bool Get( ivec& vec, const Setting &element, const string &name )
507        {
508                const Setting *root = ToChildSetting( element, name );
509                if( !root ) return false;                               
510                return FromSetting( vec, *root );
511        }
512
513        //! This methods tries to build a new double vec
514        static bool Get( ivec& vec, const Setting &element, const int index )
515        {
516                const Setting *root = ToChildSetting( element, index );
517                if( !root ) return false;                               
518                return FromSetting( vec, *root );
519        }
520
521        //! This methods tries to save a double vec
522        static void Save( ivec &vec, Setting &element, const string &name )
523        {
524                Setting &root = element.add( name, Setting::TypeArray );               
525                ToSetting( vec, root );
526        }
527
528        //! This methods tries to save a double vec
529        static void Save( ivec &vec, Setting &element)
530        {
531                Setting &root = element.add( Setting::TypeArray );             
532                ToSetting( vec, root );
533        }
534
535
536        //! This methods tries to build a new double string_array
537        static bool Get( Array<string> &string_array, const Setting &element, const string &name )
538        {
539                const Setting *root = ToChildSetting( element, name );
540                if( !root ) return false;                               
541                return FromSetting( string_array, *root );
542        }
543
544        //! This methods tries to build a new double string_array
545        static bool Get( Array<string> &string_array, const Setting &element, const int index )
546        {
547                const Setting *root = ToChildSetting( element, index );
548                if( !root ) return false;                               
549                return FromSetting( string_array, *root );
550        }
551
552        //! This methods tries to save a double string_array
553        static void Save( Array<string> &string_array, Setting &element, const string &name )
554        {
555                Setting &root = element.add( name, Setting::TypeArray );               
556                ToSetting( string_array, root );
557        }
558
559        //! This methods tries to save a double string_array
560        static void Save( Array<string> &string_array, Setting &element )
561        {
562                Setting &root = element.add( Setting::TypeArray );             
563                ToSetting( string_array, root );
564        }
565
566
567};
568
569
570/*!
571@brief The main userinfo template class. You should derive this class whenever you need
572a new userinfo of a class which is compound from smaller elements (all having its
573own userinfo class prepared).
574*/
575template<typename T> class ParticularUI : private UI
576{
577        // to permit acces to the ParticularUI<T>::ui to the UI class
578        friend UI;
579
580        //! default constructor, which is intentionally declared as private
581        ParticularUI<T>( const string &className) : UI( className ) 
582        {       
583        };
584
585        //! the only instance of this class (each type T has its own instance)
586        //! which is used as a factory for processing related UI
587        static ParticularUI<T>& ui;     
588
589        bdmroot* New()
590        {
591                return new T();
592        }
593};
594
595
596}
597
598/*! Recursive build of objects defined in the same file
599
600\code
601{type="internal";
602path="system.profile.[0]";    // Path from the root
603};
604\endcode
605 */
606
607
608
609/*! Recursive build of objects defined in external file
610
611\code
612{type="external";
613filename="my_file.cfg";       // name of file from which to read
614path="system.profile.[0]";    // Path in the external file
615};
616\endcode
617/
618
619
620//! [Debugging] Print values in current S to cout
621void UI_DBG ( Setting &S, const string &spc );
622
623
624/*
625//! Auxiliary function allowing recursivity in S (too complex, remove?)
626template<class T>
627void UIcall ( Setting &S, void ( *func ) ( Setting&, T ), T Tmp ) {
628        ASSERT_UITYPE ( S,TypeGroup );
629        // Check if field "class" is present, if not it is not a valid UI
630        it_assert_debug ( S.exists ( "class" ), string ( S.getPath() ) +" is not a valid UI!" );
631
632        const string typ=S["class"];
633        if ( typ=="internal" ) {
634                try {
635                        Setting* Stmp = &S;
636                        do {Stmp=& ( Stmp->getParent() );}
637                        while ( !Stmp->isRoot() );
638                        Setting& intS=Stmp->lookup ( ( const char* ) S["path"] );
639                        func ( intS, Tmp ); // <======== calling func
640                        return;
641                }
642                catch ( ... ) {
643                        it_error ( "Internal field " + string ( S.getPath() ) + " not valid" );
644                }
645        }
646        if ( typ=="external" ) {
647                UIFile C ( S["filename"] );
648                try {
649                        func ( C.lookup ( ( const char* ) S["path"] ), Tmp );
650                }
651                catch ( ... ) {
652                        it_error ( "External field " + string ( S.getPath() ) + " not valid" );
653                }
654                return;
655        }
656
657        // v======================= calling final func
658        func ( S, Tmp );
659};
660
661}
662
663*/
664
665#endif // #ifndef UIBUILD
Note: See TracBrowser for help on using the browser.