#ifndef UIBUILD #define UIBUILD #include #include #include #include #include #include #include #include #include #include "libconfig/libconfig.h++" #include #include "stat/libBM.h" using std::string; using namespace std; using namespace libconfig; #define UIREGISTER(class_name) template<> Particular_UI& Particular_UI::ui = Particular_UI(#class_name) #define ASSERT_UITYPE(S,Type) it_assert_debug(S.getType()==Setting::Type, string("Wrong setting type, see input path \"")+string(S.getPath())+string("\"")) namespace bdm { class UI_File : public Config { private: const string file_name; public: //! attach new RootElement instance to a file (typically with an XML extension) UI_File( const string &file_name ); //! loads root element from a file void load(); //! save UserInfo to the file (typically with an XML extension) void save(); operator Setting&(); }; /*! @brief This class serves to load and/or save DOMElements into/from files stored on a hard-disk. Firstly, you associate new RootElement instance with some filename during a time of its construtcion. Then, you save some object into the new RootElement instance, and save it into the file this way: \code CAudi audi; RootElement root("cars.xml"); UserInfo::save( audi, root, "TT"); root.save(); \endcode In the other way round, when loading object from a XML file, the appropriate code looks like this: \code RootElement root("cars.xml"); root.load(); UserInfo::build(root,"TT"); \endcode */ /*! @brief UserInfo is an abstract is for internal purposes only. Use CompoundUserInfo or Particular_UI instead. The raison d'etre of this class is to allow pointers to its templated descendants. Also, the main functions of the whole UserInfo library are included within this class, see static methods 'build' and 'save'. /*!\brief Builds computational object from a UserInfo structure Return value is a pointer to the created object (memory management issue?) / */ class UI { private: //! static class encalupsating map of names to related UserInfos //! //! The key property of this class is that it initilaized the internal map immediately //! when it is used for a first time. class Mapped_UI { private: //! Type definition of mapping which transforms type names to the related user infors typedef map< const string, const UI* const > String_To_UI_Map; //! Type definition of mapping which transforms type names to the related user infors typedef map< const type_info * const, const string > Type_Info_To_String_Map; //! immediately initialized instance of type String_To_UI_Map static String_To_UI_Map& mapped_strings(); //! immediately initialized instance of type String_To_UI_Map static Type_Info_To_String_Map& mapped_type_infos(); public: //! add a pair key-userinfo into the internal map static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui ); //! search for an userinfo related to the passed key within the internal map static const UI& retrieve_ui( const string &class_name ); //! search for an userinfo related to the passed key within the internal map static const string& retrieve_class_name( const type_info* const class_type_info ); }; // vraci true, kdyz to byl platny link, jinak false.. v pripade chyby konci it_errorem.. // do elementu vrati setting prislusny po rozbaleni linku, jinak ponecha beze zmeny class Link_Expander { private: UI_File *file; const Setting *result; public: Link_Expander( const Setting &potential_link ); ~Link_Expander(); const Setting& root() const; }; //! internal method assembling a typeless instance from components obtained by the 'AssemblyComponentsFromSetting()' method virtual bdmroot* new_instance() const = 0; //! This methods tries to save an instance of type T (or some of its descendant types) //! and build DOM tree accordingly. Then, it creates a new DOMNode named according class_name //! and connecti it to the passed Setting as a new child node. static const Setting* pointer_to_child_setting( const Setting &element, const int index ); static const Setting* pointer_to_child_setting( const Setting &element, const string &name ); static const Setting& reference_to_child_setting( const Setting &element, const int index ); static const Setting& reference_to_child_setting( const Setting &element, const string &name ); //! This methods tries to build a new double matrix static void from_setting( mat& matrix, const Setting &element ); //! This methods tries to build a new integer vector static void from_setting( ivec &vec, const Setting &element ); // jednak kvuli pretypovani, apak taky proto, ze na string nefunguje link_expander.. static void from_setting( string &str, const Setting &element ); //! This methods tries to build a new templated array template static void from_setting( T* &instance, const Setting &element ) { const Link_Expander link_expander( element ); const Setting &root = link_expander.root(); ASSERT_UITYPE(root,TypeGroup); // we get a velue stored in the "class" attribute string class_name; if( !root.lookupValue( "class", class_name ) ) ui_error( "the obligatory ""class"" identifier is missing", root ); // and finally we find a UserInfo related to this type const UI& related_UI = Mapped_UI::retrieve_ui( class_name ); bdmroot* typeless_instance = related_UI.new_instance(); instance = NULL; try { instance = (T*) typeless_instance ; } catch(...) { 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." ); } try { instance->from_setting( root ); } catch(SettingException xcptn) { 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." ); } } //! This methods tries to build a new templated array , // efektivne jen pro vect, mat a string, pro dalsi je nutne pridat from_setting metodu.. ale to asi necceme template static void from_setting( Array &array_to_load, const Setting &element ) { const Link_Expander link_expander( element ); const Setting &root = link_expander.root(); ASSERT_UITYPE(root,TypeList); int len = root.getLength(); array_to_load.set_length( len ); if( len == 0 ) return; for( int i=0; i < len; i++ ) from_setting( array_to_load(i), root[i] ); } protected: //! default constructor UI( const string& class_name, const type_info * const class_type_info ) { Mapped_UI::add_class( class_name, class_type_info, this ); } //! Virtual destructor for future use; virtual ~UI(){}; public: static void ui_error( string message, const Setting &element ) { stringstream error_message; error_message << "UI ui_error: " << message << "! Check path """ << element.getPath() << """, source line " << element.getSourceLine() << "."; it_error ( error_message.str() ); } //! This methods tries to build a new instance of type T (or some of its descendant types) //! according to a data stored in a DOMNode named class_name within a child nodes of the passed element. //! If an ui_error occurs, it returns a NULL pointer. //! Prototype of a UI builder. Return value is by the second argument since it type checking via \c dynamic_cast. template static T* build( const Setting &element, const int index ) { T* instance; from_setting( reference_to_child_setting( element, index ) ); return instance; } template static T* build( const Setting &element, const string &name ) { T* instance; from_setting( instance, reference_to_child_setting( element, name ) ); return instance; } //! This methods tries to build a new double matrix template static bool get( T &instance, const Setting &element, const string &name ) { const Setting *root = pointer_to_child_setting( element, name ); if( !root ) return false; from_setting( instance, *root ); return true; } //! This methods tries to build a new double matrix template static bool get( T &instance, const Setting &element, const int index ) { const Setting *root = pointer_to_child_setting( element, index ); if( !root ) return false; from_setting( instance, *root ); return true; } //! This methods tries to build a new double matrix template static bool get( Array &array_to_load, const Setting &element, const string &name ) { const Setting *root = pointer_to_child_setting( element, name ); if( !root ) return false; from_setting( array_to_load, *root ); return true; } //! This methods tries to build a new double matrix template static bool get( Array &array_to_load, const Setting &element, const int index ) { const Setting *root = pointer_to_child_setting( element, index ); if( !root ) return false; from_setting( array_to_load, *root ); return true; } template< class T> static void save( const T * const instance, Setting &element, const string &name = "") { Setting &root = (name == "") ? element.add( Setting::TypeGroup ) : element.add( name, Setting::TypeGroup ); const string &class_name = Mapped_UI::retrieve_class_name( &typeid(*instance) ); // add attribute "class" Setting &type = root.add( "class", Setting::TypeString ); type = class_name; try { instance->to_setting( root ); } catch(SettingException xcptn) { 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." ); } } //! This methods tries to save a double vec template static void save( const Array &array_to_save, Setting &element, const string &name = "" ) { ASSERT_UITYPE(element,TypeGroup); Setting &list = (name == "") ? element.add( Setting::TypeList ) : element.add( name, Setting::TypeList ); for( int i=0; i class Particular_UI : private UI { // to permit acces to the Particular_UI::ui to the UI class friend UI; //! default constructor, which is intentionally declared as private Particular_UI( const string &class_name) : UI( class_name, &typeid(T) ) { }; //! the only instance of this class (each type T has its own instance) //! which is used as a factory for processing related UI static Particular_UI& ui; bdmroot* new_instance() const { return new T(); } }; } /*! Recursive build of objects defined in the same file \code {type="internal"; path="system.profile.[0]"; // Path from the root }; \endcode */ /*! Recursive build of objects defined in external file \code {type="external"; filename="my_file.cfg"; // name of file from which to read path="system.profile.[0]"; // Path in the external file }; \endcode / */ #endif // #ifndef UIBUILD