• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   settings.hpp
9  * \author Andrey Semashev
10  * \date   11.10.2009
11  *
12  * The header contains definition of the library settings container.
13  */
14 
15 #ifndef BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_
17 
18 #include <cstddef>
19 #include <string>
20 #include <iterator>
21 #include <boost/assert.hpp>
22 #include <boost/move/core.hpp>
23 #include <boost/type_traits/conditional.hpp>
24 #include <boost/iterator/iterator_adaptor.hpp>
25 #include <boost/optional/optional.hpp>
26 #include <boost/property_tree/ptree.hpp>
27 #include <boost/core/explicit_operator_bool.hpp>
28 #include <boost/log/detail/setup_config.hpp>
29 #include <boost/log/detail/native_typeof.hpp>
30 #if !defined(BOOST_LOG_TYPEOF)
31 #include <boost/core/enable_if.hpp>
32 #endif
33 #if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
34 #include <boost/utility/declval.hpp>
35 #endif
36 #include <boost/log/detail/header.hpp>
37 
38 #ifdef BOOST_HAS_PRAGMA_ONCE
39 #pragma once
40 #endif
41 
42 namespace boost {
43 
44 BOOST_LOG_OPEN_NAMESPACE
45 
46 namespace aux {
47 
48 // This workaround is needed for MSVC 10 to work around ICE caused by stack overflow
49 template< typename SectionT, bool IsConstV >
50 struct basic_settings_section_iterator_base;
51 
52 template< typename SectionT >
53 struct basic_settings_section_iterator_base< SectionT, true >
54 {
55     typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< true > iterator_type;
56     typedef typename SectionT::property_tree_type::const_iterator base_iterator_type;
57     typedef iterator_adaptor<
58         iterator_type,
59         base_iterator_type,
60         SectionT,
61         use_default,
62         const SectionT
63     > type;
64 };
65 
66 template< typename SectionT >
67 struct basic_settings_section_iterator_base< SectionT, false >
68 {
69     typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< false > iterator_type;
70     typedef typename SectionT::property_tree_type::iterator base_iterator_type;
71     typedef iterator_adaptor<
72         iterator_type,
73         base_iterator_type,
74         SectionT,
75         use_default,
76         SectionT
77     > type;
78 };
79 
80 } // namespace aux
81 
82 /*!
83  * \brief The class represents a reference to the settings container section
84  *
85  * The section refers to a sub-tree of the library settings container. It does not
86  * own the referred sub-tree but allows for convenient access to parameters within the subsection.
87  */
88 template< typename CharT >
89 class basic_settings_section
90 {
91     template< typename SectionT, bool IsConstV >
92     friend struct aux::basic_settings_section_iterator_base;
93 
94 public:
95     //! Character type
96     typedef CharT char_type;
97     //! String type
98     typedef std::basic_string< char_type > string_type;
99     //! Property tree type
100     typedef property_tree::basic_ptree< std::string, string_type > property_tree_type;
101     //! Property tree path type
102     typedef typename property_tree_type::path_type path_type;
103 
104 private:
105 #if !defined(BOOST_LOG_DOXYGEN_PASS)
106 
107     //! A reference proxy object
108 #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS
109     template< bool IsConstV >
110     class ref;
111     template< bool IsConstV >
112     friend class ref;
113 #endif
114     template< bool IsConstV >
115     class ref
116     {
117     private:
118         typedef typename boost::conditional<
119             IsConstV,
120             basic_settings_section< char_type > const,
121             basic_settings_section< char_type >
122         >::type section_type;
123 
124     private:
125         section_type& m_section;
126         path_type m_path;
127 
128     public:
ref(section_type & section,std::string const & section_name)129         ref(section_type& section, std::string const& section_name) :
130             m_section(section),
131             m_path(section_name)
132         {
133         }
ref(section_type & section,const char * section_name)134         ref(section_type& section, const char* section_name) :
135             m_section(section),
136             m_path(section_name)
137         {
138         }
139 
operator [](std::string const & param_name)140         ref& operator[] (std::string const& param_name)
141         {
142             m_path /= param_name;
143             return *this;
144         }
145 
operator =(string_type const & value)146         ref& operator= (string_type const& value)
147         {
148             BOOST_ASSERT(m_section.m_ptree != NULL);
149             m_section.m_ptree->put(m_path, value);
150             return *this;
151         }
152 
153         template< bool V >
operator =(ref<V> const & value)154         ref& operator= (ref< V > const& value)
155         {
156             BOOST_ASSERT(m_section.m_ptree != NULL);
157             optional< string_type > val = value.get();
158             if (!!val)
159             {
160                 m_section.m_ptree->put(m_path, val);
161             }
162             else if (optional< property_tree_type& > node = m_section.m_ptree->get_child_optional(m_path))
163             {
164                 node.put_value(string_type());
165             }
166 
167             return *this;
168         }
169 
170         template< typename T >
operator =(T const & value)171         ref& operator= (T const& value)
172         {
173             BOOST_ASSERT(m_section.m_ptree != NULL);
174             m_section.m_ptree->put(m_path, value);
175             return *this;
176         }
177 
178         BOOST_EXPLICIT_OPERATOR_BOOL()
179 
180         bool operator! () const
181         {
182             return !m_section.m_ptree || !m_section.m_ptree->get_child_optional(m_path);
183         }
184 
get_name() const185         std::string get_name() const
186         {
187             return m_path.dump();
188         }
189 
operator optional<string_type>() const190         operator optional< string_type > () const
191         {
192             return get();
193         }
194 
get() const195         optional< string_type > get() const
196         {
197             if (m_section.m_ptree)
198                 return m_section.m_ptree->template get_optional< string_type >(m_path);
199             else
200                 return optional< string_type >();
201         }
202 
203         template< typename T >
get() const204         optional< T > get() const
205         {
206             if (m_section.m_ptree)
207                 return m_section.m_ptree->template get_optional< T >(m_path);
208             else
209                 return optional< T >();
210         }
211 
operator section_type() const212         operator section_type () const
213         {
214             return get_section();
215         }
216 
get_section() const217         section_type get_section() const
218         {
219             if (m_section.m_ptree)
220                 return section_type(m_section.m_ptree->get_child_optional(m_path).get_ptr());
221             else
222                 return section_type();
223         }
224 
225 #if defined(BOOST_LOG_TYPEOF) && !(defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) && !defined(__PATHSCALE__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ == 4 && __GNUC_MINOR__ <= 5))
226 #if !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
227         template< typename T >
or_default(T const & def_value) const228         auto or_default(T const& def_value) const -> BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), def_value))
229         {
230             if (m_section.m_ptree)
231                 return m_section.m_ptree->get(m_path, def_value);
232             else
233                 return def_value;
234         }
235 #else
236         // GCC up to 4.5 (inclusively) segfaults on the following code, if C++11 mode is not enabled
237         template< typename T >
property_tree_type()238         BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), boost::declval< T >())) or_default(T const& def_value) const
239         {
240             if (m_section.m_ptree)
241                 return m_section.m_ptree->get(m_path, def_value);
242             else
243                 return def_value;
244         }
245 #endif
246 #else
247         template< typename T >
or_default(T const & def_value) const248         T or_default(T const& def_value) const
249         {
250             if (m_section.m_ptree)
251                 return m_section.m_ptree->get(m_path, def_value);
252             else
253                 return def_value;
254         }
255 
256         template< typename T >
257         typename boost::enable_if_c< boost::property_tree::detail::is_character< T >::value, std::basic_string< T > >::type
or_default(const T * def_value) const258         or_default(const T* def_value) const
259         {
260             if (m_section.m_ptree)
261                 return m_section.m_ptree->get(m_path, def_value);
262             else
263                 return def_value;
264         }
265 #endif
or_default(string_type const & def_value) const266         string_type or_default(string_type const& def_value) const
267         {
268             return get().get_value_or(def_value);
269         }
or_default(typename string_type::value_type const * def_value) const270         string_type or_default(typename string_type::value_type const* def_value) const
271         {
272             if (optional< string_type > val = get())
273                 return val.get();
274             else
275                 return def_value;
276         }
277     };
278 
279     //! An iterator over subsections and parameters
280 #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS
281     template< bool IsConstV >
282     class iter;
283     template< bool IsConstV >
284     friend class iter;
285 #endif
286     template< bool IsConstV >
287     class iter :
288         public aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::type
289     {
290         friend class boost::iterator_core_access;
291 
292         typedef typename iter::iterator_adaptor_ iterator_adaptor_;
293         // NOTE: This typedef must not come from iterator_adaptor_::base_type in order to work around MSVC 10 ICE
294         typedef typename aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::base_iterator_type base_iterator_type;
295 
296     public:
297         typedef typename iterator_adaptor_::reference reference;
298 
299     public:
iter()300         BOOST_DEFAULTED_FUNCTION(iter(), {})
301         template< bool OtherIsConstV >
302         iter(iter< OtherIsConstV > const& that) : iterator_adaptor_(that.base()) {}
iter(base_iterator_type const & it)303         explicit iter(base_iterator_type const& it) : iterator_adaptor_(it) {}
304 
305         //! Returns the section name
get_name() const306         std::string const& get_name() const
307         {
308             return this->base()->first;
309         }
310 
311     private:
dereference() const312         reference dereference() const
313         {
314             return reference(const_cast< property_tree_type* >(&this->base()->second));
315         }
316     };
317 
318 public:
319     typedef ref< true > const_reference;
320     typedef ref< false > reference;
321     typedef iter< true > const_iterator;
322     typedef iter< false > iterator;
323     typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
324     typedef std::reverse_iterator< iterator > reverse_iterator;
325 
326 #else
327 
328 public:
329     /*!
330      * Constant reference to the parameter value
331      */
332     typedef implementation_defined const_reference;
333     /*!
334      * Mutable reference to the parameter value
335      */
336     typedef implementation_defined reference;
337 
338     /*!
339      * Constant iterator over nested parameters and subsections
340      */
341     typedef implementation_defined const_iterator;
342     /*!
343      * Mutable iterator over nested parameters and subsections
344      */
345     typedef implementation_defined iterator;
346 
347 #endif // !defined(BOOST_LOG_DOXYGEN_PASS)
348 
349 protected:
350     //! Parameters
351     property_tree_type* m_ptree;
352 
353 public:
354     /*!
355      * Default constructor. Creates an empty settings container.
356      */
basic_settings_section()357     basic_settings_section() BOOST_NOEXCEPT : m_ptree(NULL)
358     {
359     }
360 
361     /*!
362      * Copy constructor.
363      */
basic_settings_section(basic_settings_section const & that)364     basic_settings_section(basic_settings_section const& that) BOOST_NOEXCEPT : m_ptree(that.m_ptree)
365     {
366     }
367 
368     /*!
369      * Checks if the section refers to the container.
370      */
371     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
372 
373     /*!
374      * Checks if the section refers to the container.
375      */
376     bool operator! () const BOOST_NOEXCEPT { return !m_ptree; }
377 
378     /*!
379      * Returns an iterator over the nested subsections and parameters.
380      */
begin()381     iterator begin()
382     {
383         if (m_ptree)
384             return iterator(m_ptree->begin());
385         else
386             return iterator();
387     }
388 
389     /*!
390      * Returns an iterator over the nested subsections and parameters.
391      */
end()392     iterator end()
393     {
394         if (m_ptree)
395             return iterator(m_ptree->end());
396         else
397             return iterator();
398     }
399 
400     /*!
401      * Returns an iterator over the nested subsections and parameters.
402      */
begin() const403     const_iterator begin() const
404     {
405         if (m_ptree)
406             return const_iterator(m_ptree->begin());
407         else
408             return const_iterator();
409     }
410 
411     /*!
412      * Returns an iterator over the nested subsections and parameters.
413      */
end() const414     const_iterator end() const
415     {
416         if (m_ptree)
417             return const_iterator(m_ptree->end());
418         else
419             return const_iterator();
420     }
421 
422     /*!
423      * Returns a reverse iterator over the nested subsections and parameters.
424      */
rbegin()425     reverse_iterator rbegin() { return reverse_iterator(begin()); }
426 
427     /*!
428      * Returns a reverse iterator over the nested subsections and parameters.
429      */
rend()430     reverse_iterator rend() { return reverse_iterator(end()); }
431 
432     /*!
433      * Returns a reverse iterator over the nested subsections and parameters.
434      */
rbegin() const435     const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
436 
437     /*!
438      * Returns a reverse iterator over the nested subsections and parameters.
439      */
rend() const440     const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
441 
442     /*!
443      * Checks if the container is empty (i.e. contains no sections and parameters).
444      */
empty() const445     bool empty() const { return m_ptree == NULL || m_ptree->empty(); }
446 
447     /*!
448      * Accessor to a single parameter. This operator should be used in conjunction
449      * with the subsequent subscript operator that designates the parameter name.
450      *
451      * \param section_name The name of the section in which the parameter resides
452      * \return An unspecified reference type that can be used for parameter name specifying
453      */
operator [](std::string const & section_name)454     reference operator[] (std::string const& section_name) { return reference(*this, section_name); }
455     /*!
456      * Accessor to a single parameter. This operator should be used in conjunction
457      * with the subsequent subscript operator that designates the parameter name.
458      *
459      * \param section_name The name of the section in which the parameter resides
460      * \return An unspecified reference type that can be used for parameter name specifying
461      */
operator [](std::string const & section_name) const462     const_reference operator[] (std::string const& section_name) const { return const_reference(*this, section_name); }
463 
464     /*!
465      * Accessor to a single parameter. This operator should be used in conjunction
466      * with the subsequent subscript operator that designates the parameter name.
467      *
468      * \param section_name The name of the section in which the parameter resides
469      * \return An unspecified reference type that can be used for parameter name specifying
470      */
operator [](const char * section_name)471     reference operator[] (const char* section_name) { return reference(*this, section_name); }
472     /*!
473      * Accessor to a single parameter. This operator should be used in conjunction
474      * with the subsequent subscript operator that designates the parameter name.
475      *
476      * \param section_name The name of the section in which the parameter resides
477      * \return An unspecified reference type that can be used for parameter name specifying
478      */
operator [](const char * section_name) const479     const_reference operator[] (const char* section_name) const { return const_reference(*this, section_name); }
480 
481     /*!
482      * Accessor for the embedded property tree
483      */
property_tree() const484     property_tree_type const& property_tree() const { return *m_ptree; }
485     /*!
486      * Accessor for the embedded property tree
487      */
property_tree()488     property_tree_type& property_tree() { return *m_ptree; }
489 
490     /*!
491      * Checks if the specified section is present in the container.
492      *
493      * \param section_name The name of the section
494      */
has_section(string_type const & section_name) const495     bool has_section(string_type const& section_name) const
496     {
497         return m_ptree != NULL && !!m_ptree->get_child_optional(section_name);
498     }
499     /*!
500      * Checks if the specified parameter is present in the container.
501      *
502      * \param section_name The name of the section in which the parameter resides
503      * \param param_name The name of the parameter
504      */
has_parameter(string_type const & section_name,string_type const & param_name) const505     bool has_parameter(string_type const& section_name, string_type const& param_name) const
506     {
507         if (m_ptree)
508         {
509             optional< property_tree_type& > section = m_ptree->get_child_optional(section_name);
510             if (!!section)
511                 return (section->find(param_name) != section->not_found());
512         }
513 
514         return false;
515     }
516 
517     /*!
518      * Swaps two references to settings sections.
519      */
swap(basic_settings_section & that)520     void swap(basic_settings_section& that) BOOST_NOEXCEPT
521     {
522         property_tree_type* const p = m_ptree;
523         m_ptree = that.m_ptree;
524         that.m_ptree = p;
525     }
526 
527 protected:
basic_settings_section(property_tree_type * tree)528     explicit basic_settings_section(property_tree_type* tree) BOOST_NOEXCEPT : m_ptree(tree)
529     {
530     }
531 };
532 
533 template< typename CharT >
swap(basic_settings_section<CharT> & left,basic_settings_section<CharT> & right)534 inline void swap(basic_settings_section< CharT >& left, basic_settings_section< CharT >& right) BOOST_NOEXCEPT
535 {
536     left.swap(right);
537 }
538 
539 
540 /*!
541  * \brief The class represents settings container
542  *
543  * All settings are presented as a number of named parameters divided into named sections.
544  * The parameters values are stored as strings. Individual parameters may be queried via subscript operators, like this:
545  *
546  * <code><pre>
547  * optional< string > param = settings["Section1"]["Param1"]; // reads parameter "Param1" in section "Section1"
548  *                                                            // returns an empty value if no such parameter exists
549  * settings["Section2"]["Param2"] = 10; // sets the parameter "Param2" in section "Section2"
550  *                                      // to value "10"
551  * </pre></code>
552  *
553  * There are also other methods to work with parameters.
554  */
555 template< typename CharT >
556 class basic_settings :
557     public basic_settings_section< CharT >
558 {
559     typedef basic_settings this_type;
560     BOOST_COPYABLE_AND_MOVABLE(this_type)
561 
562 public:
563     //! Section type
564     typedef basic_settings_section< CharT > section;
565     //! Property tree type
566     typedef typename section::property_tree_type property_tree_type;
567 
568 public:
569     /*!
570      * Default constructor. Creates an empty settings container.
571      */
basic_settings()572     basic_settings() : section(new property_tree_type())
573     {
574     }
575 
576     /*!
577      * Copy constructor.
578      */
basic_settings(basic_settings const & that)579     basic_settings(basic_settings const& that) :
580         section(that.m_ptree ? new property_tree_type(*that.m_ptree) : static_cast< property_tree_type* >(NULL))
581     {
582     }
583 
584     /*!
585      * Move constructor.
586      */
basic_settings(BOOST_RV_REF (this_type)that)587     basic_settings(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT
588     {
589         this->swap(that);
590     }
591     /*!
592      * Initializing constructor. Creates a settings container with the copy of the specified property tree.
593      */
basic_settings(property_tree_type const & tree)594     explicit basic_settings(property_tree_type const& tree) : section(new property_tree_type(tree))
595     {
596     }
597 
598     /*!
599      * Destructor
600      */
~basic_settings()601     ~basic_settings() BOOST_NOEXCEPT
602     {
603         delete this->m_ptree;
604     }
605 
606     /*!
607      * Copy assignment operator.
608      */
operator =(BOOST_COPY_ASSIGN_REF (basic_settings)that)609     basic_settings& operator= (BOOST_COPY_ASSIGN_REF(basic_settings) that)
610     {
611         if (this != &that)
612         {
613             basic_settings tmp = that;
614             this->swap(tmp);
615         }
616         return *this;
617     }
618     /*!
619      * Move assignment operator.
620      */
operator =(BOOST_RV_REF (basic_settings)that)621     basic_settings& operator= (BOOST_RV_REF(basic_settings) that) BOOST_NOEXCEPT
622     {
623         this->swap(that);
624         return *this;
625     }
626 };
627 
628 #ifdef BOOST_LOG_USE_CHAR
629 typedef basic_settings< char > settings;                        //!< Convenience typedef for narrow-character logging
630 typedef basic_settings_section< char > settings_section;        //!< Convenience typedef for narrow-character logging
631 #endif
632 #ifdef BOOST_LOG_USE_WCHAR_T
633 typedef basic_settings< wchar_t > wsettings;                    //!< Convenience typedef for wide-character logging
634 typedef basic_settings_section< wchar_t > wsettings_section;    //!< Convenience typedef for wide-character logging
635 #endif
636 
637 BOOST_LOG_CLOSE_NAMESPACE // namespace log
638 
639 } // namespace boost
640 
641 #include <boost/log/detail/footer.hpp>
642 
643 #endif // BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_
644