644 lines
20 KiB
C++
644 lines
20 KiB
C++
/*
|
|
* 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 <cstddef>
|
|
#include <string>
|
|
#include <iterator>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/move/core.hpp>
|
|
#include <boost/mpl/if.hpp>
|
|
#include <boost/iterator/iterator_adaptor.hpp>
|
|
#include <boost/optional/optional.hpp>
|
|
#include <boost/property_tree/ptree.hpp>
|
|
#include <boost/log/detail/setup_config.hpp>
|
|
#include <boost/log/detail/native_typeof.hpp>
|
|
#include <boost/utility/explicit_operator_bool.hpp>
|
|
#if !defined(BOOST_LOG_TYPEOF)
|
|
#include <boost/core/enable_if.hpp>
|
|
#endif
|
|
#if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
|
|
#include <boost/utility/declval.hpp>
|
|
#endif
|
|
#include <boost/log/detail/header.hpp>
|
|
|
|
#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:
|
|
*
|
|
* <code><pre>
|
|
* 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"
|
|
* </pre></code>
|
|
*
|
|
* 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 <boost/log/detail/footer.hpp>
|
|
|
|
#endif // BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_
|