Merge branch 'daemon-ext'
[libi2ncommon] / configlib / i2n_global_config.hpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
23d53eb1
RP
20/** @file
21 * @brief provides config file reading and automatic propagation of the values.
22 *
0e23f538 23 * @author Reinhard Pfau
23d53eb1
RP
24 *
25 * @copyright © Copyright 2008 by Intra2net AG
23d53eb1
RP
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
61namespace I2n
62{
63
64namespace Config
65{
66
67template<
68 typename ValueType,
69 class Converter
70>
71class Var;
72
73
74typedef 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 */
80namespace Detail {
81
82
83typedef boost::function< bool(const std::string&) > FeedFunction;
84typedef boost::function< bool(const StringList&) > FeedFunction2;
85
86
87struct Thing
88{
89 virtual ~Thing() {}
90}; // eo struct Thing
91
92typedef boost::shared_ptr< Thing > FlowerShop;
93
94
95
96
97FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction& feed);
98FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction2& feed);
99FlowerShop seymour(FlowerShop shop, const FeedFunction& feed);
100FlowerShop 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 */
112template< class Container >
113struct 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
129template< class C, bool is_list >
130struct extract_type_impl
131{
132 typedef typename boost::remove_reference< typename boost::remove_const< C >::type>::type type;
133};
134
135template< class C >
136struct 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
143template< class C >
144struct extract_type
145: public extract_type_impl< C, is_list_container< C >::value >
146{
147};
148
149
150/*
151**
152*/
153
154template<
155 typename ValueType,
156 class Converter,
157 bool wantList
158>
159class 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
198template<
199 typename ValueType,
200 class Converter
201>
202class 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 */
257template<
258 typename ValueType
259>
260struct 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 */
277template<> 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 */
295template<
296 typename ValueType
297>
298struct 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 */
338template<
339 typename ValueType,
340 class Converter = DefaultConverter<
341 typename Detail::extract_type< ValueType >::type
342 >
343>
344class 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 */
450template <
451 typename ValueType,
452 class Converter
453>
454std::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
460bool set_config_file(const std::string& path);
461
462std::string get_config_file();
463
464bool reload();
465
466
467} // eo namespace Config
468
469} // eo namespace I2n
470
471#endif