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