[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 | |
---|
[361] | 18 | #ifndef BDMLIB |
---|
[358] | 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 | class UI |
---|
| 78 | { |
---|
| 79 | private: |
---|
| 80 | //! static class encalupsating map of names to related UserInfos |
---|
| 81 | //! |
---|
| 82 | //! The key property of this class is that it initilaized the internal map immediately |
---|
| 83 | //! when it is used for a first time. |
---|
[351] | 84 | class Mapped_UI |
---|
[344] | 85 | { |
---|
| 86 | private: |
---|
| 87 | //! Type definition of mapping which transforms type names to the related user infors |
---|
[351] | 88 | typedef map< const string, const UI* const > String_To_UI_Map; |
---|
[344] | 89 | |
---|
[351] | 90 | //! Type definition of mapping which transforms type names to the related user infors |
---|
| 91 | typedef map< const type_info * const, const string > Type_Info_To_String_Map; |
---|
[344] | 92 | |
---|
[351] | 93 | //! immediately initialized instance of type String_To_UI_Map |
---|
| 94 | static String_To_UI_Map& mapped_strings(); |
---|
| 95 | |
---|
| 96 | //! immediately initialized instance of type String_To_UI_Map |
---|
| 97 | static Type_Info_To_String_Map& mapped_type_infos(); |
---|
| 98 | |
---|
[344] | 99 | public: |
---|
| 100 | //! add a pair key-userinfo into the internal map |
---|
[351] | 101 | static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui ); |
---|
[344] | 102 | |
---|
| 103 | //! search for an userinfo related to the passed key within the internal map |
---|
[351] | 104 | static const UI& retrieve_ui( const string &class_name ); |
---|
| 105 | |
---|
| 106 | //! search for an userinfo related to the passed key within the internal map |
---|
| 107 | static const string& retrieve_class_name( const type_info* const class_type_info ); |
---|
[344] | 108 | }; |
---|
[351] | 109 | |
---|
| 110 | // vraci true, kdyz to byl platny link, jinak false.. v pripade chyby konci it_errorem.. |
---|
| 111 | // do elementu vrati setting prislusny po rozbaleni linku, jinak ponecha beze zmeny |
---|
| 112 | class Link_Expander |
---|
| 113 | { |
---|
| 114 | private: |
---|
| 115 | UI_File *file; |
---|
| 116 | const Setting *result; |
---|
| 117 | |
---|
| 118 | public: |
---|
| 119 | |
---|
| 120 | Link_Expander( const Setting &potential_link ); |
---|
| 121 | |
---|
| 122 | ~Link_Expander(); |
---|
| 123 | |
---|
| 124 | const Setting& root() const; |
---|
| 125 | }; |
---|
| 126 | |
---|
| 127 | |
---|
[344] | 128 | //! internal method assembling a typeless instance from components obtained by the 'AssemblyComponentsFromSetting()' method |
---|
[351] | 129 | virtual bdmroot* new_instance() const = 0; |
---|
[344] | 130 | |
---|
| 131 | //! This methods tries to save an instance of type T (or some of its descendant types) |
---|
[345] | 132 | //! and build DOM tree accordingly. Then, it creates a new DOMNode named according class_name |
---|
[344] | 133 | //! and connecti it to the passed Setting as a new child node. |
---|
[357] | 134 | static const Setting& to_child_setting( const Setting &element, const int index ); |
---|
[246] | 135 | |
---|
[357] | 136 | static const Setting& to_child_setting( const Setting &element, const string &name ); |
---|
[351] | 137 | |
---|
| 138 | |
---|
[359] | 139 | //! \name Matematical Operations TODO |
---|
| 140 | //!@{ |
---|
| 141 | |
---|
[351] | 142 | //! This methods tries to build a new double matrix |
---|
| 143 | static void from_setting( mat& matrix, const Setting &element ); |
---|
| 144 | //! This methods tries to build a new integer vector |
---|
[357] | 145 | static void from_setting( ivec &vector, const Setting &element ); |
---|
[351] | 146 | // jednak kvuli pretypovani, apak taky proto, ze na string nefunguje link_expander.. |
---|
| 147 | static void from_setting( string &str, const Setting &element ); |
---|
| 148 | //! This methods tries to build a new templated array |
---|
| 149 | |
---|
[357] | 150 | static void from_setting( vec &vector, const Setting &element ); |
---|
| 151 | |
---|
[351] | 152 | template<class T> static void from_setting( T* &instance, const Setting &element ) |
---|
[344] | 153 | { |
---|
[345] | 154 | const Link_Expander link_expander( element ); |
---|
| 155 | const Setting &root = link_expander.root(); |
---|
[246] | 156 | |
---|
[344] | 157 | ASSERT_UITYPE(root,TypeGroup); |
---|
| 158 | |
---|
| 159 | // we get a velue stored in the "class" attribute |
---|
[345] | 160 | string class_name; |
---|
| 161 | if( !root.lookupValue( "class", class_name ) ) |
---|
| 162 | ui_error( "the obligatory ""class"" identifier is missing", root ); |
---|
[344] | 163 | |
---|
| 164 | // and finally we find a UserInfo related to this type |
---|
[351] | 165 | const UI& related_UI = Mapped_UI::retrieve_ui( class_name ); |
---|
[344] | 166 | |
---|
[351] | 167 | bdmroot* typeless_instance = related_UI.new_instance(); |
---|
[344] | 168 | |
---|
[351] | 169 | instance = NULL; |
---|
[344] | 170 | try |
---|
| 171 | { |
---|
[351] | 172 | instance = (T*) typeless_instance ; |
---|
[344] | 173 | } |
---|
| 174 | catch(...) |
---|
| 175 | { |
---|
[345] | 176 | 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] | 177 | } |
---|
| 178 | |
---|
| 179 | try |
---|
| 180 | { |
---|
[351] | 181 | instance->from_setting( root ); |
---|
[344] | 182 | } |
---|
| 183 | catch(SettingException xcptn) |
---|
| 184 | { |
---|
[345] | 185 | 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] | 186 | } |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | |
---|
[351] | 190 | //! This methods tries to build a new templated array , |
---|
| 191 | // efektivne jen pro vect, mat a string, pro dalsi je nutne pridat from_setting metodu.. ale to asi necceme |
---|
| 192 | template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element ) |
---|
[344] | 193 | { |
---|
[345] | 194 | const Link_Expander link_expander( element ); |
---|
| 195 | const Setting &root = link_expander.root(); |
---|
| 196 | |
---|
[351] | 197 | ASSERT_UITYPE(root,TypeList); |
---|
[344] | 198 | |
---|
[351] | 199 | int len = root.getLength(); |
---|
| 200 | array_to_load.set_length( len ); |
---|
| 201 | if( len == 0 ) return; |
---|
| 202 | |
---|
| 203 | for( int i=0; i < len; i++ ) |
---|
| 204 | from_setting( array_to_load(i), root[i] ); |
---|
[281] | 205 | } |
---|
[243] | 206 | |
---|
[359] | 207 | //!@} |
---|
| 208 | |
---|
| 209 | |
---|
[357] | 210 | static void ui_error( string message, const Setting &element ); |
---|
| 211 | |
---|
[345] | 212 | protected: |
---|
| 213 | //! default constructor |
---|
[351] | 214 | UI( const string& class_name, const type_info * const class_type_info ) |
---|
[345] | 215 | { |
---|
[351] | 216 | Mapped_UI::add_class( class_name, class_type_info, this ); |
---|
[345] | 217 | } |
---|
| 218 | |
---|
| 219 | //! Virtual destructor for future use; |
---|
| 220 | virtual ~UI(){}; |
---|
| 221 | |
---|
[351] | 222 | public: |
---|
[344] | 223 | //! This methods tries to build a new instance of type T (or some of its descendant types) |
---|
[345] | 224 | //! according to a data stored in a DOMNode named class_name within a child nodes of the passed element. |
---|
[357] | 225 | //! If an error occurs, it returns a NULL pointer. |
---|
[281] | 226 | |
---|
[344] | 227 | //! Prototype of a UI builder. Return value is by the second argument since it type checking via \c dynamic_cast. |
---|
[351] | 228 | template<class T> static T* build( const Setting &element, const int index ) |
---|
[344] | 229 | { |
---|
[351] | 230 | T* instance; |
---|
[357] | 231 | from_setting<T>( to_child_setting( element, index ) ); |
---|
[351] | 232 | return instance; |
---|
[344] | 233 | } |
---|
[281] | 234 | |
---|
[351] | 235 | template<class T> static T* build( const Setting &element, const string &name ) |
---|
[344] | 236 | { |
---|
[351] | 237 | T* instance; |
---|
[357] | 238 | from_setting<T>( instance, to_child_setting( element, name ) ); |
---|
[351] | 239 | return instance; |
---|
[344] | 240 | } |
---|
[281] | 241 | |
---|
[344] | 242 | //! This methods tries to build a new double matrix |
---|
[357] | 243 | template<class T> static void get( T &instance, const Setting &element, const string &name ) |
---|
[344] | 244 | { |
---|
[357] | 245 | from_setting( instance, to_child_setting( element, name ) ); |
---|
[344] | 246 | } |
---|
| 247 | |
---|
| 248 | //! This methods tries to build a new double matrix |
---|
[357] | 249 | template<class T> static void get( T &instance, const Setting &element, const int index ) |
---|
[344] | 250 | { |
---|
[357] | 251 | from_setting( instance, to_child_setting( element, index ) ); |
---|
[344] | 252 | } |
---|
| 253 | |
---|
[351] | 254 | //! This methods tries to build a new double matrix |
---|
[357] | 255 | template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name ) |
---|
[344] | 256 | { |
---|
[357] | 257 | from_setting( array_to_load, to_child_setting( element, name ) ); |
---|
[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 int index ) |
---|
[344] | 262 | { |
---|
[357] | 263 | from_setting( array_to_load, to_child_setting( element, index ) ); |
---|
[344] | 264 | } |
---|
| 265 | |
---|
[351] | 266 | template< class T> static void save( const T * const instance, Setting &element, const string &name = "") |
---|
[344] | 267 | { |
---|
[351] | 268 | Setting &root = (name == "") ? element.add( Setting::TypeGroup ) |
---|
| 269 | : element.add( name, Setting::TypeGroup ); |
---|
[344] | 270 | |
---|
[351] | 271 | const string &class_name = Mapped_UI::retrieve_class_name( &typeid(*instance) ); |
---|
| 272 | |
---|
| 273 | // add attribute "class" |
---|
| 274 | Setting &type = root.add( "class", Setting::TypeString ); |
---|
| 275 | type = class_name; |
---|
[344] | 276 | |
---|
[351] | 277 | try |
---|
| 278 | { |
---|
| 279 | instance->to_setting( root ); |
---|
| 280 | } |
---|
| 281 | catch(SettingException xcptn) |
---|
| 282 | { |
---|
| 283 | 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." ); |
---|
| 284 | } |
---|
[344] | 285 | } |
---|
| 286 | |
---|
[351] | 287 | //! This methods tries to save a double vec |
---|
| 288 | template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" ) |
---|
[344] | 289 | { |
---|
[351] | 290 | ASSERT_UITYPE(element,TypeGroup); |
---|
| 291 | Setting &list = (name == "") ? element.add( Setting::TypeList ) |
---|
| 292 | : element.add( name, Setting::TypeList ); |
---|
| 293 | for( int i=0; i<array_to_save.length(); i++ ) |
---|
| 294 | save( array_to_save(i), list ); |
---|
[344] | 295 | } |
---|
[351] | 296 | |
---|
| 297 | |
---|
| 298 | //! This methods tries to save a double matrix |
---|
| 299 | static void save( const mat &matrix, Setting &element, const string &name = "" ); |
---|
| 300 | |
---|
| 301 | //! This methods tries to save a double vec |
---|
| 302 | static void save( const ivec &vec, Setting &element, const string &name = "" ); |
---|
| 303 | |
---|
[357] | 304 | static void save( const vec &vector, Setting &element, const string &name); |
---|
| 305 | |
---|
[351] | 306 | private: |
---|
| 307 | //! This methods tries to save a double vec |
---|
| 308 | static void save( const string &str, Setting &element); |
---|
| 309 | |
---|
[281] | 310 | }; |
---|
| 311 | |
---|
| 312 | |
---|
[344] | 313 | /*! |
---|
| 314 | @brief The main userinfo template class. You should derive this class whenever you need |
---|
| 315 | a new userinfo of a class which is compound from smaller elements (all having its |
---|
| 316 | own userinfo class prepared). |
---|
[281] | 317 | */ |
---|
[345] | 318 | template<typename T> class Particular_UI : private UI |
---|
[344] | 319 | { |
---|
[358] | 320 | public: |
---|
[344] | 321 | |
---|
| 322 | //! default constructor, which is intentionally declared as private |
---|
[351] | 323 | Particular_UI<T>( const string &class_name) : UI( class_name, &typeid(T) ) |
---|
[344] | 324 | { |
---|
| 325 | }; |
---|
| 326 | |
---|
| 327 | //! the only instance of this class (each type T has its own instance) |
---|
| 328 | //! which is used as a factory for processing related UI |
---|
[358] | 329 | static const Particular_UI<T>& ui; |
---|
[344] | 330 | |
---|
[351] | 331 | bdmroot* new_instance() const |
---|
[344] | 332 | { |
---|
| 333 | return new T(); |
---|
| 334 | } |
---|
[281] | 335 | }; |
---|
| 336 | |
---|
[344] | 337 | |
---|
[351] | 338 | |
---|
| 339 | |
---|
[344] | 340 | } |
---|
| 341 | |
---|
[281] | 342 | /*! Recursive build of objects defined in the same file |
---|
| 343 | |
---|
| 344 | \code |
---|
| 345 | {type="internal"; |
---|
| 346 | path="system.profile.[0]"; // Path from the root |
---|
| 347 | }; |
---|
| 348 | \endcode |
---|
| 349 | */ |
---|
[344] | 350 | |
---|
| 351 | |
---|
| 352 | |
---|
| 353 | /*! Recursive build of objects defined in external file |
---|
| 354 | |
---|
| 355 | \code |
---|
| 356 | {type="external"; |
---|
| 357 | filename="my_file.cfg"; // name of file from which to read |
---|
| 358 | path="system.profile.[0]"; // Path in the external file |
---|
[281] | 359 | }; |
---|
[344] | 360 | \endcode |
---|
| 361 | / |
---|
[281] | 362 | |
---|
[344] | 363 | */ |
---|
| 364 | |
---|
[358] | 365 | #endif // #ifndef USER_INFO_H |
---|