Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/log/sinks/basic_sink_frontend.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/log/sinks/basic_sink_frontend.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,523 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * 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 basic_sink_frontend.hpp + * \author Andrey Semashev + * \date 14.07.2009 + * + * The header contains implementation of a base class for sink frontends. + */ + +#ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_ +#define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_ + +#include <boost/mpl/bool.hpp> +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/cleanup_scope_guard.hpp> +#include <boost/log/detail/code_conversion.hpp> +#include <boost/log/detail/attachable_sstream_buf.hpp> +#include <boost/log/detail/fake_mutex.hpp> +#include <boost/log/core/record_view.hpp> +#include <boost/log/sinks/sink.hpp> +#include <boost/log/sinks/frontend_requirements.hpp> +#include <boost/log/expressions/filter.hpp> +#include <boost/log/expressions/formatter.hpp> +#if !defined(BOOST_LOG_NO_THREADS) +#include <boost/thread/exceptions.hpp> +#include <boost/thread/tss.hpp> +#include <boost/thread/locks.hpp> +#include <boost/log/detail/locks.hpp> +#include <boost/log/detail/light_rw_mutex.hpp> +#include <boost/concept_check.hpp> +#endif // !defined(BOOST_LOG_NO_THREADS) +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace sinks { + +//! A base class for a logging sink frontend +class BOOST_LOG_NO_VTABLE basic_sink_frontend : + public sink +{ + //! Base type + typedef sink base_type; + +public: + //! An exception handler type + typedef base_type::exception_handler_type exception_handler_type; + +#if !defined(BOOST_LOG_NO_THREADS) +protected: + //! Mutex type + typedef boost::log::aux::light_rw_mutex mutex_type; + +private: + //! Synchronization mutex + mutable mutex_type m_Mutex; +#endif + +private: + //! Filter + filter m_Filter; + //! Exception handler + exception_handler_type m_ExceptionHandler; + +public: + /*! + * \brief Initializing constructor + * + * \param cross_thread The flag indicates whether the sink passes log records between different threads + */ + explicit basic_sink_frontend(bool cross_thread) : sink(cross_thread) + { + } + + /*! + * The method sets sink-specific filter functional object + */ + template< typename FunT > + void set_filter(FunT const& filter) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + m_Filter = filter; + } + /*! + * The method resets the filter + */ + void reset_filter() + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + m_Filter.reset(); + } + + /*! + * The method sets an exception handler function + */ + template< typename FunT > + void set_exception_handler(FunT const& handler) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + m_ExceptionHandler = handler; + } + + /*! + * The method resets the exception handler function + */ + void reset_exception_handler() + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + m_ExceptionHandler.clear(); + } + + /*! + * The method returns \c true if no filter is set or the attribute values pass the filter + * + * \param attrs A set of attribute values of a logging record + */ + bool will_consume(attribute_value_set const& attrs) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) + try + { + return m_Filter(attrs); + } +#if !defined(BOOST_LOG_NO_THREADS) + catch (thread_interrupted&) + { + throw; + } +#endif + catch (...) + { + if (m_ExceptionHandler.empty()) + throw; + m_ExceptionHandler(); + return false; + } + } + +protected: +#if !defined(BOOST_LOG_NO_THREADS) + //! Returns reference to the frontend mutex + mutex_type& frontend_mutex() const { return m_Mutex; } +#endif + + //! Returns reference to the exception handler + exception_handler_type& exception_handler() { return m_ExceptionHandler; } + //! Returns reference to the exception handler + exception_handler_type const& exception_handler() const { return m_ExceptionHandler; } + + //! Feeds log record to the backend + template< typename BackendMutexT, typename BackendT > + void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend) + { + try + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) + backend.consume(rec); + } +#if !defined(BOOST_LOG_NO_THREADS) + catch (thread_interrupted&) + { + throw; + } +#endif + catch (...) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) + if (m_ExceptionHandler.empty()) + throw; + m_ExceptionHandler(); + } + } + + //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked + template< typename BackendMutexT, typename BackendT > + bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend) + { +#if !defined(BOOST_LOG_NO_THREADS) + unique_lock< BackendMutexT > lock; + try + { + unique_lock< BackendMutexT > tmp_lock(backend_mutex, try_to_lock); + if (!tmp_lock.owns_lock()) + return false; + lock.swap(tmp_lock); + } + catch (thread_interrupted&) + { + throw; + } + catch (...) + { + boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); + if (this->exception_handler().empty()) + throw; + this->exception_handler()(); + } +#endif + // No need to lock anything in the feed_record method + boost::log::aux::fake_mutex m; + feed_record(rec, m, backend); + return true; + } + + //! Flushes record buffers in the backend, if one supports it + template< typename BackendMutexT, typename BackendT > + void flush_backend(BackendMutexT& backend_mutex, BackendT& backend) + { + typedef typename BackendT::frontend_requirements frontend_requirements; + flush_backend_impl(backend_mutex, backend, + typename has_requirement< frontend_requirements, flushing >::type()); + } + +private: + //! Flushes record buffers in the backend (the actual implementation) + template< typename BackendMutexT, typename BackendT > + void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, mpl::true_) + { + try + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) + backend.flush(); + } +#if !defined(BOOST_LOG_NO_THREADS) + catch (thread_interrupted&) + { + throw; + } +#endif + catch (...) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) + if (m_ExceptionHandler.empty()) + throw; + m_ExceptionHandler(); + } + } + //! Flushes record buffers in the backend (stub for backends that don't support flushing) + template< typename BackendMutexT, typename BackendT > + void flush_backend_impl(BackendMutexT&, BackendT&, mpl::false_) + { + } +}; + +//! A base class for a logging sink frontend with formatting support +template< typename CharT > +class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : + public basic_sink_frontend +{ + typedef basic_sink_frontend base_type; + +public: + //! Character type + typedef CharT char_type; + //! Formatted string type + typedef std::basic_string< char_type > string_type; + + //! Formatter function object type + typedef basic_formatter< char_type > formatter_type; + //! Output stream type + typedef typename formatter_type::stream_type stream_type; + +#if !defined(BOOST_LOG_NO_THREADS) +protected: + //! Mutex type + typedef typename base_type::mutex_type mutex_type; +#endif + +private: + struct formatting_context + { +#if !defined(BOOST_LOG_NO_THREADS) + //! Object version + const unsigned int m_Version; +#endif + //! Formatted log record storage + string_type m_FormattedRecord; + //! Formatting stream + stream_type m_FormattingStream; + //! Formatter functor + formatter_type m_Formatter; + + formatting_context() : +#if !defined(BOOST_LOG_NO_THREADS) + m_Version(0), +#endif + m_FormattingStream(m_FormattedRecord) + { + m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); + } +#if !defined(BOOST_LOG_NO_THREADS) + formatting_context(unsigned int version, std::locale const& loc, formatter_type const& formatter) : + m_Version(version), + m_FormattingStream(m_FormattedRecord), + m_Formatter(formatter) + { + m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); + m_FormattingStream.imbue(loc); + } +#endif + }; + +private: +#if !defined(BOOST_LOG_NO_THREADS) + + //! State version + volatile unsigned int m_Version; + + //! Formatter functor + formatter_type m_Formatter; + //! Locale to perform formatting + std::locale m_Locale; + + //! Formatting state + thread_specific_ptr< formatting_context > m_pContext; + +#else + + //! Formatting state + formatting_context m_Context; + +#endif // !defined(BOOST_LOG_NO_THREADS) + +public: + /*! + * \brief Initializing constructor + * + * \param cross_thread The flag indicates whether the sink passes log records between different threads + */ + explicit basic_formatting_sink_frontend(bool cross_thread) : + basic_sink_frontend(cross_thread) +#if !defined(BOOST_LOG_NO_THREADS) + , m_Version(0) +#endif + { + } + + /*! + * The method sets sink-specific formatter function object + */ + template< typename FunT > + void set_formatter(FunT const& formatter) + { +#if !defined(BOOST_LOG_NO_THREADS) + boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); + m_Formatter = formatter; + ++m_Version; +#else + m_Context.m_Formatter = formatter; +#endif + } + /*! + * The method resets the formatter + */ + void reset_formatter() + { +#if !defined(BOOST_LOG_NO_THREADS) + boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); + m_Formatter.reset(); + ++m_Version; +#else + m_Context.m_Formatter.reset(); +#endif + } + + /*! + * The method returns the current locale used for formatting + */ + std::locale getloc() const + { +#if !defined(BOOST_LOG_NO_THREADS) + boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); + return m_Locale; +#else + return m_Context.m_FormattingStream.getloc(); +#endif + } + /*! + * The method sets the locale used for formatting + */ + void imbue(std::locale const& loc) + { +#if !defined(BOOST_LOG_NO_THREADS) + boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); + m_Locale = loc; + ++m_Version; +#else + m_Context.m_FormattingStream.imbue(loc); +#endif + } + +protected: + //! Returns reference to the formatter + formatter_type& formatter() + { +#if !defined(BOOST_LOG_NO_THREADS) + return m_Formatter; +#else + return m_Context.m_Formatter; +#endif + } + + //! Feeds log record to the backend + template< typename BackendMutexT, typename BackendT > + void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend) + { + formatting_context* context; + +#if !defined(BOOST_LOG_NO_THREADS) + context = m_pContext.get(); + if (!context || context->m_Version != m_Version) + { + { + boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex()); + context = new formatting_context(m_Version, m_Locale, m_Formatter); + } + m_pContext.reset(context); + } +#else + context = &m_Context; +#endif + + boost::log::aux::cleanup_guard< stream_type > cleanup1(context->m_FormattingStream); + boost::log::aux::cleanup_guard< string_type > cleanup2(context->m_FormattedRecord); + + try + { + // Perform the formatting + context->m_Formatter(rec, context->m_FormattingStream); + context->m_FormattingStream.flush(); + + // Feed the record + BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) + backend.consume(rec, context->m_FormattedRecord); + } +#if !defined(BOOST_LOG_NO_THREADS) + catch (thread_interrupted&) + { + throw; + } +#endif + catch (...) + { + BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());) + if (this->exception_handler().empty()) + throw; + this->exception_handler()(); + } + } + + //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked + template< typename BackendMutexT, typename BackendT > + bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend) + { +#if !defined(BOOST_LOG_NO_THREADS) + unique_lock< BackendMutexT > lock; + try + { + unique_lock< BackendMutexT > tmp_lock(backend_mutex, try_to_lock); + if (!tmp_lock.owns_lock()) + return false; + lock.swap(tmp_lock); + } + catch (thread_interrupted&) + { + throw; + } + catch (...) + { + boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); + if (this->exception_handler().empty()) + throw; + this->exception_handler()(); + } +#endif + // No need to lock anything in the feed_record method + boost::log::aux::fake_mutex m; + feed_record(rec, m, backend); + return true; + } +}; + +namespace aux { + + template< + typename BackendT, + bool RequiresFormattingV = has_requirement< + typename BackendT::frontend_requirements, + formatted_records + >::value + > + struct make_sink_frontend_base + { + typedef basic_sink_frontend type; + }; + template< typename BackendT > + struct make_sink_frontend_base< BackendT, true > + { + typedef basic_formatting_sink_frontend< typename BackendT::char_type > type; + }; + +} // namespace aux + +} // namespace sinks + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_