[357] | 1 | #ifndef USER_INFO_H |
---|
| 2 | #define USER_INFO_H |
---|
[254] | 3 | |
---|
[344] | 4 | #include <stdio.h> |
---|
| 5 | #include <string> |
---|
| 6 | #include <typeinfo> |
---|
| 7 | #include <map> |
---|
[243] | 8 | |
---|
[351] | 9 | #include "libconfig/libconfig.h++" |
---|
[357] | 10 | #include "bdmroot.h" |
---|
| 11 | #include "itpp/itbase.h" |
---|
[351] | 12 | |
---|
| 13 | |
---|
[344] | 14 | using std::string; |
---|
| 15 | using namespace std; |
---|
[281] | 16 | using namespace libconfig; |
---|
[246] | 17 | |
---|
[358] | 18 | #ifdef BDMLIB |
---|
| 19 | #define UIREGISTER(class_name) template<> const Particular_UI<class_name>& Particular_UI<class_name>::ui = Particular_UI<class_name>(#class_name) |
---|
| 20 | #else |
---|
| 21 | #define UIREGISTER(class_name) |
---|
| 22 | #endif |
---|
[246] | 23 | |
---|
[344] | 24 | #define ASSERT_UITYPE(S,Type) it_assert_debug(S.getType()==Setting::Type, string("Wrong setting type, see input path \"")+string(S.getPath())+string("\"")) |
---|
[271] | 25 | |
---|
[344] | 26 | namespace bdm |
---|
| 27 | { |
---|
[351] | 28 | class UI_File : public Config |
---|
| 29 | { |
---|
| 30 | private: |
---|
| 31 | const string file_name; |
---|
[246] | 32 | |
---|
[351] | 33 | public: |
---|
[357] | 34 | //! create empty object prepared to store Settings |
---|
| 35 | UI_File(); |
---|
| 36 | |
---|
| 37 | //! creates object and fills it from a file |
---|
[351] | 38 | UI_File( const string &file_name ); |
---|
| 39 | |
---|
[357] | 40 | //! save UserInfo to the file |
---|
| 41 | void save(const string &file_name); |
---|
[351] | 42 | |
---|
| 43 | operator Setting&(); |
---|
| 44 | }; |
---|
| 45 | |
---|
[344] | 46 | /*! |
---|
| 47 | @brief This class serves to load and/or save DOMElements into/from files |
---|
| 48 | stored on a hard-disk. |
---|
[246] | 49 | |
---|
[344] | 50 | Firstly, you associate new RootElement instance with some filename during a time of its |
---|
| 51 | construtcion. Then, you save some object into the new RootElement instance, |
---|
| 52 | and save it into the file this way: |
---|
| 53 | \code |
---|
| 54 | CAudi audi; |
---|
| 55 | RootElement root("cars.xml"); |
---|
[345] | 56 | UserInfo::save( audi, root, "TT"); |
---|
| 57 | root.save(); |
---|
[344] | 58 | \endcode |
---|
| 59 | |
---|
| 60 | In the other way round, when loading object from a XML file, the appropriate code looks like this: |
---|
| 61 | \code |
---|
| 62 | RootElement root("cars.xml"); |
---|
[345] | 63 | root.load(); |
---|
| 64 | UserInfo::build<T>(root,"TT"); |
---|
[344] | 65 | \endcode |
---|
| 66 | */ |
---|
| 67 | |
---|
| 68 | |
---|
| 69 | /*! |
---|
[345] | 70 | @brief UserInfo is an abstract is for internal purposes only. Use CompoundUserInfo<T> or Particular_UI<T> instead. |
---|
[344] | 71 | The raison d'etre of this class is to allow pointers to its templated descendants. |
---|
| 72 | |
---|
| 73 | Also, the main functions of the whole UserInfo library are included within this class, see |
---|
[345] | 74 | static methods 'build' and 'save'. |
---|
[344] | 75 | |
---|
| 76 | |
---|
| 77 | /*!\brief Builds computational object from a UserInfo structure |
---|
| 78 | |
---|
| 79 | Return value is a pointer to the created object (memory management issue?) |
---|
| 80 | / |
---|
| 81 | |
---|
| 82 | */ |
---|
| 83 | class UI |
---|
| 84 | { |
---|
| 85 | private: |
---|
| 86 | //! static class encalupsating map of names to related UserInfos |
---|
| 87 | //! |
---|
| 88 | //! The key property of this class is that it initilaized the internal map immediately |
---|
| 89 | //! when it is used for a first time. |
---|
[351] | 90 | class Mapped_UI |
---|
[344] | 91 | { |
---|
| 92 | private: |
---|
| 93 | //! Type definition of mapping which transforms type names to the related user infors |
---|
[351] | 94 | typedef map< const string, const UI* const > String_To_UI_Map; |
---|
[344] | 95 | |
---|
[351] | 96 | //! Type definition of mapping which transforms type names to the related user infors |
---|
| 97 | typedef map< const type_info * const, const string > Type_Info_To_String_Map; |
---|
[344] | 98 | |
---|
[351] | 99 | //! immediately initialized instance of type String_To_UI_Map |
---|
| 100 | static String_To_UI_Map& mapped_strings(); |
---|
| 101 | |
---|
| 102 | //! immediately initialized instance of type String_To_UI_Map |
---|
| 103 | static Type_Info_To_String_Map& mapped_type_infos(); |
---|
| 104 | |
---|
[344] | 105 | public: |
---|
| 106 | //! add a pair key-userinfo into the internal map |
---|
[351] | 107 | static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui ); |
---|
[344] | 108 | |
---|
| 109 | //! search for an userinfo related to the passed key within the internal map |
---|
[351] | 110 | static const UI& retrieve_ui( const string &class_name ); |
---|
| 111 | |
---|
| 112 | //! search for an userinfo related to the passed key within the internal map |
---|
| 113 | static const string& retrieve_class_name( const type_info* const class_type_info ); |
---|
[344] | 114 | }; |
---|
[351] | 115 | |
---|
| 116 | // vraci true, kdyz to byl platny link, jinak false.. v pripade chyby konci it_errorem.. |
---|
| 117 | // do elementu vrati setting prislusny po rozbaleni linku, jinak ponecha beze zmeny |
---|
| 118 | class Link_Expander |
---|
| 119 | { |
---|
| 120 | private: |
---|
| 121 | UI_File *file; |
---|
| 122 | const Setting *result; |
---|
| 123 | |
---|
| 124 | public: |
---|
| 125 | |
---|
| 126 | Link_Expander( const Setting &potential_link ); |
---|
| 127 | |
---|
| 128 | ~Link_Expander(); |
---|
| 129 | |
---|
| 130 | const Setting& root() const; |
---|
| 131 | }; |
---|
| 132 | |
---|
| 133 | |
---|
[344] | 134 | //! internal method assembling a typeless instance from components obtained by the 'AssemblyComponentsFromSetting()' method |
---|
[351] | 135 | virtual bdmroot* new_instance() const = 0; |
---|
[344] | 136 | |
---|
| 137 | //! This methods tries to save an instance of type T (or some of its descendant types) |
---|
[345] | 138 | //! and build DOM tree accordingly. Then, it creates a new DOMNode named according class_name |
---|
[344] | 139 | //! and connecti it to the passed Setting as a new child node. |
---|
[357] | 140 | static const Setting& to_child_setting( const Setting &element, const int index ); |
---|
[246] | 141 | |
---|
[357] | 142 | static const Setting& to_child_setting( const Setting &element, const string &name ); |
---|
[351] | 143 | |
---|
| 144 | |
---|
[359] | 145 | //! \name Matematical Operations TODO |
---|
| 146 | //!@{ |
---|
| 147 | |
---|
[351] | 148 | //! This methods tries to build a new double matrix |
---|
| 149 | static void from_setting( mat& matrix, const Setting &element ); |
---|
| 150 | //! This methods tries to build a new integer vector |
---|
[357] | 151 | static void from_setting( ivec &vector, const Setting &element ); |
---|
[351] | 152 | // jednak kvuli pretypovani, apak taky proto, ze na string nefunguje link_expander.. |
---|
| 153 | static void from_setting( string &str, const Setting &element ); |
---|
| 154 | //! This methods tries to build a new templated array |
---|
| 155 | |
---|
[357] | 156 | static void from_setting( vec &vector, const Setting &element ); |
---|
| 157 | |
---|
[351] | 158 | template<class T> static void from_setting( T* &instance, const Setting &element ) |
---|
[344] | 159 | { |
---|
[345] | 160 | const Link_Expander link_expander( element ); |
---|
| 161 | const Setting &root = link_expander.root(); |
---|
[246] | 162 | |
---|
[344] | 163 | ASSERT_UITYPE(root,TypeGroup); |
---|
| 164 | |
---|
| 165 | // we get a velue stored in the "class" attribute |
---|
[345] | 166 | string class_name; |
---|
| 167 | if( !root.lookupValue( "class", class_name ) ) |
---|
| 168 | ui_error( "the obligatory ""class"" identifier is missing", root ); |
---|
[344] | 169 | |
---|
| 170 | // and finally we find a UserInfo related to this type |
---|
[351] | 171 | const UI& related_UI = Mapped_UI::retrieve_ui( class_name ); |
---|
[344] | 172 | |
---|
[351] | 173 | bdmroot* typeless_instance = related_UI.new_instance(); |
---|
[344] | 174 | |
---|
[351] | 175 | instance = NULL; |
---|
[344] | 176 | try |
---|
| 177 | { |
---|
[351] | 178 | instance = (T*) typeless_instance ; |
---|
[344] | 179 | } |
---|
| 180 | catch(...) |
---|
| 181 | { |
---|
[345] | 182 | 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." ); |
---|
[344] | 183 | } |
---|
| 184 | |
---|
| 185 | try |
---|
| 186 | { |
---|
[351] | 187 | instance->from_setting( root ); |
---|
[344] | 188 | } |
---|
| 189 | catch(SettingException xcptn) |
---|
| 190 | { |
---|
[345] | 191 | 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." ); |
---|
[344] | 192 | } |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | |
---|
[351] | 196 | //! This methods tries to build a new templated array , |
---|
| 197 | // efektivne jen pro vect, mat a string, pro dalsi je nutne pridat from_setting metodu.. ale to asi necceme |
---|
| 198 | template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element ) |
---|
[344] | 199 | { |
---|
[345] | 200 | const Link_Expander link_expander( element ); |
---|
| 201 | const Setting &root = link_expander.root(); |
---|
| 202 | |
---|
[351] | 203 | ASSERT_UITYPE(root,TypeList); |
---|
[344] | 204 | |
---|
[351] | 205 | int len = root.getLength(); |
---|
| 206 | array_to_load.set_length( len ); |
---|
| 207 | if( len == 0 ) return; |
---|
| 208 | |
---|
| 209 | for( int i=0; i < len; i++ ) |
---|
| 210 | from_setting( array_to_load(i), root[i] ); |
---|
[281] | 211 | } |
---|
[243] | 212 | |
---|
[359] | 213 | //!@} |
---|
| 214 | |
---|
| 215 | |
---|
[357] | 216 | static void ui_error( string message, const Setting &element ); |
---|
| 217 | |
---|
[345] | 218 | protected: |
---|
| 219 | //! default constructor |
---|
[351] | 220 | UI( const string& class_name, const type_info * const class_type_info ) |
---|
[345] | 221 | { |
---|
[351] | 222 | Mapped_UI::add_class( class_name, class_type_info, this ); |
---|
[345] | 223 | } |
---|
| 224 | |
---|
| 225 | //! Virtual destructor for future use; |
---|
| 226 | virtual ~UI(){}; |
---|
| 227 | |
---|
[351] | 228 | public: |
---|
[344] | 229 | //! This methods tries to build a new instance of type T (or some of its descendant types) |
---|
[345] | 230 | //! according to a data stored in a DOMNode named class_name within a child nodes of the passed element. |
---|
[357] | 231 | //! If an error occurs, it returns a NULL pointer. |
---|
[281] | 232 | |
---|
[344] | 233 | //! Prototype of a UI builder. Return value is by the second argument since it type checking via \c dynamic_cast. |
---|
[351] | 234 | template<class T> static T* build( const Setting &element, const int index ) |
---|
[344] | 235 | { |
---|
[351] | 236 | T* instance; |
---|
[357] | 237 | from_setting<T>( to_child_setting( element, index ) ); |
---|
[351] | 238 | return instance; |
---|
[344] | 239 | } |
---|
[281] | 240 | |
---|
[351] | 241 | template<class T> static T* build( const Setting &element, const string &name ) |
---|
[344] | 242 | { |
---|
[351] | 243 | T* instance; |
---|
[357] | 244 | from_setting<T>( instance, to_child_setting( element, name ) ); |
---|
[351] | 245 | return instance; |
---|
[344] | 246 | } |
---|
[281] | 247 | |
---|
[344] | 248 | //! This methods tries to build a new double matrix |
---|
[357] | 249 | template<class T> static void get( T &instance, const Setting &element, const string &name ) |
---|
[344] | 250 | { |
---|
[357] | 251 | from_setting( instance, to_child_setting( element, name ) ); |
---|
[344] | 252 | } |
---|
| 253 | |
---|
| 254 | //! This methods tries to build a new double matrix |
---|
[357] | 255 | template<class T> static void get( T &instance, const Setting &element, const int index ) |
---|
[344] | 256 | { |
---|
[357] | 257 | from_setting( instance, to_child_setting( element, index ) ); |
---|
[344] | 258 | } |
---|
| 259 | |
---|
[351] | 260 | //! This methods tries to build a new double matrix |
---|
[357] | 261 | template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name ) |
---|
[344] | 262 | { |
---|
[357] | 263 | from_setting( array_to_load, to_child_setting( element, name ) ); |
---|
[344] | 264 | } |
---|
| 265 | |
---|
[351] | 266 | //! This methods tries to build a new double matrix |
---|
[357] | 267 | template<class T> static void get( Array<T> &array_to_load, const Setting &element, const int index ) |
---|
[344] | 268 | { |
---|
[357] | 269 | from_setting( array_to_load, to_child_setting( element, index ) ); |
---|
[344] | 270 | } |
---|
| 271 | |
---|
[351] | 272 | template< class T> static void save( const T * const instance, Setting &element, const string &name = "") |
---|
[344] | 273 | { |
---|
[351] | 274 | Setting &root = (name == "") ? element.add( Setting::TypeGroup ) |
---|
| 275 | : element.add( name, Setting::TypeGroup ); |
---|
[344] | 276 | |
---|
[351] | 277 | const string &class_name = Mapped_UI::retrieve_class_name( &typeid(*instance) ); |
---|
| 278 | |
---|
| 279 | // add attribute "class" |
---|
| 280 | Setting &type = root.add( "class", Setting::TypeString ); |
---|
| 281 | type = class_name; |
---|
[344] | 282 | |
---|
[351] | 283 | try |
---|
| 284 | { |
---|
| 285 | instance->to_setting( root ); |
---|
| 286 | } |
---|
| 287 | catch(SettingException xcptn) |
---|
| 288 | { |
---|
| 289 | 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." ); |
---|
| 290 | } |
---|
[344] | 291 | } |
---|
| 292 | |
---|
[351] | 293 | //! This methods tries to save a double vec |
---|
| 294 | template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" ) |
---|
[344] | 295 | { |
---|
[351] | 296 | ASSERT_UITYPE(element,TypeGroup); |
---|
| 297 | Setting &list = (name == "") ? element.add( Setting::TypeList ) |
---|
| 298 | : element.add( name, Setting::TypeList ); |
---|
| 299 | for( int i=0; i<array_to_save.length(); i++ ) |
---|
| 300 | save( array_to_save(i), list ); |
---|
[344] | 301 | } |
---|
[351] | 302 | |
---|
| 303 | |
---|
| 304 | //! This methods tries to save a double matrix |
---|
| 305 | static void save( const mat &matrix, Setting &element, const string &name = "" ); |
---|
| 306 | |
---|
| 307 | //! This methods tries to save a double vec |
---|
| 308 | static void save( const ivec &vec, Setting &element, const string &name = "" ); |
---|
| 309 | |
---|
[357] | 310 | static void save( const vec &vector, Setting &element, const string &name); |
---|
| 311 | |
---|
[351] | 312 | private: |
---|
| 313 | //! This methods tries to save a double vec |
---|
| 314 | static void save( const string &str, Setting &element); |
---|
| 315 | |
---|
[281] | 316 | }; |
---|
| 317 | |
---|
| 318 | |
---|
[344] | 319 | /*! |
---|
| 320 | @brief The main userinfo template class. You should derive this class whenever you need |
---|
| 321 | a new userinfo of a class which is compound from smaller elements (all having its |
---|
| 322 | own userinfo class prepared). |
---|
[281] | 323 | */ |
---|
[345] | 324 | template<typename T> class Particular_UI : private UI |
---|
[344] | 325 | { |
---|
[358] | 326 | public: |
---|
[344] | 327 | |
---|
| 328 | //! default constructor, which is intentionally declared as private |
---|
[351] | 329 | Particular_UI<T>( const string &class_name) : UI( class_name, &typeid(T) ) |
---|
[344] | 330 | { |
---|
| 331 | }; |
---|
| 332 | |
---|
| 333 | //! the only instance of this class (each type T has its own instance) |
---|
| 334 | //! which is used as a factory for processing related UI |
---|
[358] | 335 | static const Particular_UI<T>& ui; |
---|
[344] | 336 | |
---|
[351] | 337 | bdmroot* new_instance() const |
---|
[344] | 338 | { |
---|
| 339 | return new T(); |
---|
| 340 | } |
---|
[281] | 341 | }; |
---|
| 342 | |
---|
[344] | 343 | |
---|
[351] | 344 | |
---|
| 345 | |
---|
[344] | 346 | } |
---|
| 347 | |
---|
[281] | 348 | /*! Recursive build of objects defined in the same file |
---|
| 349 | |
---|
| 350 | \code |
---|
| 351 | {type="internal"; |
---|
| 352 | path="system.profile.[0]"; // Path from the root |
---|
| 353 | }; |
---|
| 354 | \endcode |
---|
| 355 | */ |
---|
[344] | 356 | |
---|
| 357 | |
---|
| 358 | |
---|
| 359 | /*! Recursive build of objects defined in external file |
---|
| 360 | |
---|
| 361 | \code |
---|
| 362 | {type="external"; |
---|
| 363 | filename="my_file.cfg"; // name of file from which to read |
---|
| 364 | path="system.profile.[0]"; // Path in the external file |
---|
[281] | 365 | }; |
---|
[344] | 366 | \endcode |
---|
| 367 | / |
---|
[281] | 368 | |
---|
[344] | 369 | */ |
---|
| 370 | |
---|
[358] | 371 | #endif // #ifndef USER_INFO_H |
---|