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