Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file settings.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 11.10.2009 Chris@16: * Chris@16: * The header contains definition of the library settings container. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #if !defined(BOOST_LOG_TYPEOF) Chris@16: #include Chris@16: #endif Chris@16: #if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: // This workaround is needed for MSVC 10 to work around ICE caused by stack overflow Chris@16: template< typename SectionT, bool IsConstV > Chris@16: struct basic_settings_section_iterator_base; Chris@16: Chris@16: template< typename SectionT > Chris@16: struct basic_settings_section_iterator_base< SectionT, true > Chris@16: { Chris@16: typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< true > iterator_type; Chris@16: typedef typename SectionT::property_tree_type::const_iterator base_iterator_type; Chris@16: typedef iterator_adaptor< Chris@16: iterator_type, Chris@16: base_iterator_type, Chris@16: SectionT, Chris@16: use_default, Chris@16: const SectionT Chris@16: > type; Chris@16: }; Chris@16: Chris@16: template< typename SectionT > Chris@16: struct basic_settings_section_iterator_base< SectionT, false > Chris@16: { Chris@16: typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< false > iterator_type; Chris@16: typedef typename SectionT::property_tree_type::iterator base_iterator_type; Chris@16: typedef iterator_adaptor< Chris@16: iterator_type, Chris@16: base_iterator_type, Chris@16: SectionT, Chris@16: use_default, Chris@16: SectionT Chris@16: > type; Chris@16: }; Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: /*! Chris@16: * \brief The class represents a reference to the settings container section Chris@16: * Chris@16: * The section refers to a sub-tree of the library settings container. It does not Chris@16: * own the referred sub-tree but allows for convenient access to parameters within the subsection. Chris@16: */ Chris@16: template< typename CharT > Chris@16: class basic_settings_section Chris@16: { Chris@16: template< typename SectionT, bool IsConstV > Chris@16: friend struct aux::basic_settings_section_iterator_base; Chris@16: Chris@16: public: Chris@16: //! Character type Chris@16: typedef CharT char_type; Chris@16: //! String type Chris@16: typedef std::basic_string< char_type > string_type; Chris@16: //! Property tree type Chris@16: typedef property_tree::basic_ptree< std::string, string_type > property_tree_type; Chris@16: //! Property tree path type Chris@16: typedef typename property_tree_type::path_type path_type; Chris@16: Chris@16: private: Chris@16: #if !defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: Chris@16: //! A reference proxy object Chris@16: #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS Chris@16: template< bool IsConstV > Chris@16: class ref; Chris@16: template< bool IsConstV > Chris@16: friend class ref; Chris@16: #endif Chris@16: template< bool IsConstV > Chris@16: class ref Chris@16: { Chris@16: private: Chris@16: typedef typename mpl::if_c< Chris@16: IsConstV, Chris@16: basic_settings_section< char_type > const, Chris@16: basic_settings_section< char_type > Chris@16: >::type section_type; Chris@16: Chris@16: private: Chris@16: section_type& m_section; Chris@16: path_type m_path; Chris@16: Chris@16: public: Chris@16: ref(section_type& section, std::string const& section_name) : Chris@16: m_section(section), Chris@16: m_path(section_name) Chris@16: { Chris@16: } Chris@16: ref(section_type& section, const char* section_name) : Chris@16: m_section(section), Chris@16: m_path(section_name) Chris@16: { Chris@16: } Chris@16: Chris@16: ref& operator[] (std::string const& param_name) Chris@16: { Chris@16: m_path /= param_name; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: ref& operator= (string_type const& value) Chris@16: { Chris@16: BOOST_ASSERT(m_section.m_ptree != NULL); Chris@16: m_section.m_ptree->put(m_path, value); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template< bool V > Chris@16: ref& operator= (ref< V > const& value) Chris@16: { Chris@16: BOOST_ASSERT(m_section.m_ptree != NULL); Chris@16: optional< string_type > val = value.get(); Chris@16: if (!!val) Chris@16: { Chris@16: m_section.m_ptree->put(m_path, val); Chris@16: } Chris@16: else if (optional< property_tree_type& > node = m_section.m_ptree->get_child_optional(m_path)) Chris@16: { Chris@16: node.put_value(string_type()); Chris@16: } Chris@16: Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template< typename T > Chris@16: ref& operator= (T const& value) Chris@16: { Chris@16: BOOST_ASSERT(m_section.m_ptree != NULL); Chris@16: m_section.m_ptree->put(m_path, value); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_EXPLICIT_OPERATOR_BOOL() Chris@16: Chris@16: bool operator! () const Chris@16: { Chris@16: return !m_section.m_ptree || !m_section.m_ptree->get_child_optional(m_path); Chris@16: } Chris@16: Chris@16: std::string get_name() const Chris@16: { Chris@16: return m_path.dump(); Chris@16: } Chris@16: Chris@16: operator optional< string_type > () const Chris@16: { Chris@16: return get(); Chris@16: } Chris@16: Chris@16: optional< string_type > get() const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->template get_optional< string_type >(m_path); Chris@16: else Chris@16: return optional< string_type >(); Chris@16: } Chris@16: Chris@16: template< typename T > Chris@16: optional< T > get() const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->template get_optional< T >(m_path); Chris@16: else Chris@16: return optional< T >(); Chris@16: } Chris@16: Chris@16: operator section_type () const Chris@16: { Chris@16: return get_section(); Chris@16: } Chris@16: Chris@16: section_type get_section() const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return section_type(m_section.m_ptree->get_child_optional(m_path).get_ptr()); Chris@16: else Chris@16: return section_type(); Chris@16: } Chris@16: Chris@16: #if defined(BOOST_LOG_TYPEOF) && !(defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) && !defined(__PATHSCALE__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ == 4 && __GNUC_MINOR__ <= 5)) Chris@16: #if !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) Chris@16: template< typename T > Chris@16: auto or_default(T const& def_value) const -> BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), def_value)) Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->get(m_path, def_value); Chris@16: else Chris@16: return def_value; Chris@16: } Chris@16: #else Chris@16: // GCC up to 4.5 (inclusively) segfaults on the following code, if C++11 mode is not enabled Chris@16: template< typename T > Chris@16: BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), boost::declval< T >())) or_default(T const& def_value) const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->get(m_path, def_value); Chris@16: else Chris@16: return def_value; Chris@16: } Chris@16: #endif Chris@16: #else Chris@16: template< typename T > Chris@16: T or_default(T const& def_value) const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->get(m_path, def_value); Chris@16: else Chris@16: return def_value; Chris@16: } Chris@16: Chris@16: template< typename T > Chris@16: typename enable_if< boost::property_tree::detail::is_character< T >, std::basic_string< T > >::type Chris@16: or_default(const T* def_value) const Chris@16: { Chris@16: if (m_section.m_ptree) Chris@16: return m_section.m_ptree->get(m_path, def_value); Chris@16: else Chris@16: return def_value; Chris@16: } Chris@16: #endif Chris@16: string_type or_default(string_type const& def_value) const Chris@16: { Chris@16: return get().get_value_or(def_value); Chris@16: } Chris@16: string_type or_default(typename string_type::value_type const* def_value) const Chris@16: { Chris@16: if (optional< string_type > val = get()) Chris@16: return val.get(); Chris@16: else Chris@16: return def_value; Chris@16: } Chris@16: }; Chris@16: Chris@16: //! An iterator over subsections and parameters Chris@16: #ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS Chris@16: template< bool IsConstV > Chris@16: class iter; Chris@16: template< bool IsConstV > Chris@16: friend class iter; Chris@16: #endif Chris@16: template< bool IsConstV > Chris@16: class iter : Chris@16: public aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::type Chris@16: { Chris@16: friend class boost::iterator_core_access; Chris@16: Chris@16: typedef typename iter::iterator_adaptor_ iterator_adaptor_; Chris@16: // NOTE: This typedef must not come from iterator_adaptor_::base_type in order to work around MSVC 10 ICE Chris@16: typedef typename aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::base_iterator_type base_iterator_type; Chris@16: Chris@16: public: Chris@16: typedef typename iterator_adaptor_::reference reference; Chris@16: Chris@16: public: Chris@16: BOOST_DEFAULTED_FUNCTION(iter(), {}) Chris@16: template< bool OtherIsConstV > Chris@16: iter(iter< OtherIsConstV > const& that) : iterator_adaptor_(that.base()) {} Chris@16: explicit iter(base_iterator_type const& it) : iterator_adaptor_(it) {} Chris@16: Chris@16: //! Returns the section name Chris@16: std::string const& get_name() const Chris@16: { Chris@16: return this->base()->first; Chris@16: } Chris@16: Chris@16: private: Chris@16: reference dereference() const Chris@16: { Chris@16: return reference(const_cast< property_tree_type* >(&this->base()->second)); Chris@16: } Chris@16: }; Chris@16: Chris@16: public: Chris@16: typedef ref< true > const_reference; Chris@16: typedef ref< false > reference; Chris@16: typedef iter< true > const_iterator; Chris@16: typedef iter< false > iterator; Chris@16: typedef std::reverse_iterator< const_iterator > const_reverse_iterator; Chris@16: typedef std::reverse_iterator< iterator > reverse_iterator; Chris@16: Chris@16: #else Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Constant reference to the parameter value Chris@16: */ Chris@16: typedef implementation_defined const_reference; Chris@16: /*! Chris@16: * Mutable reference to the parameter value Chris@16: */ Chris@16: typedef implementation_defined reference; Chris@16: Chris@16: /*! Chris@16: * Constant iterator over nested parameters and subsections Chris@16: */ Chris@16: typedef implementation_defined const_iterator; Chris@16: /*! Chris@16: * Mutable iterator over nested parameters and subsections Chris@16: */ Chris@16: typedef implementation_defined iterator; Chris@16: Chris@16: #endif // !defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: Chris@16: protected: Chris@16: //! Parameters Chris@16: property_tree_type* m_ptree; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor. Creates an empty settings container. Chris@16: */ Chris@16: basic_settings_section() : m_ptree(NULL) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Copy constructor. Chris@16: */ Chris@16: basic_settings_section(basic_settings_section const& that) : m_ptree(that.m_ptree) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Checks if the section refers to the container. Chris@16: */ Chris@101: BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() Chris@16: Chris@16: /*! Chris@16: * Checks if the section refers to the container. Chris@16: */ Chris@101: bool operator! () const BOOST_NOEXCEPT { return !m_ptree; } Chris@16: Chris@16: /*! Chris@16: * Returns an iterator over the nested subsections and parameters. Chris@16: */ Chris@16: iterator begin() Chris@16: { Chris@16: if (m_ptree) Chris@16: return iterator(m_ptree->begin()); Chris@16: else Chris@16: return iterator(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Returns an iterator over the nested subsections and parameters. Chris@16: */ Chris@16: iterator end() Chris@16: { Chris@16: if (m_ptree) Chris@16: return iterator(m_ptree->end()); Chris@16: else Chris@16: return iterator(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Returns an iterator over the nested subsections and parameters. Chris@16: */ Chris@16: const_iterator begin() const Chris@16: { Chris@16: if (m_ptree) Chris@16: return const_iterator(m_ptree->begin()); Chris@16: else Chris@16: return const_iterator(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Returns an iterator over the nested subsections and parameters. Chris@16: */ Chris@16: const_iterator end() const Chris@16: { Chris@16: if (m_ptree) Chris@16: return const_iterator(m_ptree->end()); Chris@16: else Chris@16: return const_iterator(); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Returns a reverse iterator over the nested subsections and parameters. Chris@16: */ Chris@16: reverse_iterator rbegin() { return reverse_iterator(begin()); } Chris@16: Chris@16: /*! Chris@16: * Returns a reverse iterator over the nested subsections and parameters. Chris@16: */ Chris@16: reverse_iterator rend() { return reverse_iterator(end()); } Chris@16: Chris@16: /*! Chris@16: * Returns a reverse iterator over the nested subsections and parameters. Chris@16: */ Chris@16: const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } Chris@16: Chris@16: /*! Chris@16: * Returns a reverse iterator over the nested subsections and parameters. Chris@16: */ Chris@16: const_reverse_iterator rend() const { return const_reverse_iterator(end()); } Chris@16: Chris@16: /*! Chris@16: * Checks if the container is empty (i.e. contains no sections and parameters). Chris@16: */ Chris@16: bool empty() const { return m_ptree == NULL || m_ptree->empty(); } Chris@16: Chris@16: /*! Chris@16: * Accessor to a single parameter. This operator should be used in conjunction Chris@16: * with the subsequent subscript operator that designates the parameter name. Chris@16: * Chris@16: * \param section_name The name of the section in which the parameter resides Chris@16: * \return An unspecified reference type that can be used for parameter name specifying Chris@16: */ Chris@16: reference operator[] (std::string const& section_name) { return reference(*this, section_name); } Chris@16: /*! Chris@16: * Accessor to a single parameter. This operator should be used in conjunction Chris@16: * with the subsequent subscript operator that designates the parameter name. Chris@16: * Chris@16: * \param section_name The name of the section in which the parameter resides Chris@16: * \return An unspecified reference type that can be used for parameter name specifying Chris@16: */ Chris@16: const_reference operator[] (std::string const& section_name) const { return const_reference(*this, section_name); } Chris@16: Chris@16: /*! Chris@16: * Accessor to a single parameter. This operator should be used in conjunction Chris@16: * with the subsequent subscript operator that designates the parameter name. Chris@16: * Chris@16: * \param section_name The name of the section in which the parameter resides Chris@16: * \return An unspecified reference type that can be used for parameter name specifying Chris@16: */ Chris@16: reference operator[] (const char* section_name) { return reference(*this, section_name); } Chris@16: /*! Chris@16: * Accessor to a single parameter. This operator should be used in conjunction Chris@16: * with the subsequent subscript operator that designates the parameter name. Chris@16: * Chris@16: * \param section_name The name of the section in which the parameter resides Chris@16: * \return An unspecified reference type that can be used for parameter name specifying Chris@16: */ Chris@16: const_reference operator[] (const char* section_name) const { return const_reference(*this, section_name); } Chris@16: Chris@16: /*! Chris@16: * Accessor for the embedded property tree Chris@16: */ Chris@16: property_tree_type const& property_tree() const { return *m_ptree; } Chris@16: /*! Chris@16: * Accessor for the embedded property tree Chris@16: */ Chris@16: property_tree_type& property_tree() { return *m_ptree; } Chris@16: Chris@16: /*! Chris@16: * Checks if the specified section is present in the container. Chris@16: * Chris@16: * \param section_name The name of the section Chris@16: */ Chris@16: bool has_section(string_type const& section_name) const Chris@16: { Chris@16: return m_ptree != NULL && !!m_ptree->get_child_optional(section_name); Chris@16: } Chris@16: /*! Chris@16: * Checks if the specified parameter is present in the container. Chris@16: * Chris@16: * \param section_name The name of the section in which the parameter resides Chris@16: * \param param_name The name of the parameter Chris@16: */ Chris@16: bool has_parameter(string_type const& section_name, string_type const& param_name) const Chris@16: { Chris@16: if (m_ptree) Chris@16: { Chris@16: optional< property_tree_type& > section = m_ptree->get_child_optional(section_name); Chris@16: if (!!section) Chris@16: return (section->find(param_name) != section->not_found()); Chris@16: } Chris@16: Chris@16: return false; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Swaps two references to settings sections. Chris@16: */ Chris@16: void swap(basic_settings_section& that) Chris@16: { Chris@16: property_tree_type* const p = m_ptree; Chris@16: m_ptree = that.m_ptree; Chris@16: that.m_ptree = p; Chris@16: } Chris@16: Chris@16: protected: Chris@16: explicit basic_settings_section(property_tree_type* tree) : m_ptree(tree) Chris@16: { Chris@16: } Chris@16: }; Chris@16: Chris@16: template< typename CharT > Chris@16: inline void swap(basic_settings_section< CharT >& left, basic_settings_section< CharT >& right) Chris@16: { Chris@16: left.swap(right); Chris@16: } Chris@16: Chris@16: Chris@16: /*! Chris@16: * \brief The class represents settings container Chris@16: * Chris@16: * All settings are presented as a number of named parameters divided into named sections. Chris@16: * The parameters values are stored as strings. Individual parameters may be queried via subscript operators, like this: Chris@16: * Chris@16: *
Chris@16:  * optional< string > param = settings["Section1"]["Param1"]; // reads parameter "Param1" in section "Section1"
Chris@16:  *                                                            // returns an empty value if no such parameter exists
Chris@16:  * settings["Section2"]["Param2"] = 10; // sets the parameter "Param2" in section "Section2"
Chris@16:  *                                      // to value "10"
Chris@16:  * 
Chris@16: * Chris@16: * There are also other methods to work with parameters. Chris@16: */ Chris@16: template< typename CharT > Chris@16: class basic_settings : Chris@16: public basic_settings_section< CharT > Chris@16: { Chris@16: typedef basic_settings this_type; Chris@16: BOOST_COPYABLE_AND_MOVABLE(this_type) Chris@16: Chris@16: public: Chris@16: //! Section type Chris@16: typedef basic_settings_section< CharT > section; Chris@16: //! Property tree type Chris@16: typedef typename section::property_tree_type property_tree_type; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor. Creates an empty settings container. Chris@16: */ Chris@16: basic_settings() : section(new property_tree_type()) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Copy constructor. Chris@16: */ Chris@16: basic_settings(basic_settings const& that) : Chris@16: section(that.m_ptree ? new property_tree_type(*that.m_ptree) : static_cast< property_tree_type* >(NULL)) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Move constructor. Chris@16: */ Chris@16: basic_settings(BOOST_RV_REF(this_type) that) Chris@16: { Chris@16: this->swap(that); Chris@16: } Chris@16: /*! Chris@16: * Initializing constructor. Creates a settings container with the copy of the specified property tree. Chris@16: */ Chris@16: explicit basic_settings(property_tree_type const& tree) : section(new property_tree_type(tree)) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Destructor Chris@16: */ Chris@16: ~basic_settings() Chris@16: { Chris@16: delete this->m_ptree; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Copy assignment operator. Chris@16: */ Chris@16: basic_settings& operator= (BOOST_COPY_ASSIGN_REF(basic_settings) that) Chris@16: { Chris@16: if (this != &that) Chris@16: { Chris@16: basic_settings tmp = that; Chris@16: this->swap(tmp); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: /*! Chris@16: * Move assignment operator. Chris@16: */ Chris@16: basic_settings& operator= (BOOST_RV_REF(basic_settings) that) Chris@16: { Chris@16: this->swap(that); Chris@16: return *this; Chris@16: } Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_LOG_USE_CHAR Chris@16: typedef basic_settings< char > settings; //!< Convenience typedef for narrow-character logging Chris@16: typedef basic_settings_section< char > settings_section; //!< Convenience typedef for narrow-character logging Chris@16: #endif Chris@16: #ifdef BOOST_LOG_USE_WCHAR_T Chris@16: typedef basic_settings< wchar_t > wsettings; //!< Convenience typedef for wide-character logging Chris@16: typedef basic_settings_section< wchar_t > wsettings_section; //!< Convenience typedef for wide-character logging Chris@16: #endif Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_