Show
Ignore:
Timestamp:
05/14/10 12:16:00 (14 years ago)
Author:
mido
Message:

the functionality of user info was improved, it supports an initialization of root descendant via UI::get directly, however it is save only for static attributes, for dynamically allocated attributes UI::build should be called to handle with intahrence issues

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • library/bdm/base/user_info.h

    r927 r942  
    228228}; 
    229229 
     230 
     231//! This class stores the details which will be logged to a logger 
     232//! 
     233//! This is only the first part of the whole declaration, which has to be however separated into 
     234//! two different classes for allowing the compilation of source code. For more details 
     235//! see logger::add_setting(...) method and mainly log_level_template<T>::template<class U> void store( const enum T::log_level_enums log_level_enum, const U data ) const 
     236//! method. For the reason the second one is templated, it was necessary to declare this whole class.  
     237template<class T> class log_level_base : public root { 
     238private: 
     239        //! this is necessary to allow logger to set ids vector appropriately and also to set registered_logger 
     240        friend class logger;  
     241 
     242protected: 
     243        //! boolean flags related indicating which details will be logged to a logger 
     244        bitset<32> values; 
     245         
     246        //! vector of vectors of log IDs - one element for each entry and multiple entries can be stored on the position of one enum 
     247        Vec<ivec> ids; 
     248 
     249        //! internal pointer to the logger to which this log_level is registered 
     250        //!  
     251        //! it is set to NULL at the beginning 
     252        logger * registered_logger; 
     253 
     254public: 
     255 
     256        //! default constructor 
     257        log_level_base( ) { 
     258                registered_logger = NULL; 
     259                int len = names().length(); 
     260                ids.set_size( len ); 
     261                for( int i = 0; i<len; i++ ) 
     262                { 
     263                        ids(i).set_size ( 1 ); 
     264                        ids(i) = -1; 
     265                } 
     266        } 
     267 
     268        //! a general utility transforming a comma-separated sequence of strings into an instance of Array<strings> 
     269        static Array<string> string2Array( const string &input ) 
     270        { 
     271                string result = input; 
     272                string::size_type loc; 
     273                while( loc = result.find( ',' ), loc != string::npos ) 
     274                        result[loc] = ' '; 
     275                return Array<string>("{ " + result + " }" ); 
     276        } 
     277 
     278 
     279 
     280        //! Set log_levels according to the Setting element 
     281        void from_setting ( const Setting &element ) 
     282        { 
     283                string raw_log_level; 
     284                UI::get( raw_log_level, element ); 
     285                Array<string> loaded_log_level = log_level_base::string2Array( raw_log_level ); 
     286         
     287                values.reset(); 
     288 
     289                for( int i = 0; i < loaded_log_level.length(); i++ ) 
     290                        for( int j = 0; j < names().length(); j++ ){ 
     291                                if( loaded_log_level(i) == names()(j)  )  
     292                                { 
     293                                        values[j] = true; 
     294                                        break; 
     295                                }  
     296                        } 
     297        } 
     298 
     299        //! Store log_levels into the Setting element 
     300        void to_setting ( Setting &element ) const  
     301        { 
     302                // HERE WE WANT NOT TO DELETE PREVIOUS DATA STORED BY OTHER LOG_LEVELS, SEE SPECIAL IMPLEMENTATION OF UI::GET(...) FOR THIS CLASS 
     303                string string_to_write =  ( const char* ) element; 
     304 
     305                for( unsigned int i = 0; i < values.size(); i++ ) 
     306                        if( values[i] )  
     307                        { 
     308                                if( string_to_write.length() > 0 ) 
     309                                        string_to_write = string_to_write + ','; 
     310                                string_to_write = string_to_write + names()(i); 
     311                        } 
     312                         
     313                element = string_to_write; 
     314        } 
     315 
     316        //! this method adds new id to its proper position and return the name of this position 
     317        string store_id_and_give_name( enum T::log_level_enums const log_level_enum,  int enum_subindex, int id ) { 
     318                if( ids(log_level_enum).length() <= enum_subindex ) 
     319                        ids(log_level_enum).set_size( enum_subindex+1, true ); 
     320                ids(log_level_enum)(enum_subindex) = id;  
     321 
     322                // here we remove a "log" prefix from name, i.e., for instance it transforms "logevidence" to "evidence" 
     323                ostringstream stream; 
     324                string name_with_prefix = names()(log_level_enum); 
     325                string possible_log_prefix = name_with_prefix.substr(0,3); 
     326                if( possible_log_prefix == "log" ) 
     327                        stream << name_with_prefix.substr(3,name_with_prefix.length()-3); 
     328                else  
     329                        stream << name_with_prefix; 
     330 
     331                // add number to name only in the case there are more registered vectors with the same log_level_enum 
     332                if( ids(log_level_enum).length() > 1 ) 
     333                        stream << "*" << enum_subindex; 
     334                 
     335                return stream.str(); 
     336        } 
     337 
     338        //! string equivalents of the used enumerations which are filled with a help of #LOG_LEVEL macro within class T 
     339        const Array<string> &names() const 
     340        { 
     341                return T::log_level_names(); 
     342        } 
     343 
     344        //! read only operator for testing individual fields of log_level 
     345        //! 
     346        //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe 
     347        bool operator [] (const enum T::log_level_enums &log_level_enum ) const 
     348        { 
     349                return values[log_level_enum]; 
     350        } 
     351 
     352        //! operator for setting an individual field of log_level  
     353        //! 
     354        //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe 
     355        bitset<32>::reference operator [] (const enum T::log_level_enums &log_level_enum ) 
     356        { 
     357                return values[log_level_enum]; 
     358        } 
     359}; 
     360//UIREGISTER IS FORBIDDEN FOR THIS CLASS,  AS IT SHOULD BE LOADED ONLY THROUGH THE SPECIALIZED UI::GET(...) METHOD 
     361 
    230362/*! 
    231363@brief UI is an abstract class which collects all the auxiliary functions useful to prepare some concrete 
     
    292424        static const Setting& to_child_setting ( const Setting &element, const string &name ); 
    293425 
     426        //! A shortcut for calling instance.from_setting( set ); with some error catches added 
     427        static void call_from_setting( root &instance, const Setting &set, string class_name = "unknown"); 
     428 
     429        //! A shortcut for calling instance.to_setting( set ); with some error catches added 
     430        static void call_to_setting( const root &instance, Setting &set, string class_name = "unknown" ); 
     431 
    294432        //! This method converts a Setting into a matrix 
    295433        static void from_setting ( mat& matrix, const Setting &element ); 
     
    304442        //! This method converts a Setting into a real scalar    
    305443        static void from_setting ( double &real, const Setting &element ); 
    306         //! This method converts a Setting into a log_level variant and initialize options properly 
    307         static void from_setting ( log_level_base &log_level, const Setting &element ); 
    308  
     444        //! This method converts a Setting into a class T descendant 
     445        static void from_setting ( root &instance, const Setting &element ); 
    309446        //! This method converts a Setting into a class T descendant 
    310447        template<class T> static void from_setting ( T* &instance, const Setting &element ) { 
     
    330467 
    331468                try { 
    332                         instance->from_setting ( link.result ); 
    333                 } catch ( SettingException &sttng_xcptn ) { 
    334                         delete instance; 
    335                         instance = 0; 
    336                         string msg = "UIException: method "; 
    337                         msg += class_name; 
    338                         msg += ".from_setting(Setting&) has thrown a SettingException."; 
    339                         throw UISettingException ( msg, sttng_xcptn.getPath() ); 
    340                 } catch ( std::runtime_error &e ) { 
    341                         delete instance; 
    342                         instance = 0; 
    343                         string msg = "UIException: method "; 
    344                         msg += class_name; 
    345                         msg += " says: "; 
    346                         msg += e.what(); 
    347                         throw UISettingException ( msg, link.result ); 
     469                        call_from_setting( *instance, link.result, class_name ); 
    348470                } catch ( ... ) { 
    349471                        delete instance; 
     
    351473                        throw; 
    352474                } 
    353  
    354                 // validate the new instance 
    355                 instance->validate(); 
    356475        } 
    357476 
    358477        //! This method converts a Setting into a descendant of class 
    359478        //! T, wrapped in an instance of bdm::shared_ptr<T> . 
    360         template<class T> 
    361         static void from_setting ( bdm::shared_ptr<T> &instance, const Setting &element ) { 
     479        template<class T> static void from_setting ( bdm::shared_ptr<T> &instance, const Setting &element ) { 
    362480                T *tmp_inst = 0; 
    363481                from_setting ( tmp_inst, element ); 
     
    372490                assert_type ( link.result, Setting::TypeList ); 
    373491 
    374  
    375492                int len = link.result.getLength(); 
    376493                array_to_load.set_length ( len ); 
     
    380497                        from_setting ( array_to_load ( i ), link.result[i] ); 
    381498        } 
    382 /* 
    383         //! This is dummy version of the from_setting method for other, unsupported types. It just throws an exception. 
    384         //! 
    385         //! At the moment, this is the only way how to compile the library without obtaining the compiler error c2665. 
    386         //! The exception can help to find the place where the template is misused and also to correct it. 
    387         template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) { 
    388                 std::string msg = "UIException: from_setting is not implemented for type "; 
    389                 try{ 
    390                         variable_to_load.from_setting(element); 
    391                 } catch (...){ 
    392                         msg += typeid ( T ).name(); 
    393                         msg += '.'; 
    394                         throw UISettingException ( msg, element ); 
    395                 } 
    396         } 
    397 */ 
    398499 
    399500protected: 
     
    414515        //! The new instance of type T* is constructed and initialized with values stored in the Setting element[name] 
    415516        //! 
    416         //! If there is not any sub-element named #name and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found). 
     517        //! If there does not exist any sub-element named #name and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found). 
    417518        template<class T> 
    418519        static bdm::shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) { 
     
    431532        //! The new instance of type T* is constructed and initialized with values stored in the Setting element[index] 
    432533        //! 
    433         //! If there is not any sub-element indexed by #index, and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found). 
     534        //! If there does not exist any sub-element indexed by #index, and settingPresence is #optional, an empty bdm::shared_ptr<T> is returned. When settingPresence is #compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found). 
    434535        template<class T> 
    435536        static bdm::shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) { 
     
    466567 
    467568        //! The existing instance of type T is initialized with values stored in the Setting element[name] 
    468         //! If there is not any sub-element named #name, this method returns false. 
     569        //! If there does not exist any sub-element named #name, this method returns false. 
    469570        template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) { 
    470571                if ( !element.exists ( name ) ) { 
     
    480581 
    481582        //! The existing instance of type T is initialized with values stored in the Setting element[index] 
    482         //! If there is not any sub-element indexed by #index, this method returns false. 
     583        //! If there does not exist any sub-element indexed by #index, this method returns false. 
    483584        template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) { 
    484585                if ( element.getLength() <= index ) { 
     
    551652        //! or by its integer index. In that case, the new element is added at the very end of the current list of child Settings. 
    552653 
    553         //! A root descendant instance is stored in the new child Setting appended to the passed element 
    554         template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) { 
    555                 Setting &set = ( name == "" ) ?  (element.getType()==Setting::TypeArray || element.getType()==Setting::TypeList) ? element.add ( Setting::TypeGroup ) : element  
    556                                : element.add ( name, Setting::TypeGroup ); 
    557  
    558                 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) ); 
    559  
    560                 // add attribute "class" 
    561                 Setting &type = set.add ( "class", Setting::TypeString ); 
    562                 type = class_name; 
    563  
    564                 try { 
    565                         instance->to_setting ( set ); 
    566                 } catch ( SettingException &sttng_xcptn ) { 
    567                         string msg = "UIException: method "; 
    568                         msg += class_name; 
    569                         msg += ".to_setting(Setting&) has thrown a SettingException."; 
    570                         throw UISettingException ( msg, sttng_xcptn.getPath() ); 
    571                 } 
    572         } 
    573  
     654        //! A root descendant is stored in the new child Setting appended to the passed element 
     655        static void save ( const root &instance, Setting &element, const string &name = "" ); 
     656 
     657        //! A pointer to root descendant is stored in the new child Setting appended to the passed element 
     658        static void save ( const root * const instance, Setting &element, const string &name = "" ); 
     659 
     660        //! A shared pointer to root descendant is stored in the new child Setting appended to the passed element 
    574661        template< class T> static void save ( const bdm::shared_ptr<T> &instance, Setting &element, const string &name = "" ) { 
    575                 save<T> ( instance.get(), element, name ); 
     662                save( instance.get(), element, name ); 
    576663        } 
    577664 
     
    603690        static void save ( const double &real, Setting &element, const string &name = "" ); 
    604691 
    605 // The only difference from classical UserInfo approach to log_level_template is the fact 
    606         // that the actual UI element related to log_level_template could possibly exists yet. In this case,  
    607         // we do not want to throw an exception like in the case of any other type being loaded 
    608         // from Setting. We rather fill the current log_level into this existig element. This way, it is  
    609         // possible that more instances of log_level_template class (templated with different classes) 
     692    // The only difference from classical UserInfo approach here is the fact 
     693        // that the actual UI element related to log_level_base could possibly exists yet. In this case,  
     694        // we do not want to throw an exception as usually. We rather append current data into the existig element. This way, it is  
     695        // possible that more instances of log_level_base  (templated with different classes) 
    610696        // can be stored in only one line in a configuration file 
    611         static void save ( const log_level_base &log_level, Setting &element, const string &name = "log_level"  ); 
     697        template<class T> static void save ( const log_level_base<T> &log_level, Setting &element ) { 
     698                assert_type ( element, Setting::TypeGroup );             
     699                string name = "log_level"; 
     700                 
     701                if( element.exists( name ) )  
     702                        assert_type ( element[name], Setting::TypeString ); 
     703                else 
     704                        element.add ( name, Setting::TypeString );  
     705 
     706                log_level.to_setting( element[name] ); 
     707        } 
    612708 
    613709        //!@}