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