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 | |
---|
15 | using std::string; |
---|
16 | using namespace std; |
---|
17 | using namespace libconfig; |
---|
18 | |
---|
19 | namespace 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 |
---|
38 | class 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 |
---|
45 | configuration files stored on a hard-disk. |
---|
46 | |
---|
47 | Firstly, save some user-infos into the new UIFile instance. Then, |
---|
48 | call 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 | |
---|
57 | In the other way round, when loading object from a configuration file, |
---|
58 | the appropriate code looks like this: |
---|
59 | |
---|
60 | \code |
---|
61 | UIFile file("cars.cfg"); |
---|
62 | CAudi *audi = UI::build<CAudi>(file,"TT"); |
---|
63 | \endcode |
---|
64 | */ |
---|
65 | class UIFile : public Config |
---|
66 | { |
---|
67 | public: |
---|
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 | |
---|
86 | This class exists mainly to allow pointers to its templated descendant ParticularUI<T>. Next, |
---|
87 | it collects all the auxiliary functions useful to prepare some concret user-infos, see static |
---|
88 | methods 'build', 'get' and 'save'. |
---|
89 | */ |
---|
90 | class UI |
---|
91 | { |
---|
92 | private: |
---|
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 | |
---|
207 | protected: |
---|
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 | |
---|
214 | public: |
---|
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 |
---|
374 | a new userinfo of a class which is compound from smaller elements (all having its |
---|
375 | own userinfo class prepared). |
---|
376 | */ |
---|
377 | template<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"; |
---|
405 | path="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"; |
---|
416 | filename="my_file.cfg"; // name of file from which to read |
---|
417 | path="system.profile.[0]"; // Path in the external file |
---|
418 | }; |
---|
419 | \endcode |
---|
420 | / |
---|
421 | |
---|
422 | */ |
---|
423 | |
---|
424 | #endif // #ifndef USER_INFO_H |
---|