/* The software in this package is distributed under the GNU General Public License version 2 (with a special exception described below). A copy of GNU General Public License (GPL) is included in this distribution, in the file COPYING.GPL. As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. */ /** @file * @brief provides config file reading and automatic propagation of the values. * * @author Reinhard Pfau * * @copyright © Copyright 2008 by Intra2net AG * * Basic idea of this module is that one need only to declare its config vars of * the type Config::Var\< T \> and pass the desired section and key from the * (INI style) config file where the value for this var should be searched. * The string value from the config file is converted to the desired type using a * converter class (a default is provided and uses a conversion based on string_to template * from libi2ncommon). * * Populating the var is automagically done when the config is read or reread or when * the variable is defined. * * * @todo review. consolidate. beautify. * @todo the converter should be better named as "validator" since they do not only convert... * @todo support for std::set<> ? */ #ifndef __I2N_GLOBAL_CONFIG_HPP__ #define __I2N_GLOBAL_CONFIG_HPP__ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace I2n { namespace Config { template< typename ValueType, class Converter > class Var; typedef std::vector< std::string > StringList; /** * @brief contains the "magic" details of the config module * (i.e. all the stuff which must be declared here, but U shouldn't use it!) */ namespace Detail { typedef boost::function< bool(const std::string&) > FeedFunction; typedef boost::function< bool(const StringList&) > FeedFunction2; struct Thing { virtual ~Thing() {} }; // eo struct Thing typedef boost::shared_ptr< Thing > FlowerShop; FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction& feed); FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction2& feed); FlowerShop seymour(FlowerShop shop, const FeedFunction& feed); FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed); /* ** type magics: */ /** * @brief determines if a type is one of the supported list containers. * @tparam Container the type to test for supported list type. * * currently we support std::list<> and std::vector<> (and derivates). */ template< class Container > struct is_list_container { static Container gen(); template< typename T > static boost::type_traits::yes_type c1( const std::vector< T >& ); template< typename T > static boost::type_traits::yes_type c1( const std::list< T >& ); static boost::type_traits::no_type c1(...); BOOST_STATIC_CONSTANT( bool, value= ( sizeof(c1(gen())) == sizeof(boost::type_traits::yes_type) ) ); }; template< class C, bool is_list > struct extract_type_impl { typedef typename boost::remove_reference< typename boost::remove_const< C >::type>::type type; }; template< class C > struct extract_type_impl< C, true > { typedef typename boost::remove_reference< typename boost::remove_const< typename C::value_type >::type >::type type; }; template< class C > struct extract_type : public extract_type_impl< C, is_list_container< C >::value > { }; /* ** */ template< typename ValueType, class Converter, bool wantList > class OuterSpace { public: typedef ValueType result_type; typedef typename boost::remove_reference< ValueType >::type unref_value_type; typedef typename boost::remove_const< unref_value_type>::type base_value_type; typedef typename boost::add_const< typename boost::add_reference< base_value_type >::type >::type const_ref_value_type; typedef FeedFunction FeedFunctionType; protected: friend class Var; OuterSpace(ValueType initial_value) : Value(initial_value) , InitialValue(initial_value) { } OuterSpace(const OuterSpace& other) : Value( other.Value) , InitialValue( other.InitialValue) { } bool audreyII(const std::string& v) { bool res= Converter()(v,Value); if (!res) Value= InitialValue; return res; } // eo audreyII(const std::string&) base_value_type Value; base_value_type InitialValue; }; // eo class OuterSpace template< typename ValueType, class Converter > class OuterSpace< ValueType, Converter, true > { public: typedef ValueType result_type; typedef typename boost::remove_reference< ValueType >::type unref_value_type; typedef typename boost::remove_const< unref_value_type>::type base_value_type; typedef typename boost::add_const< typename boost::add_reference< base_value_type >::type >::type const_ref_value_type; typedef FeedFunction2 FeedFunctionType; protected: friend class Var; OuterSpace(ValueType initial_value) : Value(initial_value) , InitialValue(initial_value) { } bool audreyII(const StringList& v) { Converter convert; Value.clear(); bool res= true; BOOST_FOREACH(const std::string& s, v) { typename base_value_type::value_type value; if (not convert(s,value)) { res = false; break; } Value.push_back( value ); } if (not res) Value= InitialValue; return res; } // eo audreyII(const std::string&) base_value_type Value; base_value_type InitialValue; }; // eo class OuterSpace } // eo namespace Detail /** * @brief default converter for the Var class. * @tparam ValueType the type of the result value (which the input should be converted to) * * Uses stringTo to convert the values. * * @see i2n::stringTo */ template< typename ValueType > struct DefaultConverter : public std::binary_function< std::string, ValueType&, bool > { bool operator () ( const std::string& str, ValueType& v ) { return string_to< ValueType >( str, v ); } // eo operator()(const std::string&,ValueType&) }; // eo struct DefaultConverter /** * @brief specialized converter for std::string result type. * * just copies the input to the result var and returns true. */ template<> struct DefaultConverter< std::string > : public std::binary_function< std::string, std::string&, bool > { bool operator () ( const std::string& str, std::string& v ) { v= str; return true; } // eo operator()(const std::string&,std::string&) }; // eo struct DefaultConverter< std::string > /** * @brief specialized converter for int types which accepts also octal and hex notation as input. * @tparam ValueType the type of the result value (which the input should be converted to) */ template< typename ValueType > struct AutoIntConverter : public std::binary_function< std::string, ValueType&, bool > { bool operator () ( const std::string& str, ValueType& v ) { std::istringstream istr(str); if (has_prefix(str,"0x")) { istr.get(); istr.get(); istr.setf( std::ios::hex, std::ios::basefield ); } else if (has_prefix(str,"0") or has_prefix(str,"-0")) { istr.setf( std::ios::oct, std::ios::basefield ); } istr >> v; return istr.eof(); } // eo operator()(const std::string&,ValueType&) }; // eo struct AutoIntConverter /** * @brief represents a configuration variable with automatic update. * @tparam ValueType type of the value this variable should hold. * @tparam Converter a converter class which converts a string (from config file) to the desired * type. * Needs to be derived from std::binary_function (taking a string as first arg, a reference to the * desired type as second and returning bool (@a true if conversion was succesful). * * Basic idea is to pass a point (section, key) in the config where the value for this * variable is stored. The config value (a string) should be converted to the desired value (type). * When the config is loaded (or reloaded) the var (content) is automatically updated. * * @see DefaultConverter * * @bug value accessing methods are @a const, but the result type may allow changing the internal value... */ template< typename ValueType, class Converter = DefaultConverter< typename Detail::extract_type< ValueType >::type > > class Var : public Detail::OuterSpace< ValueType, Converter, Detail::is_list_container< ValueType >::value > { BOOST_STATIC_ASSERT(( boost::is_base_of< std::binary_function< std::string, typename boost::add_reference< typename Detail::extract_type< ValueType >::type >::type, bool >, Converter >::value )); typedef Detail::OuterSpace< ValueType, Converter, Detail::is_list_container< ValueType >::value > MySpace; public: typedef typename MySpace::result_type result_type; typedef typename MySpace::base_value_type base_value_type; public: /** * @brief constructor with config location and initial value. * @param section the section in the config where the value is located in. * @param key the key (in the section) which identifies the value. * @param initial_value the initial value. */ Var(const std::string& section, const std::string& key, ValueType initial_value) : MySpace(initial_value) { FlowerShop= Detail::seymour( section, key, typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) ); } /** * @brief constructor with config location (key in global section) and initial value. * @param key the key (in the global section) which identifies the value. * @param initial_value the initial value. */ Var(const std::string& key, ValueType initial_value) : MySpace(initial_value) { FlowerShop= Detail::seymour( "", key, typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) ); } /** * @brief operator for accessing the value. * @return the current value. */ result_type operator()() const { return MySpace::Value; } /** * @brief method for accessing the value. * @return the current value. */ result_type get_value() const { return MySpace::Value; } /** * @brief copy constructor. * @param other the instance to copy from. */ Var(const Var& other) : MySpace( other ) { FlowerShop= Detail::seymour( other.FlowerShop, typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) ); } // eo Var(const Var&) /** * @brief cast operator for the underlying value type. delivers the value. * @return the current value. * * The cast operator allows the instance to be used whereever the underlying value type * is expected. */ operator result_type () const { return MySpace::Value; } private: Detail::FlowerShop FlowerShop; }; // eo class Var /** * @brief convenience: \<\< operator which streams the current value of a config var. */ template < typename ValueType, class Converter > std::ostream& operator<<(std::ostream& o, const Var< ValueType, Converter >& v) { return o << v(); } // eo operator<<(std::ostream&,const Var< ValueType, Converter>& bool set_config_file(const std::string& path); std::string get_config_file(); bool reload(); } // eo namespace Config } // eo namespace I2n #endif