82a03ac820082b3927aaeb97d569eb85d08193af
[libi2ncommon] / configlib / i2n_global_config.hpp
1 /** @file
2  * @brief provides config file reading and automatic propagation of the values.
3  *
4  * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
5  * 
6  * @copyright &copy; Copyright 2008 by Intra2net AG
7  * @license commercial
8  * @contact info@intra2net.com
9  *
10  * Basic idea of this module is that one need only to declare its config vars of
11  * the type Config::Var\< T \> and pass the desired section and key from the
12  * (INI style) config file where the value for this var should be searched.
13  * The string value from the config file is converted to the desired type using a
14  * converter class (a default is provided and uses a conversion based on string_to template
15  * from libi2ncommon).
16  *
17  * Populating the var is automagically done when the config is read or reread or when
18  * the variable is defined.
19  *
20  *
21  * @todo review. consolidate. beautify.
22  * @todo the converter should be better named as "validator" since they do not only convert...
23  * @todo support for std::set<> ?
24  */
25
26 #ifndef __I2N_GLOBAL_CONFIG_HPP__
27 #define __I2N_GLOBAL_CONFIG_HPP__
28
29 #include <string>
30 #include <functional>
31 #include <vector>
32 #include <list>
33 #include <ostream>
34 #include <sstream>
35 #include <stringfunc.hxx>
36 #include <boost/shared_ptr.hpp>
37 #include <boost/static_assert.hpp>
38 #include <boost/type_traits.hpp>
39 #include <boost/function.hpp>
40 #include <boost/bind.hpp>
41 #include <boost/foreach.hpp>
42
43
44 namespace I2n
45 {
46
47 namespace Config
48 {
49
50 template<
51     typename ValueType,
52     class Converter
53 >
54 class Var;
55
56
57 typedef std::vector< std::string > StringList;
58
59 /**
60  * @brief contains the "magic" details of the config module
61  * (i.e. all the stuff which must be declared here, but U shouldn't use it!)
62  */
63 namespace Detail {
64
65
66 typedef boost::function< bool(const std::string&) > FeedFunction;
67 typedef boost::function< bool(const StringList&) > FeedFunction2;
68
69
70 struct Thing
71 {
72     virtual ~Thing() {}
73 }; // eo struct Thing
74
75 typedef boost::shared_ptr< Thing > FlowerShop;
76
77
78
79
80 FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction& feed);
81 FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction2& feed);
82 FlowerShop seymour(FlowerShop shop, const FeedFunction& feed);
83 FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed);
84
85 /*
86 ** type magics:
87 */
88
89 /**
90  * @brief determines if a type is one of the supported list containers.
91  * @tparam Container the type to test for supported list type.
92  *
93  * currently we support std::list<> and std::vector<> (and derivates).
94  */
95 template< class Container >
96 struct is_list_container
97 {
98     static Container gen();
99
100     template< typename T >
101     static boost::type_traits::yes_type c1( const std::vector< T >& );
102
103     template< typename T >
104     static boost::type_traits::yes_type c1( const std::list< T >& );
105
106     static boost::type_traits::no_type c1(...);
107
108     BOOST_STATIC_CONSTANT( bool, value= ( sizeof(c1(gen())) == sizeof(boost::type_traits::yes_type) ) );
109 };
110
111
112 template< class C, bool is_list >
113 struct extract_type_impl
114 {
115     typedef typename boost::remove_reference< typename boost::remove_const< C >::type>::type type;
116 };
117
118 template< class C >
119 struct extract_type_impl< C, true >
120 {
121     typedef typename boost::remove_reference<
122         typename boost::remove_const< typename C::value_type >::type
123     >::type type;
124 };
125
126 template< class C >
127 struct extract_type
128 : public extract_type_impl< C, is_list_container< C >::value >
129 {
130 };
131
132
133 /*
134 **
135 */
136
137 template<
138     typename ValueType,
139     class Converter,
140     bool wantList
141 >
142 class OuterSpace
143 {
144     public:
145         typedef ValueType result_type;
146         typedef typename boost::remove_reference< ValueType >::type unref_value_type;
147         typedef typename boost::remove_const< unref_value_type>::type base_value_type;
148         typedef typename boost::add_const<
149             typename boost::add_reference< base_value_type >::type
150         >::type const_ref_value_type;
151
152         typedef FeedFunction FeedFunctionType;
153
154     protected:
155         friend class Var<ValueType, Converter>;
156
157         OuterSpace(ValueType initial_value)
158         : Value(initial_value)
159         , InitialValue(initial_value)
160         {
161         }
162
163         OuterSpace(const OuterSpace& other)
164         : Value( other.Value)
165         , InitialValue( other.InitialValue)
166         {
167         }
168
169         bool audreyII(const std::string& v)
170         {
171             bool res= Converter()(v,Value);
172             if (!res) Value= InitialValue;
173             return res;
174         } // eo audreyII(const std::string&)
175
176         base_value_type Value;
177         base_value_type InitialValue;
178 }; // eo class OuterSpace
179
180
181 template<
182     typename ValueType,
183     class Converter
184 >
185 class OuterSpace< ValueType, Converter, true >
186 {
187     public:
188         typedef ValueType result_type;
189         typedef typename boost::remove_reference< ValueType >::type unref_value_type;
190         typedef typename boost::remove_const< unref_value_type>::type base_value_type;
191         typedef typename boost::add_const<
192             typename boost::add_reference< base_value_type >::type
193         >::type const_ref_value_type;
194
195         typedef FeedFunction2 FeedFunctionType;
196
197     protected:
198         friend class Var<ValueType, Converter>;
199
200         OuterSpace(ValueType initial_value)
201         : Value(initial_value)
202         , InitialValue(initial_value)
203         {
204         }
205
206         bool audreyII(const StringList& v)
207         {
208             Converter convert;
209             Value.clear();
210             bool res= true;
211             BOOST_FOREACH(const std::string& s, v)
212             {
213                 typename base_value_type::value_type value;
214                 if (not convert(s,value))
215                 {
216                     res = false;
217                     break;
218                 }
219                 Value.push_back( value );
220             }
221             if (not res) Value= InitialValue;
222             return res;
223         } // eo audreyII(const std::string&)
224
225         base_value_type Value;
226         base_value_type InitialValue;
227 }; // eo class OuterSpace
228
229 } // eo namespace Detail
230
231
232 /**
233  * @brief default converter for the Var class.
234  * @tparam ValueType the type of the result value (which the input should be converted to)
235  *
236  * Uses stringTo to convert the values.
237  *
238  * @see i2n::stringTo
239  */
240 template<
241     typename ValueType
242 >
243 struct DefaultConverter
244 : public std::binary_function< std::string, ValueType&, bool >
245 {
246
247     bool operator () ( const std::string& str, ValueType& v )
248     {
249         return string_to< ValueType >( str, v );
250     } // eo operator()(const std::string&,ValueType&)
251
252 }; // eo struct DefaultConverter
253
254
255 /**
256  * @brief specialized converter for std::string result type.
257  *
258  * just copies the input to the result var and returns true.
259  */
260 template<> struct DefaultConverter< std::string >
261 : public std::binary_function< std::string, std::string&, bool >
262 {
263
264     bool operator () ( const std::string& str, std::string& v )
265     {
266         v= str;
267         return true;
268     } // eo operator()(const std::string&,std::string&)
269
270 };  // eo struct DefaultConverter< std::string >
271
272
273
274 /**
275  * @brief specialized converter for int types which accepts also octal and hex notation as input.
276  * @tparam ValueType the type of the result value (which the input should be converted to)
277  */
278 template<
279     typename ValueType
280 >
281 struct AutoIntConverter
282 : public std::binary_function< std::string, ValueType&, bool >
283 {
284
285     bool operator () ( const std::string& str, ValueType& v )
286     {
287         std::istringstream istr(str);
288         if (has_prefix(str,"0x"))
289         {
290             istr.get(); istr.get();
291             istr.setf( std::ios::hex, std::ios::basefield );
292         }
293         else if (has_prefix(str,"0") or has_prefix(str,"-0"))
294         {
295             istr.setf( std::ios::oct, std::ios::basefield );
296         }
297         istr >> v;
298         return istr.eof();
299     } // eo operator()(const std::string&,ValueType&)
300
301 }; // eo struct AutoIntConverter
302
303
304
305 /**
306  * @brief represents a configuration variable with automatic update.
307  * @tparam ValueType type of the value this variable should hold.
308  * @tparam Converter a converter class which converts a string (from config file) to the desired
309  * type.
310  * Needs to be derived from std::binary_function (taking a string as first arg, a reference to the
311  * desired type as second and returning bool (@a true if conversion was succesful).
312  *
313  * Basic idea is to pass a point (section, key) in the config where the value for this
314  * variable is stored. The config value (a string) should be converted to the desired value (type).
315  * When the config is loaded (or reloaded) the var (content) is automatically updated.
316  *
317  * @see DefaultConverter
318  *
319  * @bug value accessing methods are @a const, but the result type may allow changing the internal value...
320  */
321 template<
322     typename ValueType,
323     class Converter = DefaultConverter<
324         typename Detail::extract_type< ValueType >::type
325     >
326 >
327 class Var
328 : public Detail::OuterSpace<
329     ValueType, Converter,
330     Detail::is_list_container< ValueType >::value >
331 {
332         BOOST_STATIC_ASSERT(( boost::is_base_of<
333             std::binary_function<
334                 std::string,
335                 typename boost::add_reference<
336                     typename Detail::extract_type< ValueType >::type
337                 >::type,
338                 bool >,
339             Converter >::value ));
340
341         typedef Detail::OuterSpace<
342             ValueType, Converter,
343             Detail::is_list_container< ValueType >::value
344         > MySpace;
345
346     public:
347
348         typedef typename MySpace::result_type result_type;
349         typedef typename MySpace::base_value_type base_value_type;
350
351     public:
352
353         /**
354          * @brief constructor with config location and initial value.
355          * @param section the section in the config where the value is located in.
356          * @param key the key (in the section) which identifies the value.
357          * @param initial_value the initial value.
358          */
359         Var(const std::string& section,
360             const std::string& key,
361             ValueType initial_value)
362         : MySpace(initial_value)
363         {
364             FlowerShop= Detail::seymour(
365                 section, key,
366                 typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
367         }
368
369
370         /**
371          * @brief constructor with config location (key in global section) and initial value.
372          * @param key the key (in the global section) which identifies the value.
373          * @param initial_value the initial value.
374          */
375         Var(const std::string& key,
376             ValueType initial_value)
377         : MySpace(initial_value)
378         {
379             FlowerShop= Detail::seymour(
380                 "", key,
381                 typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
382         }
383
384
385         /**
386          * @brief operator for accessing the value.
387          * @return the current value.
388          */
389         result_type operator()() const { return MySpace::Value; }
390
391
392         /**
393          * @brief method for accessing the value.
394          * @return the current value.
395          */
396         result_type get_value() const { return MySpace::Value; }
397
398
399         /**
400          * @brief copy constructor.
401          * @param other the instance to copy from.
402          */
403         Var(const Var& other)
404         : MySpace( other )
405         {
406             FlowerShop= Detail::seymour(
407                 other.FlowerShop,
408                 typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
409         } // eo Var(const Var&)
410
411
412         /**
413          * @brief cast operator for the underlying value type. delivers the value.
414          * @return the current value.
415          *
416          * The cast operator allows the instance to be used whereever the underlying value type
417          * is expected.
418          */
419         operator result_type () const { return MySpace::Value; }
420
421
422     private:
423
424         Detail::FlowerShop FlowerShop;
425
426 }; // eo class Var
427
428
429
430 /**
431  * @brief convenience: \<\< operator which streams the current value of a config var.
432  */
433 template <
434     typename ValueType,
435     class Converter
436 >
437 std::ostream& operator<<(std::ostream& o, const Var< ValueType, Converter >& v)
438 {
439     return o << v();
440 } // eo operator<<(std::ostream&,const Var< ValueType, Converter>&
441
442
443 bool set_config_file(const std::string& path);
444
445 std::string get_config_file();
446
447 bool reload();
448
449
450 } // eo namespace Config
451
452 } // eo namespace I2n
453
454 #endif