diff options
Diffstat (limited to 'boost/log')
77 files changed, 3440 insertions, 390 deletions
diff --git a/boost/log/attributes/attribute_value_impl.hpp b/boost/log/attributes/attribute_value_impl.hpp index b21091e58b..e18015bec3 100644 --- a/boost/log/attributes/attribute_value_impl.hpp +++ b/boost/log/attributes/attribute_value_impl.hpp @@ -17,7 +17,7 @@ #include <boost/type_index.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/type_traits/remove_cv.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/attributes/attribute_value.hpp> diff --git a/boost/log/attributes/constant.hpp b/boost/log/attributes/constant.hpp index 1e9a036176..f10b0a7e5b 100644 --- a/boost/log/attributes/constant.hpp +++ b/boost/log/attributes/constant.hpp @@ -16,7 +16,7 @@ #define BOOST_LOG_ATTRIBUTES_CONSTANT_HPP_INCLUDED_ #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/embedded_string_type.hpp> diff --git a/boost/log/attributes/mutable_constant.hpp b/boost/log/attributes/mutable_constant.hpp index 52356b45de..6ff76ddc2c 100644 --- a/boost/log/attributes/mutable_constant.hpp +++ b/boost/log/attributes/mutable_constant.hpp @@ -19,7 +19,7 @@ #include <boost/smart_ptr/intrusive_ptr.hpp> #include <boost/mpl/if.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/type_traits/is_void.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/locks.hpp> diff --git a/boost/log/attributes/scoped_attribute.hpp b/boost/log/attributes/scoped_attribute.hpp index bd0e52da7f..88dd218e4c 100644 --- a/boost/log/attributes/scoped_attribute.hpp +++ b/boost/log/attributes/scoped_attribute.hpp @@ -17,8 +17,8 @@ #include <utility> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/core/addressof.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/core/core.hpp> #include <boost/log/sources/basic_logger.hpp> diff --git a/boost/log/attributes/value_extraction.hpp b/boost/log/attributes/value_extraction.hpp index 7ec3f1d174..87fd1495e3 100644 --- a/boost/log/attributes/value_extraction.hpp +++ b/boost/log/attributes/value_extraction.hpp @@ -25,7 +25,7 @@ #include <boost/mpl/contains.hpp> #include <boost/mpl/push_back.hpp> #include <boost/type_traits/is_same.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/exceptions.hpp> #include <boost/log/core/record.hpp> @@ -137,14 +137,14 @@ private: //! The function unwraps \c value_ref, if possible template< typename T, typename TagT > -BOOST_FORCEINLINE typename enable_if< mpl::is_sequence< T >, value_ref< T, TagT > >::type +BOOST_FORCEINLINE typename boost::enable_if_c< mpl::is_sequence< T >::value, value_ref< T, TagT > >::type unwrap_value_ref(value_ref< T, TagT > const& r) { return r; } template< typename T, typename TagT > -BOOST_FORCEINLINE typename disable_if< mpl::is_sequence< T >, T const& >::type +BOOST_FORCEINLINE typename boost::disable_if_c< mpl::is_sequence< T >::value, T const& >::type unwrap_value_ref(value_ref< T, TagT > const& r) { return r.get(); diff --git a/boost/log/core/record.hpp b/boost/log/core/record.hpp index b58177c58a..b666214c61 100644 --- a/boost/log/core/record.hpp +++ b/boost/log/core/record.hpp @@ -55,6 +55,10 @@ private: //! A pointer to the log record implementation public_data* m_impl; +private: + // A private constructor, accessible from core + BOOST_CONSTEXPR explicit record(public_data* impl) BOOST_NOEXCEPT : m_impl(impl) {} + #endif // BOOST_LOG_DOXYGEN_PASS public: @@ -63,7 +67,7 @@ public: * * \post <tt>!*this == true</tt> */ - record() : m_impl(NULL) {} + BOOST_CONSTEXPR record() BOOST_NOEXCEPT : m_impl(NULL) {} /*! * Move constructor. Source record contents unspecified after the operation. diff --git a/boost/log/core/record_view.hpp b/boost/log/core/record_view.hpp index 6fa7a63f98..515627aebd 100644 --- a/boost/log/core/record_view.hpp +++ b/boost/log/core/record_view.hpp @@ -17,6 +17,7 @@ #include <boost/smart_ptr/intrusive_ptr.hpp> #include <boost/move/core.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/utility/explicit_operator_bool.hpp> #include <boost/log/attributes/attribute_value_set.hpp> @@ -72,10 +73,10 @@ private: //! Attribute values view attribute_value_set m_attribute_values; - //! Constructor from the attribute sets - explicit public_data(BOOST_RV_REF(attribute_value_set) values) : + //! Constructor from the attribute value set + explicit public_data(BOOST_RV_REF(attribute_value_set) values) BOOST_NOEXCEPT : m_ref_counter(1), - m_attribute_values(values) + m_attribute_values(boost::move(values)) { } @@ -98,7 +99,7 @@ private: private: // A private constructor, accessible from record - explicit record_view(public_data* impl) : m_impl(impl, false) {} + explicit record_view(public_data* impl) BOOST_NOEXCEPT : m_impl(impl, false) {} #endif // BOOST_LOG_DOXYGEN_PASS @@ -108,7 +109,12 @@ public: * * \post <tt>!*this == true</tt> */ - BOOST_DEFAULTED_FUNCTION(record_view(), {}) + BOOST_CONSTEXPR record_view() BOOST_NOEXCEPT +#if !defined(BOOST_LOG_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS) + = default; +#else + {} +#endif /*! * Copy constructor diff --git a/boost/log/detail/adaptive_mutex.hpp b/boost/log/detail/adaptive_mutex.hpp index 25e7559e17..f9830effde 100644 --- a/boost/log/detail/adaptive_mutex.hpp +++ b/boost/log/detail/adaptive_mutex.hpp @@ -37,19 +37,11 @@ #if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI) +#include <boost/log/detail/pause.hpp> #include <boost/detail/interlocked.hpp> #include <boost/detail/winapi/thread.hpp> #if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# if defined(_M_IX86) -# define BOOST_LOG_PAUSE_OP __asm { pause } -# elif defined(_M_AMD64) -extern "C" void _mm_pause(void); -# if defined(BOOST_MSVC) -# pragma intrinsic(_mm_pause) -# endif -# define BOOST_LOG_PAUSE_OP _mm_pause() -# endif # if defined(__INTEL_COMPILER) # define BOOST_LOG_COMPILER_BARRIER __memory_barrier() # else @@ -60,7 +52,6 @@ extern "C" void _ReadWriteBarrier(void); # define BOOST_LOG_COMPILER_BARRIER _ReadWriteBarrier() # endif #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# define BOOST_LOG_PAUSE_OP __asm__ __volatile__("pause;") # define BOOST_LOG_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory") #endif @@ -94,17 +85,17 @@ public: void lock() { -#if defined(BOOST_LOG_PAUSE_OP) +#if defined(BOOST_LOG_AUX_PAUSE) unsigned int pause_count = initial_pause; #endif while (!try_lock()) { -#if defined(BOOST_LOG_PAUSE_OP) +#if defined(BOOST_LOG_AUX_PAUSE) if (pause_count < max_pause) { for (unsigned int i = 0; i < pause_count; ++i) { - BOOST_LOG_PAUSE_OP; + BOOST_LOG_AUX_PAUSE; } pause_count += pause_count; } @@ -136,7 +127,7 @@ public: BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&)) }; -#undef BOOST_LOG_PAUSE_OP +#undef BOOST_LOG_AUX_PAUSE #undef BOOST_LOG_COMPILER_BARRIER } // namespace aux diff --git a/boost/log/detail/attachable_sstream_buf.hpp b/boost/log/detail/attachable_sstream_buf.hpp index ae536a4316..3608bb1083 100644 --- a/boost/log/detail/attachable_sstream_buf.hpp +++ b/boost/log/detail/attachable_sstream_buf.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2016. * 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) @@ -16,11 +16,14 @@ #ifndef BOOST_LOG_ATTACHABLE_SSTREAM_BUF_HPP_INCLUDED_ #define BOOST_LOG_ATTACHABLE_SSTREAM_BUF_HPP_INCLUDED_ +#include <cstddef> #include <memory> +#include <locale> #include <string> #include <streambuf> #include <boost/assert.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/locale/utf.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/header.hpp> @@ -58,66 +61,196 @@ public: typedef typename base_type::traits_type traits_type; //! String type typedef std::basic_string< char_type, traits_type, AllocatorT > string_type; + //! Size type + typedef typename string_type::size_type size_type; //! Int type typedef typename base_type::int_type int_type; + struct storage_state + { + //! A reference to the string that will be filled + string_type* storage; + //! Max size of the storage, in characters + size_type max_size; + //! Indicates that storage overflow happened + bool overflow; + + BOOST_CONSTEXPR storage_state() BOOST_NOEXCEPT : storage(NULL), max_size(0u), overflow(false) + { + } + }; + private: - //! A reference to the string that will be filled - string_type* m_Storage; + //! Buffer storage state + storage_state m_storage_state; //! A buffer used to temporarily store output - char_type m_Buffer[buffer_size]; + char_type m_buffer[buffer_size]; public: //! Constructor - explicit basic_ostringstreambuf() : m_Storage(0) + basic_ostringstreambuf() BOOST_NOEXCEPT { - base_type::setp(m_Buffer, m_Buffer + (sizeof(m_Buffer) / sizeof(*m_Buffer))); + base_type::setp(m_buffer, m_buffer + (sizeof(m_buffer) / sizeof(*m_buffer))); } //! Constructor - explicit basic_ostringstreambuf(string_type& storage) : m_Storage(boost::addressof(storage)) + explicit basic_ostringstreambuf(string_type& storage) BOOST_NOEXCEPT { - base_type::setp(m_Buffer, m_Buffer + (sizeof(m_Buffer) / sizeof(*m_Buffer))); + base_type::setp(m_buffer, m_buffer + (sizeof(m_buffer) / sizeof(*m_buffer))); + attach(storage); } - //! Clears the buffer to the initial state - void clear() - { - char_type* pBase = this->pbase(); - char_type* pPtr = this->pptr(); - if (pBase != pPtr) - this->pbump(static_cast< int >(pBase - pPtr)); - } + storage_state const& get_storage_state() const BOOST_NOEXCEPT { return m_storage_state; } + void set_storage_state(storage_state const& st) BOOST_NOEXCEPT { m_storage_state = st; } //! Detaches the buffer from the string void detach() { - if (m_Storage) + if (m_storage_state.storage) { this_type::sync(); - m_Storage = 0; + m_storage_state.storage = NULL; + m_storage_state.max_size = 0u; + m_storage_state.overflow = false; } } //! Attaches the buffer to another string void attach(string_type& storage) { + attach(storage, storage.max_size()); + } + + //! Attaches the buffer to another string + void attach(string_type& storage, size_type max_size) + { detach(); - m_Storage = boost::addressof(storage); + m_storage_state.storage = &storage; + this->max_size(max_size); } //! Returns a pointer to the attached string - string_type* storage() const { return m_Storage; } + string_type* storage() const BOOST_NOEXCEPT { return m_storage_state.storage; } + + //! Returns the maximum size of the storage + size_type max_size() const BOOST_NOEXCEPT { return m_storage_state.max_size; } + //! Sets the maximum size of the storage + void max_size(size_type size) + { + if (m_storage_state.storage) + { + const size_type storage_max_size = m_storage_state.storage->max_size(); + size = size > storage_max_size ? storage_max_size : size; + } + + m_storage_state.max_size = size; + ensure_max_size(); + } + //! Makes sure the storage does not exceed the max size limit. Should be called after the storage is modified externally. + void ensure_max_size() + { + if (m_storage_state.storage && m_storage_state.storage->size() > m_storage_state.max_size) + { + const size_type len = length_until_boundary(m_storage_state.storage->c_str(), m_storage_state.storage->size(), m_storage_state.max_size); + m_storage_state.storage->resize(len); + m_storage_state.overflow = true; + } + } + + //! Returns true if the max size limit has been exceeded + bool storage_overflow() const BOOST_NOEXCEPT { return m_storage_state.overflow; } + //! Sets the overflow flag + void storage_overflow(bool f) BOOST_NOEXCEPT { m_storage_state.overflow = f; } + + //! Returns the size left in the storage + size_type size_left() const BOOST_NOEXCEPT + { + BOOST_ASSERT(m_storage_state.storage != NULL); + + const size_type size = m_storage_state.storage->size(); + return size < m_storage_state.max_size ? m_storage_state.max_size - size : static_cast< size_type >(0u); + } + + //! Appends a string to the storage and returns the number of written characters + size_type append(const char_type* s, size_type n) + { + if (!m_storage_state.overflow) + { + BOOST_ASSERT(m_storage_state.storage != NULL); + + size_type left = size_left(); + BOOST_LOG_ASSUME(left <= m_storage_state.storage->max_size()); + if (BOOST_LIKELY(n <= left)) + { + m_storage_state.storage->append(s, n); + return n; + } + else + { + // We have to find out where the last character that fits before the limit ends + left = length_until_boundary(s, n, left); + m_storage_state.storage->append(s, left); + m_storage_state.overflow = true; + return left; + } + } + return 0u; + } + + //! Appends the specified number of characters to the storage and returns the number of written characters + size_type append(size_type n, char_type c) + { + if (!m_storage_state.overflow) + { + BOOST_ASSERT(m_storage_state.storage != NULL); + + const size_type left = size_left(); + BOOST_LOG_ASSUME(left <= m_storage_state.storage->max_size()); + if (BOOST_LIKELY(n <= left)) + { + m_storage_state.storage->append(n, c); + return n; + } + else + { + m_storage_state.storage->append(left, c); + m_storage_state.overflow = true; + return left; + } + } + return 0u; + } + + //! Appends a character to the storage and returns the number of written characters + size_type push_back(char_type c) + { + if (!m_storage_state.overflow) + { + BOOST_ASSERT(m_storage_state.storage != NULL); + + BOOST_LOG_ASSUME(m_storage_state.max_size <= m_storage_state.storage->max_size()); + if (BOOST_LIKELY(m_storage_state.storage->size() < m_storage_state.max_size)) + { + m_storage_state.storage->push_back(c); + return 1u; + } + else + { + m_storage_state.overflow = true; + return 0u; + } + } + return 0u; + } protected: //! Puts all buffered data to the string int sync() { - BOOST_ASSERT(m_Storage != 0); char_type* pBase = this->pbase(); char_type* pPtr = this->pptr(); if (pBase != pPtr) { - m_Storage->append(pBase, pPtr); + this->append(pBase, static_cast< size_type >(pPtr - pBase)); this->pbump(static_cast< int >(pBase - pPtr)); } return 0; @@ -125,11 +258,10 @@ protected: //! Puts an unbuffered character to the string int_type overflow(int_type c) { - BOOST_ASSERT(m_Storage != 0); - basic_ostringstreambuf::sync(); + this_type::sync(); if (!traits_type::eq_int_type(c, traits_type::eof())) { - m_Storage->push_back(traits_type::to_char_type(c)); + this->push_back(traits_type::to_char_type(c)); return c; } else @@ -138,21 +270,47 @@ protected: //! Puts a character sequence to the string std::streamsize xsputn(const char_type* s, std::streamsize n) { - BOOST_ASSERT(m_Storage != 0); - basic_ostringstreambuf::sync(); - typedef typename string_type::size_type string_size_type; - const string_size_type max_storage_left = - m_Storage->max_size() - m_Storage->size(); - if (static_cast< string_size_type >(n) < max_storage_left) - { - m_Storage->append(s, static_cast< string_size_type >(n)); - return n; - } - else + this_type::sync(); + return static_cast< std::streamsize >(this->append(s, static_cast< size_type >(n))); + } + + //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size + size_type length_until_boundary(const char_type* s, size_type n, size_type max_size) const + { + return length_until_boundary(s, n, max_size, mpl::bool_< sizeof(char_type) == 1u >());; + } + + //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size + size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, mpl::true_) const + { + std::locale loc = this->getloc(); + std::codecvt< wchar_t, char, std::mbstate_t > const& fac = std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc); + std::mbstate_t mbs = std::mbstate_t(); + return static_cast< size_type >(fac.length(mbs, s, s + max_size, ~static_cast< std::size_t >(0u))); + } + + //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size + static size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, mpl::false_) + { + // Note: Although it's not required to be true for wchar_t, here we assume that the string has Unicode encoding. + // Compilers use some version of Unicode for wchar_t on all tested platforms, and std::locale doesn't offer a way + // to find the character boundary for character types other than char anyway. + typedef boost::locale::utf::utf_traits< CharT > utf_traits; + + size_type pos = max_size; + while (pos > 0u) { - m_Storage->append(s, max_storage_left); - return static_cast< std::streamsize >(max_storage_left); + --pos; + if (utf_traits::is_lead(s[pos])) + { + const char_type* p = s + pos; + boost::locale::utf::code_point cp = utf_traits::decode(p, s + n); + if (boost::locale::utf::is_valid_codepoint(cp) && p <= (s + max_size)) + return static_cast< size_type >(p - s); + } } + + return 0u; } //! Copy constructor (closed) diff --git a/boost/log/detail/c_str.hpp b/boost/log/detail/c_str.hpp new file mode 100644 index 0000000000..049d1c389e --- /dev/null +++ b/boost/log/detail/c_str.hpp @@ -0,0 +1,55 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 c_str.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#ifndef BOOST_LOG_DETAIL_C_STR_HPP_INCLUDED_ +#define BOOST_LOG_DETAIL_C_STR_HPP_INCLUDED_ + +#include <string> +#include <boost/core/enable_if.hpp> +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/is_character_type.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +template< typename T > +inline typename boost::enable_if_c< is_character_type< T >::value, const T* >::type c_str(const T* str) BOOST_NOEXCEPT +{ + return str; +} + +template< typename T, typename TraitsT, typename AllocatorT > +inline typename boost::enable_if_c< is_character_type< T >::value, const T* >::type c_str(std::basic_string< T, TraitsT, AllocatorT > const& str) BOOST_NOEXCEPT +{ + return str.c_str(); +} + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_DETAIL_C_STR_HPP_INCLUDED_ diff --git a/boost/log/detail/code_conversion.hpp b/boost/log/detail/code_conversion.hpp index 86cdfd8800..b39970d022 100644 --- a/boost/log/detail/code_conversion.hpp +++ b/boost/log/detail/code_conversion.hpp @@ -38,64 +38,99 @@ namespace aux { // type. These conversions are used in sinks, e.g. to convert multibyte strings to wide-character filesystem paths. //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc = std::locale()); #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS) #if !defined(BOOST_NO_CXX11_CHAR16_T) //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc = std::locale()); #endif #if !defined(BOOST_NO_CXX11_CHAR32_T) //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc = std::locale()); #endif #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T) //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc = std::locale()); //! The function converts one string to the character type of another -BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::locale const& loc = std::locale()); +BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc = std::locale()); #endif #endif // !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS) //! The function converts one string to the character type of another +template< typename SourceCharT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT), bool >::type +code_convert(const SourceCharT* str1, std::size_t len, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::size_t max_size, std::locale const& = std::locale()) +{ + std::size_t size_left = str2.size() < max_size ? max_size - str2.size() : static_cast< std::size_t >(0u); + const bool overflow = len > size_left; + str2.append(reinterpret_cast< const TargetCharT* >(str1), overflow ? size_left : len); + return !overflow; +} + +//! The function converts one string to the character type of another template< typename SourceCharT, typename SourceTraitsT, typename SourceAllocatorT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > -inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT) >::type -code_convert(std::basic_string< SourceCharT, SourceTraitsT, SourceAllocatorT > const& str1, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& = std::locale()) +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT), bool >::type +code_convert(std::basic_string< SourceCharT, SourceTraitsT, SourceAllocatorT > const& str1, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::size_t max_size, std::locale const& loc = std::locale()) +{ + return aux::code_convert(str1.data(), str1.size(), str2, max_size, loc); +} + +//! The function converts one string to the character type of another +template< typename SourceCharT, typename SourceTraitsT, typename SourceAllocatorT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT), bool >::type +code_convert(std::basic_string< SourceCharT, SourceTraitsT, SourceAllocatorT > const& str1, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& loc = std::locale()) { - str2.append(reinterpret_cast< const TargetCharT* >(str1.c_str()), str1.size()); + return aux::code_convert(str1.data(), str1.size(), str2, str2.max_size(), loc); } //! The function converts one string to the character type of another template< typename SourceCharT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > -inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT) >::type -code_convert(const SourceCharT* str1, std::size_t len, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& = std::locale()) +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) == sizeof(TargetCharT), bool >::type +code_convert(const SourceCharT* str1, std::size_t len, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& loc = std::locale()) { - str2.append(reinterpret_cast< const TargetCharT* >(str1), len); + return aux::code_convert(str1, len, str2, str2.max_size(), loc); } //! The function converts one string to the character type of another template< typename SourceCharT, typename SourceTraitsT, typename SourceAllocatorT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > -inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT) >::type +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT), bool >::type code_convert(std::basic_string< SourceCharT, SourceTraitsT, SourceAllocatorT > const& str1, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& loc = std::locale()) { - aux::code_convert_impl(str1.c_str(), str1.size(), str2, loc); + return aux::code_convert_impl(str1.c_str(), str1.size(), str2, str2.max_size(), loc); } //! The function converts one string to the character type of another template< typename SourceCharT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > -inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT) >::type +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT), bool >::type code_convert(const SourceCharT* str1, std::size_t len, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::locale const& loc = std::locale()) { - aux::code_convert_impl(str1, len, str2, loc); + return aux::code_convert_impl(str1, len, str2, str2.max_size(), loc); +} + +//! The function converts one string to the character type of another +template< typename SourceCharT, typename SourceTraitsT, typename SourceAllocatorT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT), bool >::type +code_convert(std::basic_string< SourceCharT, SourceTraitsT, SourceAllocatorT > const& str1, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::size_t max_size, std::locale const& loc = std::locale()) +{ + return aux::code_convert_impl(str1.c_str(), str1.size(), str2, max_size, loc); +} + +//! The function converts one string to the character type of another +template< typename SourceCharT, typename TargetCharT, typename TargetTraitsT, typename TargetAllocatorT > +inline typename boost::enable_if_c< is_character_type< SourceCharT >::value && is_character_type< TargetCharT >::value && sizeof(SourceCharT) != sizeof(TargetCharT), bool >::type +code_convert(const SourceCharT* str1, std::size_t len, std::basic_string< TargetCharT, TargetTraitsT, TargetAllocatorT >& str2, std::size_t max_size, std::locale const& loc = std::locale()) +{ + return aux::code_convert_impl(str1, len, str2, max_size, loc); } //! The function converts the passed string to the narrow-character encoding @@ -114,8 +149,8 @@ inline std::string const& to_narrow(std::string const& str, std::locale const&) inline std::string to_narrow(std::wstring const& str, std::locale const& loc = std::locale()) { std::string res; - aux::code_convert_impl(str.c_str(), str.size(), res, loc); -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + aux::code_convert_impl(str.c_str(), str.size(), res, res.max_size(), loc); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_HAS_NRVO) return static_cast< std::string&& >(res); #else return res; @@ -138,8 +173,8 @@ inline std::wstring const& to_wide(std::wstring const& str, std::locale const&) inline std::wstring to_wide(std::string const& str, std::locale const& loc = std::locale()) { std::wstring res; - aux::code_convert_impl(str.c_str(), str.size(), res, loc); -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + aux::code_convert_impl(str.c_str(), str.size(), res, res.max_size(), loc); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_HAS_NRVO) return static_cast< std::wstring&& >(res); #else return res; diff --git a/boost/log/detail/config.hpp b/boost/log/detail/config.hpp index ce9aeb2dc1..7265d2b6e4 100644 --- a/boost/log/detail/config.hpp +++ b/boost/log/detail/config.hpp @@ -134,6 +134,16 @@ #define BOOST_LOG_NO_CXX11_ARG_PACKS_TO_NON_VARIADIC_ARGS_EXPANSION #endif +#if defined(BOOST_NO_CXX11_CONSTEXPR) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) +// GCC 4.6 does not support in-class brace initializers for static constexpr array members +#define BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS +#endif + +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) +// GCC 4.6 cannot handle a defaulted function with noexcept specifier +#define BOOST_LOG_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS +#endif + #if defined(_MSC_VER) # define BOOST_LOG_NO_VTABLE __declspec(novtable) #elif defined(__GNUC__) @@ -168,6 +178,14 @@ # define BOOST_LOG_UNREACHABLE_RETURN(r) BOOST_LOG_UNREACHABLE() #endif +// The macro efficiently returns a local lvalue from a function. +// It employs NRVO, if supported by compiler, or uses a move constructor otherwise. +#if defined(BOOST_HAS_NRVO) +#define BOOST_LOG_NRVO_RESULT(x) x +#else +#define BOOST_LOG_NRVO_RESULT(x) boost::move(x) +#endif + // Some compilers support a special attribute that shows that a function won't return #if defined(__GNUC__) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) // GCC and Sun Studio 12 support attribute syntax diff --git a/boost/log/detail/decomposed_time.hpp b/boost/log/detail/decomposed_time.hpp index 6008d6a798..0328106edc 100644 --- a/boost/log/detail/decomposed_time.hpp +++ b/boost/log/detail/decomposed_time.hpp @@ -25,6 +25,7 @@ #include <boost/range/iterator_range_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/date_time_format_parser.hpp> +#include <boost/log/detail/attachable_sstream_buf.hpp> #include <boost/log/utility/formatting_ostream.hpp> #include <boost/log/detail/header.hpp> @@ -108,7 +109,7 @@ struct decomposed_time_wrapper : }; template< typename CharT > -BOOST_LOG_API void put_integer(std::basic_string< CharT >& str, uint32_t value, unsigned int width, CharT fill_char); +BOOST_LOG_API void put_integer(boost::log::aux::basic_ostringstreambuf< CharT >& strbuf, uint32_t value, unsigned int width, CharT fill_char); template< typename T, typename CharT > class date_time_formatter @@ -130,14 +131,12 @@ public: { date_time_formatter const& self; stream_type& strm; - string_type& str; value_type const& value; unsigned int literal_index, literal_pos; context(date_time_formatter const& self_, stream_type& strm_, value_type const& value_) : self(self_), strm(strm_), - str(*strm_.rdbuf()->storage()), value(value_), literal_index(0), literal_pos(0) @@ -166,12 +165,12 @@ public: m_literal_chars(that.m_literal_chars) { } - date_time_formatter(BOOST_RV_REF(date_time_formatter) that) + date_time_formatter(BOOST_RV_REF(date_time_formatter) that) BOOST_NOEXCEPT { this->swap(static_cast< date_time_formatter& >(that)); } - date_time_formatter& operator= (date_time_formatter that) + date_time_formatter& operator= (date_time_formatter that) BOOST_NOEXCEPT { this->swap(that); return *this; @@ -200,7 +199,7 @@ public: m_formatters.push_back(&date_time_formatter_::format_literal); } - void swap(date_time_formatter& that) + void swap(date_time_formatter& that) BOOST_NOEXCEPT { m_formatters.swap(that.m_formatters); m_literal_lens.swap(that.m_literal_lens); @@ -220,55 +219,55 @@ public: static void format_full_year(context& ctx) { - (put_integer)(ctx.str, ctx.value.year, 4, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.year, 4, static_cast< char_type >('0')); } static void format_short_year(context& ctx) { - (put_integer)(ctx.str, ctx.value.year % 100u, 2, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.year % 100u, 2, static_cast< char_type >('0')); } static void format_numeric_month(context& ctx) { - (put_integer)(ctx.str, ctx.value.month, 2, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.month, 2, static_cast< char_type >('0')); } template< char_type FillCharV > static void format_month_day(context& ctx) { - (put_integer)(ctx.str, ctx.value.day, 2, static_cast< char_type >(FillCharV)); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.day, 2, static_cast< char_type >(FillCharV)); } static void format_week_day(context& ctx) { - (put_integer)(ctx.str, static_cast< decomposed_time const& >(ctx.value).week_day(), 1, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), static_cast< decomposed_time const& >(ctx.value).week_day(), 1, static_cast< char_type >('0')); } template< char_type FillCharV > static void format_hours(context& ctx) { - (put_integer)(ctx.str, ctx.value.hours, 2, static_cast< char_type >(FillCharV)); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.hours, 2, static_cast< char_type >(FillCharV)); } template< char_type FillCharV > static void format_hours_12(context& ctx) { - (put_integer)(ctx.str, ctx.value.hours % 12u + 1u, 2, static_cast< char_type >(FillCharV)); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.hours % 12u + 1u, 2, static_cast< char_type >(FillCharV)); } static void format_minutes(context& ctx) { - (put_integer)(ctx.str, ctx.value.minutes, 2, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.minutes, 2, static_cast< char_type >('0')); } static void format_seconds(context& ctx) { - (put_integer)(ctx.str, ctx.value.seconds, 2, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.seconds, 2, static_cast< char_type >('0')); } static void format_fractional_seconds(context& ctx) { - (put_integer)(ctx.str, ctx.value.subseconds, decomposed_time::subseconds_digits10, static_cast< char_type >('0')); + (put_integer)(*ctx.strm.rdbuf(), ctx.value.subseconds, decomposed_time::subseconds_digits10, static_cast< char_type >('0')); } template< bool UpperCaseV > @@ -277,16 +276,16 @@ public: static const char_type am[] = { static_cast< char_type >(UpperCaseV ? 'A' : 'a'), static_cast< char_type >(UpperCaseV ? 'M' : 'm'), static_cast< char_type >(0) }; static const char_type pm[] = { static_cast< char_type >(UpperCaseV ? 'P' : 'p'), static_cast< char_type >(UpperCaseV ? 'M' : 'm'), static_cast< char_type >(0) }; - ctx.str.append(((static_cast< decomposed_time const& >(ctx.value).hours > 11) ? pm : am), 2u); + ctx.strm.rdbuf()->append(((static_cast< decomposed_time const& >(ctx.value).hours > 11) ? pm : am), 2u); } template< bool DisplayPositiveV > static void format_sign(context& ctx) { if (static_cast< decomposed_time const& >(ctx.value).negative) - ctx.str.push_back('-'); + ctx.strm.rdbuf()->push_back('-'); else if (DisplayPositiveV) - ctx.str.push_back('+'); + ctx.strm.rdbuf()->push_back('+'); } private: @@ -296,7 +295,7 @@ private: ++ctx.literal_index; ctx.literal_pos += len; const char_type* lit = ctx.self.m_literal_chars.c_str(); - ctx.str.append(lit + pos, len); + ctx.strm.rdbuf()->append(lit + pos, len); } }; diff --git a/boost/log/detail/enqueued_record.hpp b/boost/log/detail/enqueued_record.hpp index ef6377799f..f4821363a2 100644 --- a/boost/log/detail/enqueued_record.hpp +++ b/boost/log/detail/enqueued_record.hpp @@ -18,7 +18,7 @@ #define BOOST_LOG_DETAIL_ENQUEUED_RECORD_HPP_INCLUDED_ #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/timestamp.hpp> #include <boost/log/core/record_view.hpp> diff --git a/boost/log/detail/format.hpp b/boost/log/detail/format.hpp index 89c6a9fb01..449f85edfa 100644 --- a/boost/log/detail/format.hpp +++ b/boost/log/detail/format.hpp @@ -21,7 +21,7 @@ #include <iosfwd> #include <boost/assert.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/unhandled_exception_count.hpp> #include <boost/log/detail/cleanup_scope_guard.hpp> @@ -188,37 +188,19 @@ public: } //! Creates a pump that will receive all format arguments and put the formatted string into the stream - pump make_pump(stream_type& strm) BOOST_NOEXCEPT + pump make_pump(stream_type& strm) { + // Flush the stream beforehand so that the pump can safely switch the stream storage string + strm.flush(); return pump(*this, strm); } //! Composes the final string from the formatted pieces - void compose(string_type& str) const - { - typename format_description_type::format_element_list::const_iterator it = m_format.format_elements.begin(), end = m_format.format_elements.end(); - for (; it != end; ++it) - { - if (it->arg_number >= 0) - { - // This is a placeholder - str.append(m_formatting_params[it->arg_number].target); - } - else - { - // This is a literal - const char_type* p = m_format.literal_chars.c_str() + it->literal_start_pos; - str.append(p, it->literal_len); - } - } - } - - //! Composes the final string from the formatted pieces string_type str() const { string_type result; compose(result); - return boost::move(result); + return BOOST_LOG_NRVO_RESULT(result); } private: @@ -236,6 +218,28 @@ private: } } } + + //! Composes the final string from the formatted pieces + template< typename T > + void compose(T& str) const + { + typename format_description_type::format_element_list::const_iterator it = m_format.format_elements.begin(), end = m_format.format_elements.end(); + for (; it != end; ++it) + { + if (it->arg_number >= 0) + { + // This is a placeholder + string_type const& target = m_formatting_params[it->arg_number].target; + str.append(target.data(), target.size()); + } + else + { + // This is a literal + const char_type* p = m_format.literal_chars.c_str() + it->literal_start_pos; + str.append(p, it->literal_len); + } + } + } }; //! The pump receives arguments and formats them into strings. At destruction the pump composes the final string in the attached stream. @@ -248,18 +252,18 @@ private: //! The guard temporarily replaces storage string in the specified stream struct scoped_storage { - scoped_storage(stream_type& strm, string_type& storage) : m_stream(strm), m_storage_backup(*strm.rdbuf()->storage()) + scoped_storage(stream_type& strm, string_type& storage) : m_stream(strm), m_storage_state_backup(strm.rdbuf()->get_storage_state()) { strm.attach(storage); } ~scoped_storage() { - m_stream.attach(m_storage_backup); + m_stream.rdbuf()->set_storage_state(m_storage_state_backup); } private: stream_type& m_stream; - string_type& m_storage_backup; + typename stream_type::streambuf_type::storage_state m_storage_state_backup; }; private: @@ -296,7 +300,7 @@ public: { // Compose the final string in the stream buffer m_stream->flush(); - m_owner->compose(*m_stream->rdbuf()->storage()); + m_owner->compose(*m_stream->rdbuf()); } } } diff --git a/boost/log/detail/light_function.hpp b/boost/log/detail/light_function.hpp index d6606e0e67..0835772f66 100644 --- a/boost/log/detail/light_function.hpp +++ b/boost/log/detail/light_function.hpp @@ -21,7 +21,7 @@ #include <cstddef> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/utility/explicit_operator_bool.hpp> #include <boost/type_traits/remove_cv.hpp> @@ -33,7 +33,7 @@ #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> #endif #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -#include <boost/utility/enable_if.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #else #include <boost/type_traits/remove_reference.hpp> #endif @@ -194,12 +194,12 @@ public: } #else template< typename FunT > - light_function(FunT const& fun, typename disable_if_c< is_rv_or_same< FunT, this_type >::value, int >::type = 0) : + light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< FunT >(fun)) { } template< typename FunT > - light_function(BOOST_RV_REF(FunT) fun, typename disable_if_c< is_cv_same< FunT, this_type >::value, int >::type = 0) : + light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< typename remove_cv< FunT >::type >(fun)) { } @@ -256,7 +256,7 @@ public: } #else template< typename FunT > - typename disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type + typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type operator= (FunT const& fun) { light_function tmp(fun); @@ -400,12 +400,12 @@ public: } #else template< typename FunT > - light_function(FunT const& fun, typename disable_if_c< is_rv_or_same< FunT, this_type >::value, int >::type = 0) : + light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< FunT >(fun)) { } template< typename FunT > - light_function(BOOST_RV_REF(FunT) fun, typename disable_if_c< is_cv_same< FunT, this_type >::value, int >::type = 0) : + light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< typename remove_cv< FunT >::type >(fun)) { } @@ -462,7 +462,7 @@ public: } #else template< typename FunT > - typename disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type + typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type operator= (FunT const& fun) { light_function tmp(fun); diff --git a/boost/log/detail/light_function_pp.hpp b/boost/log/detail/light_function_pp.hpp index 92df419a52..9bf5f573fe 100644 --- a/boost/log/detail/light_function_pp.hpp +++ b/boost/log/detail/light_function_pp.hpp @@ -119,12 +119,12 @@ public: } #else template< typename FunT > - light_function(FunT const& fun, typename disable_if_c< is_rv_or_same< FunT, this_type >::value, int >::type = 0) : + light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< FunT >(fun)) { } template< typename FunT > - light_function(BOOST_RV_REF(FunT) fun, typename disable_if_c< is_cv_same< FunT, this_type >::value, int >::type = 0) : + light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< typename remove_cv< FunT >::type >(fun)) { } @@ -181,7 +181,7 @@ public: } #else template< typename FunT > - typename disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type + typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type operator= (FunT const& fun) { light_function tmp(fun); @@ -327,12 +327,12 @@ public: } #else template< typename FunT > - light_function(FunT const& fun, typename disable_if_c< is_rv_or_same< FunT, this_type >::value, int >::type = 0) : + light_function(FunT const& fun, typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< FunT >(fun)) { } template< typename FunT > - light_function(BOOST_RV_REF(FunT) fun, typename disable_if_c< is_cv_same< FunT, this_type >::value, int >::type = 0) : + light_function(BOOST_RV_REF(FunT) fun, typename boost::disable_if_c< is_cv_same< FunT, this_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_pImpl(new impl< typename remove_cv< FunT >::type >(fun)) { } @@ -389,7 +389,7 @@ public: } #else template< typename FunT > - typename disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type + typename boost::disable_if_c< is_rv_or_same< FunT, this_type >::value, this_type& >::type operator= (FunT const& fun) { light_function tmp(fun); diff --git a/boost/log/detail/locks.hpp b/boost/log/detail/locks.hpp index 99bc7e17f9..224d8e59bb 100644 --- a/boost/log/detail/locks.hpp +++ b/boost/log/detail/locks.hpp @@ -32,6 +32,8 @@ namespace boost { template< typename > class lock_guard; template< typename > +class shared_lock_guard; +template< typename > class shared_lock; template< typename > class upgrade_lock; @@ -92,6 +94,25 @@ struct is_shared_lockable enum value_t { value = sizeof(check_shared_lockable((MutexT*)NULL)) == sizeof(true_type) }; }; +//! A scope guard that automatically unlocks the mutex on destruction +template< typename MutexT > +struct exclusive_auto_unlocker +{ + explicit exclusive_auto_unlocker(MutexT& m) BOOST_NOEXCEPT : m_Mutex(m) + { + } + ~exclusive_auto_unlocker() + { + m_Mutex.unlock(); + } + + BOOST_DELETED_FUNCTION(exclusive_auto_unlocker(exclusive_auto_unlocker const&)) + BOOST_DELETED_FUNCTION(exclusive_auto_unlocker& operator= (exclusive_auto_unlocker const&)) + +protected: + MutexT& m_Mutex; +}; + //! An analogue to the minimalistic \c lock_guard template. Defined here to avoid including Boost.Thread. template< typename MutexT > struct exclusive_lock_guard @@ -105,9 +126,8 @@ struct exclusive_lock_guard m_Mutex.unlock(); } -private: - exclusive_lock_guard(exclusive_lock_guard const&); - exclusive_lock_guard& operator= (exclusive_lock_guard const&); + BOOST_DELETED_FUNCTION(exclusive_lock_guard(exclusive_lock_guard const&)) + BOOST_DELETED_FUNCTION(exclusive_lock_guard& operator= (exclusive_lock_guard const&)) private: MutexT& m_Mutex; @@ -126,9 +146,8 @@ struct shared_lock_guard m_Mutex.unlock_shared(); } -private: - shared_lock_guard(shared_lock_guard const&); - shared_lock_guard& operator= (shared_lock_guard const&); + BOOST_DELETED_FUNCTION(shared_lock_guard(shared_lock_guard const&)) + BOOST_DELETED_FUNCTION(shared_lock_guard& operator= (shared_lock_guard const&)) private: MutexT& m_Mutex; diff --git a/boost/log/detail/parameter_tools.hpp b/boost/log/detail/parameter_tools.hpp index 01df40536c..55695e3cde 100644 --- a/boost/log/detail/parameter_tools.hpp +++ b/boost/log/detail/parameter_tools.hpp @@ -17,6 +17,8 @@ #define BOOST_LOG_DETAIL_PARAMETER_TOOLS_HPP_INCLUDED_ #include <boost/parameter/keyword.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/comparison/equal.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> @@ -24,6 +26,7 @@ #include <boost/preprocessor/arithmetic/dec.hpp> #include <boost/preprocessor/tuple/elem.hpp> #include <boost/log/detail/config.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #include <boost/log/detail/header.hpp> #ifdef BOOST_HAS_PRAGMA_ONCE @@ -40,23 +43,37 @@ public:\ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, macro, args) +#define BOOST_LOG_CTOR_FORWARD_1(n, types)\ + template< typename T0 >\ + explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ + BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))) {} -#define BOOST_LOG_CTOR_FORWARD(z, n, types)\ +#define BOOST_LOG_CTOR_FORWARD_N(n, types)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))) {} +#define BOOST_LOG_CTOR_FORWARD(z, n, types)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_FORWARD_1, BOOST_LOG_CTOR_FORWARD_N)(n, types) + // The macro expands to a number of templated constructors that aggregate their named arguments // into an ArgumentsPack and pass it to the base class constructor. #define BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_FORWARD(class_type, base_type)\ BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_CTOR_FORWARD, (class_type, base_type)) +#define BOOST_LOG_CTOR_CALL_1(n, types)\ + template< typename T0 >\ + explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy())\ + { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))); } -#define BOOST_LOG_CTOR_CALL(z, n, types)\ +#define BOOST_LOG_CTOR_CALL_N(n, types)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg))\ { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))); } +#define BOOST_LOG_CTOR_CALL(z, n, types)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_CALL_1, BOOST_LOG_CTOR_CALL_N)(n, types) + // The macro expands to a number of templated constructors that aggregate their named arguments // into an ArgumentsPack and pass it to a function call. #define BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(class_type, fun)\ @@ -69,6 +86,7 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { // Yeah, not too cute. The empty_arg_list class should really be public. +// https://svn.boost.org/trac/boost/ticket/7247 typedef boost::parameter::aux::empty_arg_list empty_arg_list; #if !(defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_LOG_NO_CXX11_ARG_PACKS_TO_NON_VARIADIC_ARGS_EXPANSION)) @@ -103,6 +121,27 @@ struct make_arg_list< ArgT0, BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(BOOST_LOG_MAX_PAR #endif +template< typename T, typename R > +struct enable_if_named_parameters {}; + +template< typename R > +struct enable_if_named_parameters< empty_arg_list, R > +{ + typedef R type; +}; + +template< typename Keyword, typename Arg, typename R > +struct enable_if_named_parameters< boost::parameter::aux::tagged_argument< Keyword, Arg >, R > +{ + typedef R type; +}; + +template< typename TaggedArg, typename Next, typename R > +struct enable_if_named_parameters< boost::parameter::aux::arg_list< TaggedArg, Next >, R > +{ + typedef R type; +}; + } // namespace aux BOOST_LOG_CLOSE_NAMESPACE // namespace log diff --git a/boost/log/detail/pause.hpp b/boost/log/detail/pause.hpp new file mode 100644 index 0000000000..c1b43498f0 --- /dev/null +++ b/boost/log/detail/pause.hpp @@ -0,0 +1,61 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 pause.hpp + * \author Andrey Semashev + * \date 06.01.2016 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#ifndef BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ +#define BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# if defined(_M_IX86) +# define BOOST_LOG_AUX_PAUSE __asm { pause } +# elif defined(_M_AMD64) +extern "C" void _mm_pause(void); +# if defined(BOOST_MSVC) +# pragma intrinsic(_mm_pause) +# endif +# define BOOST_LOG_AUX_PAUSE _mm_pause() +# endif +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# define BOOST_LOG_AUX_PAUSE __asm__ __volatile__("pause;") +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +BOOST_FORCEINLINE void pause() BOOST_NOEXCEPT +{ +#if defined(BOOST_LOG_AUX_PAUSE) + BOOST_LOG_AUX_PAUSE; +#endif +} + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ diff --git a/boost/log/detail/sfinae_tools.hpp b/boost/log/detail/sfinae_tools.hpp new file mode 100644 index 0000000000..e9f2735b25 --- /dev/null +++ b/boost/log/detail/sfinae_tools.hpp @@ -0,0 +1,44 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 sfinae_tools.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#ifndef BOOST_LOG_DETAIL_SFINAE_TOOLS_HPP_INCLUDED_ +#define BOOST_LOG_DETAIL_SFINAE_TOOLS_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <boost/core/enable_if.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +//! A distinct type that can be used as a fake argument type in constructors filtered by SFINAE +struct sfinae_dummy {}; + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_DETAIL_SFINAE_TOOLS_HPP_INCLUDED_ diff --git a/boost/log/detail/sink_init_helpers.hpp b/boost/log/detail/sink_init_helpers.hpp index c94b5630c4..a3bbe0e8a1 100644 --- a/boost/log/detail/sink_init_helpers.hpp +++ b/boost/log/detail/sink_init_helpers.hpp @@ -20,7 +20,7 @@ #include <boost/mpl/bool.hpp> #include <boost/parameter/binding.hpp> #include <boost/type_traits/is_void.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/phoenix/core/is_actor.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/core/core.hpp> @@ -54,8 +54,8 @@ inline filter acquire_filter(std::basic_string< CharT, TraitsT, AllocatorT > con return boost::log::parse_filter(filter); } template< typename FilterT > -inline typename enable_if< - phoenix::is_actor< FilterT >, +inline typename boost::enable_if_c< + phoenix::is_actor< FilterT >::value, FilterT const& >::type acquire_filter(FilterT const& filter) { @@ -87,8 +87,8 @@ inline basic_formatter< CharT > acquire_formatter(std::basic_string< CharT, Trai return boost::log::parse_formatter(formatter); } template< typename FormatterT > -inline typename enable_if< - phoenix::is_actor< FormatterT >, +inline typename boost::enable_if_c< + phoenix::is_actor< FormatterT >::value, FormatterT const& >::type acquire_formatter(FormatterT const& formatter) { diff --git a/boost/log/detail/snprintf.hpp b/boost/log/detail/snprintf.hpp index 7fae834526..14c6a6b1dc 100644 --- a/boost/log/detail/snprintf.hpp +++ b/boost/log/detail/snprintf.hpp @@ -35,20 +35,10 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -#if !defined(_MSC_VER) +#if defined(_MSC_VER) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) -// Standard-conforming compilers already have the correct snprintfs -using ::snprintf; -using ::vsnprintf; - -# ifdef BOOST_LOG_USE_WCHAR_T -using ::swprintf; -using ::vswprintf; -# endif // BOOST_LOG_USE_WCHAR_T - -#else // !defined(_MSC_VER) - -// MSVC snprintfs are not conforming but they are good enough for our cases +// MSVC snprintfs are not conforming but they are good enough for our cases. +// MinGW32, at least the older versions up until gcc 4.7, also provide the non-conforming interface. inline int vsnprintf(char* buf, std::size_t size, const char* format, std::va_list args) { int n = _vsnprintf(buf, size, format, args); @@ -93,7 +83,18 @@ inline int swprintf(wchar_t* buf, std::size_t size, const wchar_t* format, ...) } # endif // BOOST_LOG_USE_WCHAR_T -#endif // !defined(_MSC_VER) +#else + +// Standard-conforming compilers already have the correct snprintfs +using ::snprintf; +using ::vsnprintf; + +# ifdef BOOST_LOG_USE_WCHAR_T +using ::swprintf; +using ::vswprintf; +# endif // BOOST_LOG_USE_WCHAR_T + +#endif } // namespace aux diff --git a/boost/log/detail/tagged_integer.hpp b/boost/log/detail/tagged_integer.hpp index f72b9af78d..82c9706863 100644 --- a/boost/log/detail/tagged_integer.hpp +++ b/boost/log/detail/tagged_integer.hpp @@ -42,17 +42,17 @@ struct tagged_integer integer_type value; //! Conversion operator - operator integer_type() const { return value; } + BOOST_CONSTEXPR operator integer_type() const BOOST_NOEXCEPT { return value; } // Increment - tagged_integer& operator++ () { ++value; return *this; } - tagged_integer operator++ (int) { tagged_integer temp = *this; ++value; return temp; } + tagged_integer& operator++ () BOOST_NOEXCEPT { ++value; return *this; } + tagged_integer operator++ (int) BOOST_NOEXCEPT { tagged_integer temp = *this; ++value; return temp; } // Decrement - tagged_integer& operator-- () { --value; return *this; } - tagged_integer operator-- (int) { tagged_integer temp = *this; --value; return temp; } + tagged_integer& operator-- () BOOST_NOEXCEPT { --value; return *this; } + tagged_integer operator-- (int) BOOST_NOEXCEPT { tagged_integer temp = *this; --value; return temp; } #define BOOST_LOG_TAGGED_INTEGER_OP(op)\ - tagged_integer& operator op (tagged_integer const& that) { value op that.value; return *this; } + tagged_integer& operator op (tagged_integer const& that) BOOST_NOEXCEPT { value op that.value; return *this; } BOOST_LOG_TAGGED_INTEGER_OP(|=) BOOST_LOG_TAGGED_INTEGER_OP(&=) @@ -66,13 +66,13 @@ struct tagged_integer #undef BOOST_LOG_TAGGED_INTEGER_OP //! Inversion operator - tagged_integer& operator~ () { ~value; return *this; } + tagged_integer& operator~ () BOOST_NOEXCEPT { ~value; return *this; } // Shift operators template< typename T > - tagged_integer& operator<<= (T const& that) { value <<= that; return *this; } + tagged_integer& operator<<= (T const& that) BOOST_NOEXCEPT { value <<= that; return *this; } template< typename T > - tagged_integer& operator>>= (T const& that) { value >>= that; return *this; } + tagged_integer& operator>>= (T const& that) BOOST_NOEXCEPT { value >>= that; return *this; } private: // Protection against improper usage @@ -86,7 +86,7 @@ private: #define BOOST_LOG_TAGGED_INTEGER_OP(op)\ template< typename IntT, typename TagT >\ inline bool operator op (\ - tagged_integer< IntT, TagT > const& left, tagged_integer< IntT, TagT > const& right)\ + tagged_integer< IntT, TagT > const& left, tagged_integer< IntT, TagT > const& right) BOOST_NOEXCEPT\ {\ return (left.value op right.value);\ } @@ -103,7 +103,7 @@ BOOST_LOG_TAGGED_INTEGER_OP(>=) #define BOOST_LOG_TAGGED_INTEGER_OP(op)\ template< typename IntT, typename TagT >\ inline tagged_integer< IntT, TagT > operator op (\ - tagged_integer< IntT, TagT > const& left, tagged_integer< IntT, TagT > const& right)\ + tagged_integer< IntT, TagT > const& left, tagged_integer< IntT, TagT > const& right) BOOST_NOEXCEPT\ {\ tagged_integer< IntT, TagT > temp = left;\ temp op##= right;\ @@ -124,7 +124,7 @@ BOOST_LOG_TAGGED_INTEGER_OP(%) #define BOOST_LOG_TAGGED_INTEGER_OP(op)\ template< typename IntT, typename TagT, typename T >\ inline tagged_integer< IntT, TagT > operator op (\ - tagged_integer< IntT, TagT > const& left, T const& right)\ + tagged_integer< IntT, TagT > const& left, T const& right) BOOST_NOEXCEPT\ {\ tagged_integer< IntT, TagT > temp = left;\ temp op##= right;\ diff --git a/boost/log/detail/threadsafe_queue.hpp b/boost/log/detail/threadsafe_queue.hpp index 2ab2172b13..b8b3dbe60a 100644 --- a/boost/log/detail/threadsafe_queue.hpp +++ b/boost/log/detail/threadsafe_queue.hpp @@ -29,7 +29,7 @@ #include <cstddef> #include <boost/aligned_storage.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/type_with_alignment.hpp> #include <boost/log/detail/header.hpp> diff --git a/boost/log/exceptions.hpp b/boost/log/exceptions.hpp index 8f305fabeb..32d55d40c5 100644 --- a/boost/log/exceptions.hpp +++ b/boost/log/exceptions.hpp @@ -20,6 +20,8 @@ #include <stdexcept> #include <boost/type_index.hpp> #include <boost/preprocessor/seq/enum.hpp> +#include <boost/system/error_code.hpp> +#include <boost/system/system_error.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/attributes/attribute_name.hpp> #include <boost/log/detail/header.hpp> @@ -59,6 +61,68 @@ BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const } // namespace aux /*! + * \brief Base class for memory allocation errors + * + * Exceptions derived from this class indicate problems with memory allocation. + */ +class BOOST_LOG_API bad_alloc : + public std::bad_alloc +{ +private: + std::string m_message; + +public: + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit bad_alloc(const char* descr); + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit bad_alloc(std::string const& descr); + /*! + * Destructor + */ + ~bad_alloc() throw(); + + /*! + * Error message accessor. + */ + const char* what() const throw(); + +#ifndef BOOST_LOG_DOXYGEN_PASS + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); +#endif +}; + +/*! + * \brief The exception is used to indicate reaching a storage capacity limit + */ +class BOOST_LOG_API capacity_limit_reached : + public bad_alloc +{ +public: + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit capacity_limit_reached(const char* descr); + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit capacity_limit_reached(std::string const& descr); + /*! + * Destructor + */ + ~capacity_limit_reached() throw(); + +#ifndef BOOST_LOG_DOXYGEN_PASS + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); +#endif +}; + +/*! * \brief Base class for runtime exceptions from the logging library * * Exceptions derived from this class indicate a problem that may not directly @@ -68,7 +132,7 @@ BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const class BOOST_LOG_API runtime_error : public std::runtime_error { -protected: +public: /*! * Initializing constructor. Creates an exception with the specified error message. */ @@ -101,7 +165,9 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name); #endif }; @@ -128,9 +194,13 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, typeindex::type_index const& type); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, typeindex::type_index const& type); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name, typeindex::type_index const& type); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name, typeindex::type_index const& type); #endif }; @@ -157,6 +227,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; @@ -183,8 +254,11 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, std::size_t content_line); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, std::size_t content_line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name); #endif }; @@ -211,6 +285,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; @@ -219,25 +294,23 @@ public: * \brief Exception class that is used to indicate underlying OS API errors */ class BOOST_LOG_API system_error : - public runtime_error + public boost::system::system_error { public: /*! - * Default constructor. Creates an exception with the default error message. - */ - system_error(); - /*! * Initializing constructor. Creates an exception with the specified error message. */ - explicit system_error(std::string const& descr); + system_error(boost::system::error_code code, std::string const& descr); /*! * Destructor */ ~system_error() throw(); #ifndef BOOST_LOG_DOXYGEN_PASS - static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); - static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, int system_error_code); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, int system_error_code); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, boost::system::error_code code); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, boost::system::error_code code); #endif }; @@ -250,7 +323,7 @@ public: class BOOST_LOG_API logic_error : public std::logic_error { -protected: +public: /*! * Initializing constructor. Creates an exception with the specified error message. */ @@ -259,6 +332,11 @@ protected: * Destructor */ ~logic_error() throw(); + +#ifndef BOOST_LOG_DOXYGEN_PASS + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); +#endif }; /*! @@ -283,6 +361,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; @@ -309,6 +388,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; @@ -335,6 +415,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; @@ -361,6 +442,7 @@ public: #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); #endif }; diff --git a/boost/log/expressions/attr.hpp b/boost/log/expressions/attr.hpp index aca0447cff..60540e7d77 100644 --- a/boost/log/expressions/attr.hpp +++ b/boost/log/expressions/attr.hpp @@ -56,8 +56,10 @@ private: typedef attribute_terminal< T, FallbackPolicyT, TagT > this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Attribute tag type typedef TagT tag_type; diff --git a/boost/log/expressions/filter.hpp b/boost/log/expressions/filter.hpp index ae43abe150..1e53f5c3bd 100644 --- a/boost/log/expressions/filter.hpp +++ b/boost/log/expressions/filter.hpp @@ -16,11 +16,11 @@ #define BOOST_LOG_EXPRESSIONS_FILTER_HPP_INCLUDED_ #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -#include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_cv.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #endif #include <boost/log/detail/config.hpp> #include <boost/log/attributes/attribute_value_set.hpp> @@ -89,13 +89,13 @@ public: filter(FunT&& fun) : m_Filter(boost::forward< FunT >(fun)) { } -#elif !defined(BOOST_MSVC) || BOOST_MSVC > 1400 +#elif !defined(BOOST_MSVC) || BOOST_MSVC >= 1600 template< typename FunT > - filter(FunT const& fun, typename disable_if_c< move_detail::is_rv< FunT >::value, int >::type = 0) : m_Filter(fun) + filter(FunT const& fun, typename boost::disable_if_c< move_detail::is_rv< FunT >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_Filter(fun) { } #else - // MSVC 8 blows up in unexpected ways if we use SFINAE to disable constructor instantiation + // MSVC 9 and older blows up in unexpected ways if we use SFINAE to disable constructor instantiation template< typename FunT > filter(FunT const& fun) : m_Filter(fun) { @@ -137,7 +137,7 @@ public: filter& operator= (FunT const& fun) #else template< typename FunT > - typename disable_if< is_same< typename remove_cv< FunT >::type, filter >, filter& >::type + typename boost::disable_if_c< is_same< typename remove_cv< FunT >::type, filter >::value, filter& >::type operator= (FunT const& fun) #endif { diff --git a/boost/log/expressions/formatter.hpp b/boost/log/expressions/formatter.hpp index bdbabb504e..bc80dfa250 100644 --- a/boost/log/expressions/formatter.hpp +++ b/boost/log/expressions/formatter.hpp @@ -19,11 +19,11 @@ #include <ostream> #include <boost/ref.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -#include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_cv.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #endif #include <boost/log/detail/config.hpp> #include <boost/log/detail/light_function.hpp> @@ -376,11 +376,11 @@ public: } #elif !defined(BOOST_MSVC) || BOOST_MSVC >= 1600 template< typename FunT > - basic_formatter(FunT const& fun, typename disable_if_c< move_detail::is_rv< FunT >::value, int >::type = 0) : m_Formatter(fun) + basic_formatter(FunT const& fun, typename boost::disable_if_c< move_detail::is_rv< FunT >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) : m_Formatter(fun) { } #else - // MSVC 9 blows up in unexpected ways if we use SFINAE to disable constructor instantiation + // MSVC 9 and older blows up in unexpected ways if we use SFINAE to disable constructor instantiation template< typename FunT > basic_formatter(FunT const& fun) : m_Formatter(fun) { @@ -426,7 +426,7 @@ public: } #else template< typename FunT > - typename disable_if< is_same< typename remove_cv< FunT >::type, this_type >, this_type& >::type + typename boost::disable_if_c< is_same< typename remove_cv< FunT >::type, this_type >::value, this_type& >::type operator= (FunT const& fun) { this_type(fun).swap(*this); diff --git a/boost/log/expressions/formatters.hpp b/boost/log/expressions/formatters.hpp index 1d3f4edd54..f85cb7903b 100644 --- a/boost/log/expressions/formatters.hpp +++ b/boost/log/expressions/formatters.hpp @@ -27,6 +27,7 @@ #include <boost/log/expressions/formatters/xml_decorator.hpp> #include <boost/log/expressions/formatters/csv_decorator.hpp> #include <boost/log/expressions/formatters/c_decorator.hpp> +#include <boost/log/expressions/formatters/max_size_decorator.hpp> #include <boost/log/expressions/formatters/if.hpp> #include <boost/log/expressions/formatters/wrap_formatter.hpp> diff --git a/boost/log/expressions/formatters/char_decorator.hpp b/boost/log/expressions/formatters/char_decorator.hpp index e3188810ff..229e72ae89 100644 --- a/boost/log/expressions/formatters/char_decorator.hpp +++ b/boost/log/expressions/formatters/char_decorator.hpp @@ -27,9 +27,8 @@ #include <boost/range/const_iterator.hpp> #include <boost/range/value_type.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> -#include <boost/core/enable_if.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/core/addressof.hpp> #include <boost/phoenix/core/actor.hpp> #include <boost/phoenix/core/meta_grammar.hpp> #include <boost/phoenix/core/terminal_fwd.hpp> @@ -43,6 +42,7 @@ #include <boost/log/detail/config.hpp> #include <boost/log/detail/custom_terminal_spec.hpp> #include <boost/log/detail/deduce_char_type.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #include <boost/log/utility/formatting_ostream.hpp> #include <boost/log/detail/header.hpp> @@ -113,7 +113,7 @@ public: explicit pattern_replacer(RangeT const& decorations #ifndef BOOST_LOG_DOXYGEN_PASS // This is needed for a workaround against an MSVC-10 and older bug in constructor overload resolution - , typename boost::enable_if_has_type< typename range_const_iterator< RangeT >::type, int >::type = 0 + , typename boost::enable_if_has_type< typename range_const_iterator< RangeT >::type, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy() #endif ) { @@ -235,8 +235,10 @@ private: typedef char_decorator_output_terminal< LeftT, SubactorT, ImplT > this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Implementation type typedef ImplT impl_type; @@ -300,12 +302,12 @@ public: typename string_type::size_type const start_pos = strm.rdbuf()->storage()->size(); // Invoke the adopted formatter - typedef typename result< this_type(ContextT const&) >::type result_type; phoenix::eval(m_subactor, ctx); // Flush the buffered characters and apply decorations strm.flush(); m_impl(*strm.rdbuf()->storage(), start_pos); + strm.rdbuf()->ensure_max_size(); return strm; } @@ -323,12 +325,12 @@ public: typename string_type::size_type const start_pos = strm.rdbuf()->storage()->size(); // Invoke the adopted formatter - typedef typename result< const this_type(ContextT const&) >::type result_type; phoenix::eval(m_subactor, ctx); // Flush the buffered characters and apply decorations strm.flush(); m_impl(*strm.rdbuf()->storage(), start_pos); + strm.rdbuf()->ensure_max_size(); return strm; } @@ -357,8 +359,10 @@ private: typedef char_decorator_terminal< SubactorT, ImplT > this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Implementation type typedef ImplT impl_type; @@ -439,7 +443,7 @@ public: strm.flush(); m_impl(*strm.rdbuf()->storage()); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } /*! @@ -471,7 +475,7 @@ public: strm.flush(); m_impl(*strm.rdbuf()->storage()); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } BOOST_DELETED_FUNCTION(char_decorator_terminal()) diff --git a/boost/log/expressions/formatters/date_time.hpp b/boost/log/expressions/formatters/date_time.hpp index 45091fc206..b8de0b4cb7 100644 --- a/boost/log/expressions/formatters/date_time.hpp +++ b/boost/log/expressions/formatters/date_time.hpp @@ -17,7 +17,7 @@ #include <string> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/phoenix/core/actor.hpp> #include <boost/phoenix/core/terminal_fwd.hpp> #include <boost/phoenix/core/is_nullary.hpp> @@ -54,8 +54,10 @@ template< typename T, typename FallbackPolicyT, typename CharT > class format_date_time_terminal { public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Attribute value type typedef T value_type; @@ -126,7 +128,7 @@ public: stream_type strm(str); m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type&, stream_type& >(m_formatter, strm)); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } //! Invokation operator @@ -137,7 +139,7 @@ public: stream_type strm(str); m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type const&, stream_type& >(m_formatter, strm)); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } BOOST_DELETED_FUNCTION(format_date_time_terminal()) diff --git a/boost/log/expressions/formatters/format.hpp b/boost/log/expressions/formatters/format.hpp index ceccae942e..d312d8e36d 100644 --- a/boost/log/expressions/formatters/format.hpp +++ b/boost/log/expressions/formatters/format.hpp @@ -44,8 +44,10 @@ template< typename CharT > class format_terminal { public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Character type typedef CharT char_type; diff --git a/boost/log/expressions/formatters/if.hpp b/boost/log/expressions/formatters/if.hpp index 360622f843..3e1e1abc5a 100644 --- a/boost/log/expressions/formatters/if.hpp +++ b/boost/log/expressions/formatters/if.hpp @@ -48,8 +48,10 @@ private: typedef if_output_terminal this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Result type definition template< typename > @@ -113,8 +115,10 @@ private: typedef if_else_output_terminal this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Result type definition template< typename > diff --git a/boost/log/expressions/formatters/max_size_decorator.hpp b/boost/log/expressions/formatters/max_size_decorator.hpp new file mode 100644 index 0000000000..0ab44d6fa4 --- /dev/null +++ b/boost/log/expressions/formatters/max_size_decorator.hpp @@ -0,0 +1,561 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 formatters/max_size_decorator.hpp + * \author Andrey Semashev + * \date 06.07.2016 + * + * The header contains implementation of a string length limiting decorator. + */ + +#ifndef BOOST_LOG_EXPRESSIONS_FORMATTERS_MAX_SIZE_DECORATOR_HPP_INCLUDED_ +#define BOOST_LOG_EXPRESSIONS_FORMATTERS_MAX_SIZE_DECORATOR_HPP_INCLUDED_ + +#include <cstddef> +#include <string> +#include <boost/assert.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/move/core.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/core/addressof.hpp> +#include <boost/phoenix/core/actor.hpp> +#include <boost/phoenix/core/meta_grammar.hpp> +#include <boost/phoenix/core/terminal_fwd.hpp> +#include <boost/phoenix/core/is_nullary.hpp> +#include <boost/phoenix/core/environment.hpp> +#include <boost/phoenix/support/vector.hpp> +#include <boost/fusion/sequence/intrinsic/at_c.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/custom_terminal_spec.hpp> +#include <boost/log/utility/formatting_ostream.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace expressions { + +namespace aux { + +//! String size limiting decorator stream output terminal +template< typename LeftT, typename SubactorT, typename CharT > +class max_size_decorator_output_terminal +{ +private: + //! Self type + typedef max_size_decorator_output_terminal< LeftT, SubactorT, CharT > this_type; + +public: +#ifndef BOOST_LOG_DOXYGEN_PASS + //! Internal typedef for type categorization + typedef void _is_boost_log_terminal; +#endif + + //! Character type + typedef CharT char_type; + //! String type + typedef std::basic_string< char_type > string_type; + //! String size type + typedef std::size_t size_type; + //! Adopted actor type + typedef SubactorT subactor_type; + + //! Result type definition + template< typename > + struct result; + + template< typename ThisT, typename ContextT > + struct result< ThisT(ContextT) > + { + typedef typename remove_cv< typename remove_reference< ContextT >::type >::type context_type; + typedef typename phoenix::evaluator::impl< + typename LeftT::proto_base_expr&, + context_type, + phoenix::unused + >::result_type type; + }; + +private: + //! Left argument actor + LeftT m_left; + //! Adopted formatter actor + subactor_type m_subactor; + //! Max size of the formatted string produced by the adopted formatter + size_type m_max_size; + //! Overflow marker + string_type m_overflow_marker; + +public: + /*! + * Initializing constructor. Creates decorator of the \a fmt formatter with the specified \a decorations. + */ + max_size_decorator_output_terminal(LeftT const& left, subactor_type const& sub, size_type max_size, string_type const& overflow_marker = string_type()) : + m_left(left), m_subactor(sub), m_max_size(max_size), m_overflow_marker(overflow_marker) + { + BOOST_ASSERT(overflow_marker.size() <= max_size); + } + /*! + * Copy constructor + */ + max_size_decorator_output_terminal(max_size_decorator_output_terminal const& that) : + m_left(that.m_left), m_subactor(that.m_subactor), m_max_size(that.m_max_size), m_overflow_marker(that.m_overflow_marker) + { + } + + /*! + * Invokation operator + */ + template< typename ContextT > + typename result< this_type(ContextT const&) >::type operator() (ContextT const& ctx) + { + // Flush the stream and keep the current write position in the target string + typedef typename result< this_type(ContextT const&) >::type result_type; + result_type strm = phoenix::eval(m_left, ctx); + strm.flush(); + + if (!strm.rdbuf()->storage_overflow()) + { + const size_type old_max_size = strm.rdbuf()->max_size(); + const size_type start_pos = strm.rdbuf()->storage()->size(), max_size_left = strm.rdbuf()->storage()->max_size() - start_pos; + strm.rdbuf()->max_size(start_pos + (m_max_size <= max_size_left ? m_max_size : max_size_left)); + + try + { + // Invoke the adopted formatter + phoenix::eval(m_subactor, ctx); + + // Flush the buffered characters and apply decorations + strm.flush(); + + if (strm.rdbuf()->storage_overflow()) + { + if (!m_overflow_marker.empty()) + { + // Free up space for the overflow marker + strm.rdbuf()->max_size(strm.rdbuf()->max_size() - m_overflow_marker.size()); + + // Append the marker + strm.rdbuf()->max_size(strm.rdbuf()->storage()->max_size()); + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->append(m_overflow_marker.data(), m_overflow_marker.size()); + } + else + { + strm.rdbuf()->storage_overflow(false); + } + } + + // Restore the original size limit + strm.rdbuf()->max_size(old_max_size); + } + catch (...) + { + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->max_size(old_max_size); + throw; + } + } + + return strm; + } + + /*! + * Invokation operator + */ + template< typename ContextT > + typename result< const this_type(ContextT const&) >::type operator() (ContextT const& ctx) const + { + // Flush the stream and keep the current write position in the target string + typedef typename result< const this_type(ContextT const&) >::type result_type; + result_type strm = phoenix::eval(m_left, ctx); + strm.flush(); + + if (!strm.rdbuf()->storage_overflow()) + { + const size_type old_max_size = strm.rdbuf()->max_size(); + const size_type start_pos = strm.rdbuf()->storage()->size(), max_size_left = strm.rdbuf()->storage()->max_size() - start_pos; + strm.rdbuf()->max_size(start_pos + (m_max_size <= max_size_left ? m_max_size : max_size_left)); + + try + { + // Invoke the adopted formatter + phoenix::eval(m_subactor, ctx); + + // Flush the buffered characters and apply decorations + strm.flush(); + + if (strm.rdbuf()->storage_overflow()) + { + if (!m_overflow_marker.empty()) + { + // Free up space for the overflow marker + strm.rdbuf()->max_size(strm.rdbuf()->max_size() - m_overflow_marker.size()); + + // Append the marker + strm.rdbuf()->max_size(strm.rdbuf()->storage()->max_size()); + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->append(m_overflow_marker.data(), m_overflow_marker.size()); + } + else + { + strm.rdbuf()->storage_overflow(false); + } + } + + // Restore the original size limit + strm.rdbuf()->max_size(old_max_size); + } + catch (...) + { + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->max_size(old_max_size); + throw; + } + } + + return strm; + } + + BOOST_DELETED_FUNCTION(max_size_decorator_output_terminal()) +}; + +} // namespace aux + +/*! + * String size limiting decorator terminal class. This formatter allows to limit the maximum total length + * of the strings generated by other formatters. + * + * The \c max_size_decorator_terminal class aggregates the formatter being decorated, the maximum string length + * it can produce and an optional truncation marker string, which will be put at the end of the output if the limit is exceeded. Note that + * the marker length is included in the limit and as such must not exceed it. + * The \c max_size_decorator_terminal class is a formatter itself, so it can be used to construct + * more complex formatters, including nesting decorators. + */ +template< typename SubactorT, typename CharT > +class max_size_decorator_terminal +{ +private: + //! Self type + typedef max_size_decorator_terminal< SubactorT, CharT > this_type; + +public: +#ifndef BOOST_LOG_DOXYGEN_PASS + //! Internal typedef for type categorization + typedef void _is_boost_log_terminal; +#endif + + //! Character type + typedef CharT char_type; + //! String type + typedef std::basic_string< char_type > string_type; + //! String size type + typedef std::size_t size_type; + //! Stream type + typedef basic_formatting_ostream< char_type > stream_type; + //! Adopted actor type + typedef SubactorT subactor_type; + + //! Result type definition + typedef string_type result_type; + +private: + //! Adopted formatter actor + subactor_type m_subactor; + //! Max size of the formatted string produced by the adopted formatter + size_type m_max_size; + //! Overflow marker + string_type m_overflow_marker; + +public: + /*! + * Initializing constructor. + */ + max_size_decorator_terminal(subactor_type const& sub, size_type max_size, string_type const& overflow_marker = string_type()) : + m_subactor(sub), m_max_size(max_size), m_overflow_marker(overflow_marker) + { + BOOST_ASSERT(overflow_marker.size() <= max_size); + } + /*! + * Copy constructor + */ + max_size_decorator_terminal(max_size_decorator_terminal const& that) : + m_subactor(that.m_subactor), m_max_size(that.m_max_size), m_overflow_marker(that.m_overflow_marker) + { + } + + /*! + * \returns Adopted subactor + */ + subactor_type const& get_subactor() const + { + return m_subactor; + } + + /*! + * \returns Max string size limit + */ + size_type get_max_size() const + { + return m_max_size; + } + + /*! + * \returns Max string size limit + */ + string_type const& get_overflow_marker() const + { + return m_overflow_marker; + } + + /*! + * Invokation operator + */ + template< typename ContextT > + result_type operator() (ContextT const& ctx) + { + string_type str; + stream_type strm(str); + strm.rdbuf()->max_size(m_max_size); + + // Invoke the adopted formatter + typedef phoenix::vector3< + subactor_type*, + typename fusion::result_of::at_c< + typename remove_cv< + typename remove_reference< + typename phoenix::result_of::env< ContextT const& >::type + >::type + >::type::args_type, + 0 + >::type, + stream_type& + > env_type; + env_type env = { boost::addressof(m_subactor), fusion::at_c< 0 >(phoenix::env(ctx).args()), strm }; + phoenix::eval(m_subactor, phoenix::make_context(env, phoenix::actions(ctx))); + + // Flush the buffered characters and see of overflow happened + strm.flush(); + + if (strm.rdbuf()->storage_overflow() && !m_overflow_marker.empty()) + { + strm.rdbuf()->max_size(strm.rdbuf()->max_size() - m_overflow_marker.size()); + strm.rdbuf()->max_size(str.max_size()); + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->append(m_overflow_marker.data(), m_overflow_marker.size()); + strm.flush(); + } + + return BOOST_LOG_NRVO_RESULT(str); + } + + /*! + * Invokation operator + */ + template< typename ContextT > + result_type operator() (ContextT const& ctx) const + { + string_type str; + stream_type strm(str); + strm.rdbuf()->max_size(m_max_size); + + // Invoke the adopted formatter + typedef phoenix::vector3< + const subactor_type*, + typename fusion::result_of::at_c< + typename remove_cv< + typename remove_reference< + typename phoenix::result_of::env< ContextT const& >::type + >::type + >::type::args_type, + 0 + >::type, + stream_type& + > env_type; + env_type env = { boost::addressof(m_subactor), fusion::at_c< 0 >(phoenix::env(ctx).args()), strm }; + phoenix::eval(m_subactor, phoenix::make_context(env, phoenix::actions(ctx))); + + // Flush the buffered characters and see of overflow happened + strm.flush(); + + if (strm.rdbuf()->storage_overflow()) + { + strm.rdbuf()->max_size(strm.rdbuf()->max_size() - m_overflow_marker.size()); + strm.rdbuf()->max_size(str.max_size()); + strm.rdbuf()->storage_overflow(false); + strm.rdbuf()->append(m_overflow_marker.data(), m_overflow_marker.size()); + strm.flush(); + } + + return BOOST_LOG_NRVO_RESULT(str); + } + + BOOST_DELETED_FUNCTION(max_size_decorator_terminal()) +}; + +/*! + * Character decorator actor + */ +template< typename SubactorT, typename CharT, template< typename > class ActorT = phoenix::actor > +class max_size_decorator_actor : + public ActorT< max_size_decorator_terminal< SubactorT, CharT > > +{ +public: + //! Base terminal type + typedef max_size_decorator_terminal< SubactorT, CharT > terminal_type; + //! Character type + typedef typename terminal_type::char_type char_type; + + //! Base actor type + typedef ActorT< terminal_type > base_type; + +public: + //! Initializing constructor + explicit max_size_decorator_actor(base_type const& act) : base_type(act) + { + } + + //! Returns reference to the terminal + terminal_type const& get_terminal() const + { + return this->proto_expr_.child0; + } +}; + +#ifndef BOOST_LOG_DOXYGEN_PASS + +#define BOOST_LOG_AUX_OVERLOAD(left_ref, right_ref)\ + template< typename LeftExprT, typename SubactorT, typename CharT, template< typename > class ActorT >\ + BOOST_FORCEINLINE phoenix::actor< aux::max_size_decorator_output_terminal< phoenix::actor< LeftExprT >, SubactorT, CharT > >\ + operator<< (phoenix::actor< LeftExprT > left_ref left, max_size_decorator_actor< SubactorT, CharT, ActorT > right_ref right)\ + {\ + typedef aux::max_size_decorator_output_terminal< phoenix::actor< LeftExprT >, SubactorT, CharT > terminal_type;\ + phoenix::actor< terminal_type > actor = {{ terminal_type(left, right.get_terminal().get_subactor(), right.get_terminal().get_max_size(), right.get_terminal().get_overflow_marker()) }};\ + return actor;\ + } + +#include <boost/log/detail/generate_overloads.hpp> + +#undef BOOST_LOG_AUX_OVERLOAD + +#endif // BOOST_LOG_DOXYGEN_PASS + +namespace aux { + +template< typename CharT > +class max_size_decorator_gen +{ +private: + typedef CharT char_type; + typedef std::basic_string< char_type > string_type; + typedef std::size_t size_type; + +private: + size_type m_max_size; + string_type m_overflow_marker; + +public: + explicit max_size_decorator_gen(size_type max_size, string_type const& overflow_marker = string_type()) : + m_max_size(max_size), m_overflow_marker(overflow_marker) + { + BOOST_ASSERT(overflow_marker.size() <= max_size); + } + + template< typename SubactorT > + BOOST_FORCEINLINE max_size_decorator_actor< SubactorT, char_type > operator[] (SubactorT const& subactor) const + { + typedef max_size_decorator_actor< SubactorT, char_type > result_type; + typedef typename result_type::terminal_type terminal_type; + typename result_type::base_type act = {{ terminal_type(subactor, m_max_size, m_overflow_marker) }}; + return result_type(act); + } +}; + +} // namespace aux + +/*! + * The function returns a decorator generator object. The generator provides <tt>operator[]</tt> that can be used + * to construct the actual decorator. + * + * \param max_size The maximum number of characters (i.e. string element objects) that the decorated formatter can produce. + */ +template< typename CharT > +BOOST_FORCEINLINE aux::max_size_decorator_gen< CharT > max_size_decor(std::size_t max_size) +{ + return aux::max_size_decorator_gen< CharT >(max_size); +} + +/*! + * The function returns a decorator generator object. The generator provides <tt>operator[]</tt> that can be used + * to construct the actual decorator. + * + * \param max_size The maximum number of characters (i.e. string element objects) that the decorated formatter can produce. + * \param overflow_marker The marker string which is appended to the output if the \a max_size limit is exceeded. Must be + * a non-null pointer to a zero-terminated string. + * + * \pre The \a overflow_marker length must not exceed the \a max_size limit. + */ +template< typename CharT > +BOOST_FORCEINLINE aux::max_size_decorator_gen< CharT > max_size_decor(std::size_t max_size, const CharT* overflow_marker) +{ + return aux::max_size_decorator_gen< CharT >(max_size, overflow_marker); +} + +/*! + * The function returns a decorator generator object. The generator provides <tt>operator[]</tt> that can be used + * to construct the actual decorator. + * + * \param max_size The maximum number of characters (i.e. string element objects) that the decorated formatter can produce. + * \param overflow_marker The marker string which is appended to the output if the \a max_size limit is exceeded. + * + * \pre The \a overflow_marker length must not exceed the \a max_size limit. + */ +template< typename CharT > +BOOST_FORCEINLINE aux::max_size_decorator_gen< CharT > max_size_decor(std::size_t max_size, std::basic_string< CharT > const& overflow_marker) +{ + return aux::max_size_decorator_gen< CharT >(max_size, overflow_marker); +} + +} // namespace expressions + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +#ifndef BOOST_LOG_DOXYGEN_PASS + +namespace phoenix { + +namespace result_of { + +template< typename SubactorT, typename CharT > +struct is_nullary< custom_terminal< boost::log::expressions::max_size_decorator_terminal< SubactorT, CharT > > > : + public mpl::false_ +{ +}; + +template< typename LeftT, typename SubactorT, typename CharT > +struct is_nullary< custom_terminal< boost::log::expressions::aux::max_size_decorator_output_terminal< LeftT, SubactorT, CharT > > > : + public mpl::false_ +{ +}; + +} // namespace result_of + +} // namespace phoenix + +#endif + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_EXPRESSIONS_FORMATTERS_MAX_SIZE_DECORATOR_HPP_INCLUDED_ diff --git a/boost/log/expressions/formatters/named_scope.hpp b/boost/log/expressions/formatters/named_scope.hpp index cc45dc6e81..ae140b1956 100644 --- a/boost/log/expressions/formatters/named_scope.hpp +++ b/boost/log/expressions/formatters/named_scope.hpp @@ -21,7 +21,7 @@ #include <boost/static_assert.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/parameter/binding.hpp> #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> @@ -257,8 +257,10 @@ template< typename FallbackPolicyT, typename CharT > class format_named_scope_terminal { public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Attribute value type typedef attributes::named_scope::value_type value_type; @@ -337,7 +339,7 @@ public: stream_type strm(str); m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type&, stream_type& >(m_formatter, strm)); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } //! Invokation operator @@ -348,7 +350,7 @@ public: stream_type strm(str); m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type const&, stream_type& >(m_formatter, strm)); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } BOOST_DELETED_FUNCTION(format_named_scope_terminal()) diff --git a/boost/log/expressions/formatters/wrap_formatter.hpp b/boost/log/expressions/formatters/wrap_formatter.hpp index 612be28d70..29c19c2f80 100644 --- a/boost/log/expressions/formatters/wrap_formatter.hpp +++ b/boost/log/expressions/formatters/wrap_formatter.hpp @@ -17,7 +17,7 @@ #include <string> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/mpl/has_xxx.hpp> #include <boost/phoenix/core/actor.hpp> #include <boost/phoenix/core/terminal_fwd.hpp> @@ -53,8 +53,10 @@ private: typedef wrapped_formatter_output_terminal< LeftT, FunT > this_type; public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Wrapped function type typedef FunT function_type; @@ -156,8 +158,10 @@ template< typename FunT, typename CharT > class wrapped_formatter_terminal { public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Character type typedef CharT char_type; @@ -199,7 +203,7 @@ public: stream_type strm(str); m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } //! Invokation operator @@ -210,7 +214,7 @@ public: stream_type strm(str); m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm); strm.flush(); - return boost::move(str); + return BOOST_LOG_NRVO_RESULT(str); } }; diff --git a/boost/log/expressions/predicates/channel_severity_filter.hpp b/boost/log/expressions/predicates/channel_severity_filter.hpp index 079b79233d..c7430a1bd7 100644 --- a/boost/log/expressions/predicates/channel_severity_filter.hpp +++ b/boost/log/expressions/predicates/channel_severity_filter.hpp @@ -57,8 +57,10 @@ template< class channel_severity_filter_terminal { public: +#ifndef BOOST_LOG_DOXYGEN_PASS //! Internal typedef for type categorization typedef void _is_boost_log_terminal; +#endif //! Function result type typedef bool result_type; diff --git a/boost/log/keywords/block_size.hpp b/boost/log/keywords/block_size.hpp new file mode 100644 index 0000000000..daaa91fc25 --- /dev/null +++ b/boost/log/keywords/block_size.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 keywords/block_size.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * The header contains the \c block_size keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_BLOCK_SIZE_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_BLOCK_SIZE_HPP_INCLUDED_ + +#include <boost/parameter/keyword.hpp> +#include <boost/log/detail/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass interprocess queue name to the queue constructor +BOOST_PARAMETER_KEYWORD(tag, block_size) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_BLOCK_SIZE_HPP_INCLUDED_ diff --git a/boost/log/keywords/capacity.hpp b/boost/log/keywords/capacity.hpp new file mode 100644 index 0000000000..d7b6345ce8 --- /dev/null +++ b/boost/log/keywords/capacity.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 keywords/capacity.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * The header contains the \c capacity keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_CAPACITY_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_CAPACITY_HPP_INCLUDED_ + +#include <boost/parameter/keyword.hpp> +#include <boost/log/detail/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass interprocess queue capacity to the queue constructor +BOOST_PARAMETER_KEYWORD(tag, capacity) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_CAPACITY_HPP_INCLUDED_ diff --git a/boost/log/keywords/name.hpp b/boost/log/keywords/name.hpp new file mode 100644 index 0000000000..d0f93d3d74 --- /dev/null +++ b/boost/log/keywords/name.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 keywords/name.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * The header contains the \c name keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_NAME_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_NAME_HPP_INCLUDED_ + +#include <boost/parameter/keyword.hpp> +#include <boost/log/detail/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass interprocess queue name to the queue constructor +BOOST_PARAMETER_KEYWORD(tag, name) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_NAME_HPP_INCLUDED_ diff --git a/boost/log/keywords/overflow_policy.hpp b/boost/log/keywords/overflow_policy.hpp new file mode 100644 index 0000000000..e66450d824 --- /dev/null +++ b/boost/log/keywords/overflow_policy.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 keywords/overflow_policy.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * The header contains the \c overflow_policy keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_OVERFLOW_POLICY_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_OVERFLOW_POLICY_HPP_INCLUDED_ + +#include <boost/parameter/keyword.hpp> +#include <boost/log/detail/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass interprocess queue overflow policy to the queue constructor +BOOST_PARAMETER_KEYWORD(tag, overflow_policy) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_OVERFLOW_POLICY_HPP_INCLUDED_ diff --git a/boost/log/keywords/permissions.hpp b/boost/log/keywords/permissions.hpp new file mode 100644 index 0000000000..4b2451a0ab --- /dev/null +++ b/boost/log/keywords/permissions.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 keywords/permissions.hpp + * \author Andrey Semashev + * \date 23.02.2016 + * + * The header contains the \c permissions keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_PERMISSIONS_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_PERMISSIONS_HPP_INCLUDED_ + +#include <boost/parameter/keyword.hpp> +#include <boost/log/detail/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass interprocess queue permissions to the queue constructor +BOOST_PARAMETER_KEYWORD(tag, permissions) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_PERMISSIONS_HPP_INCLUDED_ diff --git a/boost/log/sinks.hpp b/boost/log/sinks.hpp index 0969b31d3c..d22d1c1d1e 100644 --- a/boost/log/sinks.hpp +++ b/boost/log/sinks.hpp @@ -33,6 +33,7 @@ #include <boost/log/sinks/syslog_backend.hpp> #include <boost/log/sinks/text_file_backend.hpp> +#include <boost/log/sinks/text_ipc_message_queue_backend.hpp> #include <boost/log/sinks/text_multifile_backend.hpp> #include <boost/log/sinks/text_ostream_backend.hpp> #ifdef BOOST_WINDOWS diff --git a/boost/log/sinks/async_frontend.hpp b/boost/log/sinks/async_frontend.hpp index c0209bfb2f..ec5371006e 100644 --- a/boost/log/sinks/async_frontend.hpp +++ b/boost/log/sinks/async_frontend.hpp @@ -32,6 +32,8 @@ #include <boost/atomic/atomic.hpp> #include <boost/smart_ptr/shared_ptr.hpp> #include <boost/smart_ptr/make_shared_object.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/comparison/equal.hpp> #include <boost/thread/locks.hpp> #include <boost/thread/recursive_mutex.hpp> #include <boost/thread/thread.hpp> @@ -54,7 +56,31 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, types)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ + template< typename T0 >\ + explicit asynchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ + base_type(true),\ + queue_base_type(arg0),\ + m_pBackend(boost::make_shared< sink_backend_type >(arg0)),\ + m_StopRequested(false),\ + m_FlushRequested(false)\ + {\ + if (arg0[keywords::start_thread | true])\ + start_feeding_thread();\ + }\ + template< typename T0 >\ + explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, T0 const& arg0) :\ + base_type(true),\ + queue_base_type(arg0),\ + m_pBackend(backend),\ + m_StopRequested(false),\ + m_FlushRequested(false)\ + {\ + if (arg0[keywords::start_thread | true])\ + start_feeding_thread();\ + } + +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit asynchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ base_type(true),\ @@ -78,6 +104,9 @@ namespace sinks { start_feeding_thread();\ } +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + #endif // BOOST_LOG_DOXYGEN_PASS /*! @@ -254,8 +283,23 @@ public: start_feeding_thread(); } - // Constructors that pass arbitrary parameters to the backend constructor + /*! + * Constructor that passes arbitrary named parameters to the interprocess sink backend constructor. + * Refer to the backend documentation for the list of supported parameters. + * + * The frontend uses the following named parameters: + * + * \li start_thread - If \c true, the frontend creates a thread to feed + * log records to the backend. Otherwise no thread is + * started and it is assumed that the user will call + * either \c run or \c feed_records himself. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~) +#else + template< typename... Args > + explicit asynchronous_sink(Args&&... args); +#endif /*! * Destructor. Implicitly stops the dedicated feeding thread, if one is running. @@ -455,6 +499,8 @@ private: #endif // BOOST_LOG_DOXYGEN_PASS }; +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1 +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N #undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL } // namespace sinks diff --git a/boost/log/sinks/attribute_mapping.hpp b/boost/log/sinks/attribute_mapping.hpp index c14f5e7841..24cfe3387e 100644 --- a/boost/log/sinks/attribute_mapping.hpp +++ b/boost/log/sinks/attribute_mapping.hpp @@ -83,7 +83,7 @@ namespace aux { template< typename T > void operator() (T const& val) const { - mapped_type v = { val }; + mapped_type v = { static_cast< IntT >(val) }; m_Extracted = v; } diff --git a/boost/log/sinks/basic_sink_frontend.hpp b/boost/log/sinks/basic_sink_frontend.hpp index 965451c7a8..3686bc5917 100644 --- a/boost/log/sinks/basic_sink_frontend.hpp +++ b/boost/log/sinks/basic_sink_frontend.hpp @@ -17,7 +17,6 @@ #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> @@ -29,7 +28,6 @@ #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> #endif // !defined(BOOST_LOG_NO_THREADS) @@ -186,13 +184,10 @@ protected: 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()) + if (!backend_mutex.try_lock()) return false; - lock.swap(tmp_lock); } catch (thread_interrupted&) { @@ -206,6 +201,8 @@ protected: this->exception_handler()(); return false; } + + boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex); #endif // No need to lock anything in the feed_record method boost::log::aux::fake_mutex m; @@ -280,6 +277,28 @@ protected: private: struct formatting_context { + class cleanup_guard + { + private: + formatting_context& m_context; + + public: + explicit cleanup_guard(formatting_context& ctx) BOOST_NOEXCEPT : m_context(ctx) + { + } + + ~cleanup_guard() + { + m_context.m_FormattedRecord.clear(); + m_context.m_FormattingStream.rdbuf()->max_size(m_context.m_FormattedRecord.max_size()); + m_context.m_FormattingStream.rdbuf()->storage_overflow(false); + m_context.m_FormattingStream.clear(); + } + + BOOST_DELETED_FUNCTION(cleanup_guard(cleanup_guard const&)) + BOOST_DELETED_FUNCTION(cleanup_guard& operator=(cleanup_guard const&)) + }; + #if !defined(BOOST_LOG_NO_THREADS) //! Object version const unsigned int m_Version; @@ -431,8 +450,7 @@ protected: 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); + typename formatting_context::cleanup_guard cleanup(*context); try { @@ -464,13 +482,10 @@ protected: 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()) + if (!backend_mutex.try_lock()) return false; - lock.swap(tmp_lock); } catch (thread_interrupted&) { @@ -484,6 +499,8 @@ protected: this->exception_handler()(); return false; } + + boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex); #endif // No need to lock anything in the feed_record method boost::log::aux::fake_mutex m; diff --git a/boost/log/sinks/sync_frontend.hpp b/boost/log/sinks/sync_frontend.hpp index 6d3a57f4ee..6a927d0571 100644 --- a/boost/log/sinks/sync_frontend.hpp +++ b/boost/log/sinks/sync_frontend.hpp @@ -28,6 +28,8 @@ #include <boost/static_assert.hpp> #include <boost/smart_ptr/shared_ptr.hpp> #include <boost/smart_ptr/make_shared_object.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/comparison/equal.hpp> #include <boost/thread/recursive_mutex.hpp> #include <boost/log/detail/locking_ptr.hpp> #include <boost/log/detail/parameter_tools.hpp> @@ -44,12 +46,21 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ + template< typename T0 >\ + explicit synchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ + base_type(false),\ + m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {} + +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit synchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ base_type(false),\ m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {} +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + #endif // BOOST_LOG_DOXYGEN_PASS /*! @@ -115,8 +126,16 @@ public: { } - // Constructors that pass arbitrary parameters to the backend constructor + /*! + * Constructor that passes arbitrary named parameters to the interprocess sink backend constructor. + * Refer to the backend documentation for the list of supported parameters. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~) +#else + template< typename... Args > + explicit synchronous_sink(Args&&... args); +#endif /*! * Locking accessor to the attached backend @@ -153,6 +172,8 @@ public: } }; +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1 +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N #undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL } // namespace sinks diff --git a/boost/log/sinks/text_ipc_message_queue_backend.hpp b/boost/log/sinks/text_ipc_message_queue_backend.hpp new file mode 100644 index 0000000000..370ccfb32f --- /dev/null +++ b/boost/log/sinks/text_ipc_message_queue_backend.hpp @@ -0,0 +1,172 @@ +/* + * Copyright Lingxi Li 2015. + * Copyright Andrey Semashev 2016. + * 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 text_ipc_message_queue_backend.hpp + * \author Lingxi Li + * \author Andrey Semashev + * \date 14.10.2015 + * + * The header contains implementation of a text interprocess message queue sink + * backend along with implementation of a supporting interprocess message queue. + */ + +#ifndef BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ +#define BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ + +#include <limits> +#include <string> +#include <boost/cstdint.hpp> +#include <boost/move/core.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/comparison/equal.hpp> +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/parameter_tools.hpp> +#include <boost/log/core/record_view.hpp> +#include <boost/log/sinks/basic_sink_backend.hpp> +#include <boost/log/sinks/frontend_requirements.hpp> +#include <boost/log/exceptions.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace sinks { + +#ifndef BOOST_LOG_DOXYGEN_PASS + +#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1(n, data)\ + template< typename T0 >\ + explicit text_ipc_message_queue_backend(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ + m_queue(arg0) {} + +#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N(n, data)\ + template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ + explicit text_ipc_message_queue_backend(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ + m_queue(BOOST_PP_ENUM_PARAMS(n, arg)) {} + +#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL(z, n, data)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N)(n, data) + +#endif // BOOST_LOG_DOXYGEN_PASS + +/*! + * \brief An implementation of a text interprocess message queue sink backend and + * a supporting interprocess message queue. + * + * The sink backend sends formatted log messages to an interprocess message queue + * which can be extracted by a viewer process. Methods of this class are not + * thread-safe, unless otherwise specified. + */ +template< typename QueueT > +class text_ipc_message_queue_backend : + public basic_formatted_sink_backend< char, concurrent_feeding > +{ + //! Base type + typedef basic_formatted_sink_backend< char, concurrent_feeding > base_type; + +public: + //! Character type + typedef base_type::char_type char_type; + //! String type to be used as a message text holder + typedef base_type::string_type string_type; + //! Interprocess message queue type + typedef QueueT queue_type; + +private: + //! Interprocess queue + queue_type m_queue; + +public: + /*! + * Default constructor. The method constructs the backend using the default-constructed + * interprocess message queue. The queue may need additional setup in order to be able + * to send messages. + */ + text_ipc_message_queue_backend() BOOST_NOEXCEPT + { + } + + /*! + * Initializing constructor. The method constructs the backend using the provided + * interprocess message queue. The constructor moves from the provided queue. + */ + explicit text_ipc_message_queue_backend(BOOST_RV_REF(queue_type) queue) BOOST_NOEXCEPT : + m_queue(static_cast< BOOST_RV_REF(queue_type) >(queue)) + { + } + + /*! + * Constructor that passes arbitrary named parameters to the interprocess queue constructor. + * Refer to the queue documentation for the list of supported parameters. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS + BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL, ~) +#else + template< typename... Args > + explicit text_ipc_message_queue_backend(Args&&... args); +#endif + + /*! + * The method returns a reference to the managed \c queue_type object. + * + * \return A reference to the managed \c queue_type object. + */ + queue_type& message_queue() BOOST_NOEXCEPT { return m_queue; } + + /*! + * The method returns a constant reference to the managed \c queue_type object. + * + * \return A constant reference to the managed \c queue_type object. + */ + queue_type const& message_queue() const BOOST_NOEXCEPT { return m_queue; } + + /*! + * Tests whether the object is associated with any message queue. Only when the backend has + * an associated message queue, will any message be sent. + * + * \return \c true if the object is associated with a message queue, and \c false otherwise. + */ + bool is_open() const BOOST_NOEXCEPT { return m_queue.is_open(); } + + /*! + * The method writes the message to the backend. Concurrent calls to this method + * are allowed. Therefore, the backend may be used with unlocked frontend. <tt>stop_local()</tt> + * can be used to have a blocked <tt>consume()</tt> call return and prevent future + * calls to <tt>consume()</tt> from blocking. + */ + void consume(record_view const&, string_type const& formatted_message) + { + if (m_queue.is_open()) + { + typedef typename queue_type::size_type size_type; + const string_type::size_type size = formatted_message.size(); + if (BOOST_UNLIKELY(size > static_cast< string_type::size_type >((std::numeric_limits< size_type >::max)()))) + BOOST_LOG_THROW_DESCR(limitation_error, "Message too long to send to an interprocess queue"); + m_queue.send(formatted_message.data(), static_cast< size_type >(size)); + } + } +}; + +#undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1 +#undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N +#undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL + +} // namespace sinks + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ diff --git a/boost/log/sinks/text_multifile_backend.hpp b/boost/log/sinks/text_multifile_backend.hpp index 82c18bf4d9..8e707b990c 100644 --- a/boost/log/sinks/text_multifile_backend.hpp +++ b/boost/log/sinks/text_multifile_backend.hpp @@ -113,6 +113,9 @@ namespace file { /*! * The function adopts a log record formatter into a file name generator + * + * \param fmt The formatter function object to adopt + * \param loc The locale to use to character code conversion and formatting */ template< typename FormatterT > inline file_name_composer_adapter< FormatterT > as_file_name_composer( diff --git a/boost/log/sinks/unlocked_frontend.hpp b/boost/log/sinks/unlocked_frontend.hpp index b7b0d353c4..918efeb6d2 100644 --- a/boost/log/sinks/unlocked_frontend.hpp +++ b/boost/log/sinks/unlocked_frontend.hpp @@ -18,6 +18,8 @@ #include <boost/static_assert.hpp> #include <boost/smart_ptr/shared_ptr.hpp> #include <boost/smart_ptr/make_shared_object.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/comparison/equal.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/parameter_tools.hpp> #include <boost/log/detail/fake_mutex.hpp> @@ -37,12 +39,21 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, types)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ + template< typename T0 >\ + explicit unlocked_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ + base_type(false),\ + m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {} + +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit unlocked_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ base_type(false),\ m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {} +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + #endif // BOOST_LOG_DOXYGEN_PASS /*! @@ -94,8 +105,16 @@ public: { } - // Constructors that pass arbitrary parameters to the backend constructor + /*! + * Constructor that passes arbitrary named parameters to the interprocess sink backend constructor. + * Refer to the backend documentation for the list of supported parameters. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~) +#else + template< typename... Args > + explicit unlocked_sink(Args&&... args); +#endif /*! * Locking accessor to the attached backend. @@ -129,6 +148,8 @@ public: } }; +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1 +#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N #undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL } // namespace sinks diff --git a/boost/log/sources/basic_logger.hpp b/boost/log/sources/basic_logger.hpp index bc35acf3a8..58bd6594c5 100644 --- a/boost/log/sources/basic_logger.hpp +++ b/boost/log/sources/basic_logger.hpp @@ -21,8 +21,8 @@ #include <ostream> #include <boost/assert.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/core/addressof.hpp> #include <boost/preprocessor/facilities/empty.hpp> #include <boost/preprocessor/facilities/identity.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> diff --git a/boost/log/sources/channel_feature.hpp b/boost/log/sources/channel_feature.hpp index aa0349010c..d7e88c4aad 100644 --- a/boost/log/sources/channel_feature.hpp +++ b/boost/log/sources/channel_feature.hpp @@ -17,7 +17,7 @@ #include <string> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/locks.hpp> #include <boost/log/detail/default_attribute_names.hpp> diff --git a/boost/log/sources/exception_handler_feature.hpp b/boost/log/sources/exception_handler_feature.hpp index bd77fca528..d29041109d 100644 --- a/boost/log/sources/exception_handler_feature.hpp +++ b/boost/log/sources/exception_handler_feature.hpp @@ -17,7 +17,7 @@ #include <boost/mpl/if.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/light_function.hpp> diff --git a/boost/log/sources/global_logger_storage.hpp b/boost/log/sources/global_logger_storage.hpp index a98e5e63e1..dad41a128c 100644 --- a/boost/log/sources/global_logger_storage.hpp +++ b/boost/log/sources/global_logger_storage.hpp @@ -37,7 +37,7 @@ namespace sources { namespace aux { //! The base class for logger holders -struct BOOST_LOG_NO_VTABLE BOOST_SYMBOL_VISIBLE logger_holder_base +struct logger_holder_base { //! The source file name where the logger was registered const char* const m_RegistrationFile; @@ -52,12 +52,11 @@ struct BOOST_LOG_NO_VTABLE BOOST_SYMBOL_VISIBLE logger_holder_base m_LoggerType(logger_type) { } - virtual ~logger_holder_base() {} }; //! The actual logger holder class template< typename LoggerT > -struct BOOST_SYMBOL_VISIBLE logger_holder : +struct logger_holder : public logger_holder_base { //! The logger instance @@ -68,6 +67,14 @@ struct BOOST_SYMBOL_VISIBLE logger_holder : m_Logger(logger) { } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + logger_holder(const char* file, unsigned int line, LoggerT&& logger) : + logger_holder_base(file, line, typeindex::type_id< LoggerT >()), + m_Logger(static_cast< LoggerT&& >(logger)) + { + } +#endif }; //! The class implements a global repository of tagged loggers @@ -122,8 +129,8 @@ struct logger_singleton : if (holder->m_LoggerType == logger_type_index) { // Note: dynamic_cast may fail here if logger_type is not visible (for example, with Clang on Linux, if the original logger - // instance was initialized in a different DSO than where it's being queried). logger_holder default visibility doesn't - // help since it is inhibited by the template parameter visibility. + // instance was initialized in a different DSO than where it's being queried). logger_holder visibility doesn't + // have effect since it is inhibited by the template parameter visibility. instance = boost::static_pointer_cast< logger_holder< logger_type > >(holder); } else @@ -133,7 +140,7 @@ struct logger_singleton : // happen if the same-named tag is defined differently in two or more // dlls. This check is intended to detect such ODR violations. However, there // is no protection against different definitions of the logger type itself. - throw_odr_violation(tag_type_index, logger_type_index, *holder); + boost::log::sources::aux::throw_odr_violation(tag_type_index, logger_type_index, *holder); } } diff --git a/boost/log/sources/record_ostream.hpp b/boost/log/sources/record_ostream.hpp index c1e80593aa..5fac8742b7 100644 --- a/boost/log/sources/record_ostream.hpp +++ b/boost/log/sources/record_ostream.hpp @@ -20,8 +20,8 @@ #include <ostream> #include <boost/assert.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/core/addressof.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/native_typeof.hpp> #include <boost/log/detail/unhandled_exception_count.hpp> diff --git a/boost/log/sources/severity_feature.hpp b/boost/log/sources/severity_feature.hpp index 6ecf95e551..101769bda1 100644 --- a/boost/log/sources/severity_feature.hpp +++ b/boost/log/sources/severity_feature.hpp @@ -19,7 +19,7 @@ #include <boost/static_assert.hpp> #include <boost/smart_ptr/intrusive_ptr.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/locks.hpp> #include <boost/log/detail/default_attribute_names.hpp> diff --git a/boost/log/support/date_time.hpp b/boost/log/support/date_time.hpp index e1c9050adb..468f02fa40 100644 --- a/boost/log/support/date_time.hpp +++ b/boost/log/support/date_time.hpp @@ -22,7 +22,7 @@ #include <iterator> #include <boost/cstdint.hpp> #include <boost/move/core.hpp> -#include <boost/move/utility.hpp> +#include <boost/move/utility_core.hpp> #include <boost/date_time/time.hpp> #include <boost/date_time/date.hpp> #include <boost/date_time/gregorian/gregorian_types.hpp> diff --git a/boost/log/support/exception.hpp b/boost/log/support/exception.hpp index f6d9be20d5..160521d3c9 100644 --- a/boost/log/support/exception.hpp +++ b/boost/log/support/exception.hpp @@ -15,6 +15,7 @@ #ifndef BOOST_LOG_SUPPORT_EXCEPTION_HPP_INCLUDED_ #define BOOST_LOG_SUPPORT_EXCEPTION_HPP_INCLUDED_ +#include <string> #include <boost/type_index.hpp> #include <boost/exception/info.hpp> #include <boost/log/detail/config.hpp> @@ -63,6 +64,17 @@ inline current_scope_info current_scope() return current_scope_info(attributes::named_scope::get_scopes()); } +namespace ipc { + +class object_name; + +/*! + * System resource name + */ +typedef error_info< struct object_name_tag, object_name > object_name_info; + +} // namespace ipc + BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost diff --git a/boost/log/support/spirit_classic.hpp b/boost/log/support/spirit_classic.hpp index 36a680ac6f..5f117388d8 100644 --- a/boost/log/support/spirit_classic.hpp +++ b/boost/log/support/spirit_classic.hpp @@ -16,7 +16,7 @@ #define BOOST_LOG_SUPPORT_SPIRIT_CLASSIC_HPP_INCLUDED_ #include <boost/mpl/bool.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/utility/functional/matches.hpp> diff --git a/boost/log/support/spirit_qi.hpp b/boost/log/support/spirit_qi.hpp index 027552670a..e335d1ae55 100644 --- a/boost/log/support/spirit_qi.hpp +++ b/boost/log/support/spirit_qi.hpp @@ -15,7 +15,7 @@ #ifndef BOOST_LOG_SUPPORT_SPIRIT_QI_HPP_INCLUDED_ #define BOOST_LOG_SUPPORT_SPIRIT_QI_HPP_INCLUDED_ -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/spirit/include/qi_parse.hpp> #include <boost/spirit/include/qi_domain.hpp> #include <boost/spirit/include/support_unused.hpp> @@ -40,7 +40,7 @@ struct boost_spirit_qi_expression_tag; //! The metafunction detects the matching expression kind and returns a tag that is used to specialize \c match_traits template< typename ExpressionT > -struct matching_expression_kind< ExpressionT, typename boost::enable_if< spirit::traits::matches< spirit::qi::domain, ExpressionT > >::type > +struct matching_expression_kind< ExpressionT, typename boost::enable_if_c< spirit::traits::matches< spirit::qi::domain, ExpressionT >::value >::type > { typedef boost_spirit_qi_expression_tag type; }; diff --git a/boost/log/utility/exception_handler.hpp b/boost/log/utility/exception_handler.hpp index 6b369704d1..9b8551ac0d 100644 --- a/boost/log/utility/exception_handler.hpp +++ b/boost/log/utility/exception_handler.hpp @@ -22,10 +22,10 @@ #include <boost/mpl/placeholders.hpp> #include <boost/mpl/has_xxx.hpp> #include <boost/mpl/vector.hpp> +#include <boost/core/enable_if.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> -#include <boost/utility/enable_if.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/utility/functional/nop.hpp> #include <boost/log/detail/header.hpp> @@ -228,8 +228,8 @@ inline nop make_exception_suppressor() #ifndef BOOST_LOG_DOXYGEN_PASS template< typename HandlerT > -inline typename lazy_enable_if< - aux::has_exception_types< HandlerT >, +inline typename boost::lazy_enable_if_c< + aux::has_exception_types< HandlerT >::value, aux::make_self_contained_exception_handler< exception_handler, HandlerT > >::type make_exception_handler(HandlerT const& handler) { @@ -238,8 +238,8 @@ inline typename lazy_enable_if< } template< typename HandlerT > -inline typename lazy_enable_if< - aux::has_exception_types< HandlerT >, +inline typename boost::lazy_enable_if_c< + aux::has_exception_types< HandlerT >::value, aux::make_self_contained_exception_handler< nothrow_exception_handler, HandlerT > >::type make_exception_handler(HandlerT const& handler, std::nothrow_t const&) { diff --git a/boost/log/utility/formatting_ostream.hpp b/boost/log/utility/formatting_ostream.hpp index d3732d36f4..4a79998b1c 100644 --- a/boost/log/utility/formatting_ostream.hpp +++ b/boost/log/utility/formatting_ostream.hpp @@ -245,7 +245,7 @@ public: */ string_type const& str() const { - string_type* storage = m_streambuf.storage(); + string_type* const storage = m_streambuf.storage(); BOOST_ASSERT(storage != NULL); m_streambuf.pubsync(); @@ -372,8 +372,12 @@ public: { m_stream.flush(); - string_type* storage = m_streambuf.storage(); - aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc()); + if (!m_streambuf.storage_overflow()) + { + string_type* storage = m_streambuf.storage(); + if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc())) + m_streambuf.storage_overflow(true); + } } return *this; @@ -643,9 +647,10 @@ public: } #endif -private: +protected: void init_stream() { + m_stream.exceptions(ostream_type::goodbit); m_stream.clear(m_streambuf.storage() ? ostream_type::goodbit : ostream_type::badbit); m_stream.flags ( @@ -658,6 +663,7 @@ private: m_stream.fill(static_cast< char_type >(' ')); } +private: basic_formatting_ostream& formatted_write(const char_type* p, std::streamsize size) { sentry guard(*this); @@ -666,7 +672,7 @@ private: m_stream.flush(); if (m_stream.width() <= size) - m_streambuf.storage()->append(p, static_cast< std::size_t >(size)); + m_streambuf.append(p, static_cast< std::size_t >(size)); else this->aligned_write(p, size); @@ -685,7 +691,13 @@ private: m_stream.flush(); if (m_stream.width() <= size) - aux::code_convert(p, static_cast< std::size_t >(size), *m_streambuf.storage(), m_stream.getloc()); + { + if (!m_streambuf.storage_overflow()) + { + if (!aux::code_convert(p, static_cast< std::size_t >(size), *m_streambuf.storage(), m_streambuf.max_size(), m_stream.getloc())) + m_streambuf.storage_overflow(true); + } + } else this->aligned_write(p, size); @@ -780,19 +792,18 @@ BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, Allo template< typename CharT, typename TraitsT, typename AllocatorT > void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const char_type* p, std::streamsize size) { - string_type* const storage = m_streambuf.storage(); typename string_type::size_type const alignment_size = static_cast< typename string_type::size_type >(m_stream.width() - size); const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left; if (align_left) { - storage->append(p, static_cast< std::size_t >(size)); - storage->append(alignment_size, m_stream.fill()); + m_streambuf.append(p, static_cast< std::size_t >(size)); + m_streambuf.append(alignment_size, m_stream.fill()); } else { - storage->append(alignment_size, m_stream.fill()); - storage->append(p, static_cast< std::size_t >(size)); + m_streambuf.append(alignment_size, m_stream.fill()); + m_streambuf.append(p, static_cast< std::size_t >(size)); } } @@ -806,13 +817,21 @@ void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left; if (align_left) { - aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc()); - storage->append(alignment_size, m_stream.fill()); + if (!m_streambuf.storage_overflow()) + { + if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc())) + m_streambuf.storage_overflow(true); + } + m_streambuf.append(alignment_size, m_stream.fill()); } else { - storage->append(alignment_size, m_stream.fill()); - aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc()); + m_streambuf.append(alignment_size, m_stream.fill()); + if (!m_streambuf.storage_overflow()) + { + if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc())) + m_streambuf.storage_overflow(true); + } } } diff --git a/boost/log/utility/ipc/object_name.hpp b/boost/log/utility/ipc/object_name.hpp new file mode 100644 index 0000000000..582ecdcbf3 --- /dev/null +++ b/boost/log/utility/ipc/object_name.hpp @@ -0,0 +1,271 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 utility/ipc/object_name.hpp + * \author Andrey Semashev + * \date 05.03.2016 + * + * The header contains declaration of a system object name wrapper. + */ + +#ifndef BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <cstddef> +#include <iosfwd> +#include <string> +#include <boost/move/core.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +/*! + * \brief A system object name class + * + * In order to identify a system-wide object such as a shared memory segment or a named synchronization primitive the object has to be given a name. + * The format of the name is specific to the operating system and the \c object_name class provides an abstraction for names of objects. It also + * provides means for scoping, which allows to avoid name clashes between different processes. + * + * The object name is a UTF-8 encoded string. The portable object name should consist of the following characters: + * + * <pre> + * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + * a b c d e f g h i j k l m n o p q r s t u v w x y z + * 0 1 2 3 4 5 6 7 8 9 . _ - + * </pre> + * + * \note The character set corresponds to the POSIX Portable Filename Character Set (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_278). + * + * Use of other characters may result in non-portable system-specific behavior. + * + * The name can have one of the following scopes: + * + * \li \c global - objects within this scope are visible to any process on the system. In order to use this scope the process may need to have + * extended privileges. This scope is not available for Windows Store applications. + * \li \c user - objects within this scope can be opened by processes running under the same user as the current process. + * \li \c session - objects within this scope are visible to processes within the session of the current process. The definition of a session may vary between + * operating systems. On POSIX, a session is typically a group of processes attached to a single virtual terminal device. On Windows a session is + * started when a user logs into the system. There is also a separate session for Windows services. + * \li \c process_group - objects within this scope are visible to processes within the process group of the current process. Currently, on Windows all processes + * running in the current session are considered members of the same process group. This may change in future. + * + * The scopes are not overlapping. For instance, if an object is created in the global scope, the object cannot be opened with the same name but in user's scope. + * + * Note that name scoping is not a security feature. On some systems any process on the system has technical capability to open objects within any scope. + * The scope is only used to help avoid name clashes between processes using \c object_name to identify objects. + */ +class object_name +{ +public: + //! Name scopes + enum scope + { + global, //!< The name has global scope; any process in the system has the potential to open the resource identified by the name + user, //!< The name is limited to processes running under the current user + session, //!< The name is limited to processes running in the current login session + process_group //!< The name is limited to processes running in the current process group + }; + +#if !defined(BOOST_LOG_DOXYGEN_PASS) + + BOOST_COPYABLE_AND_MOVABLE(object_name) + +private: + std::string m_name; + +#endif // !defined(BOOST_LOG_DOXYGEN_PASS) + +public: + /*! + * Default constructor. The method creates an empty object name. + * + * \post <tt>empty() == true</tt> + */ + object_name() BOOST_NOEXCEPT + { + } + + /*! + * Move constructor. + */ + object_name(BOOST_RV_REF(object_name) that) BOOST_NOEXCEPT + { + m_name.swap(that.m_name); + } + + /*! + * Copy constructor. + */ + object_name(object_name const& that) : m_name(that.m_name) + { + } + + /*! + * Constructor from the native string. + * + * \param str The object name string, must not be \c NULL. The string format is specific to the operating system. + */ + static object_name from_native(const char* str) + { + object_name name; + name.m_name = str; + return name; + } + + /*! + * Constructor from the native string. + * + * \param str The object name string. The string format is specific to the operating system. + */ + static object_name from_native(std::string const& str) + { + object_name name; + name.m_name = str; + return name; + } + + /*! + * Constructor from the object name + * \param ns The scope of the object name + * \param str The object name, must not be NULL. + */ + BOOST_LOG_API object_name(scope ns, const char* str); + + /*! + * Constructor from the object name + * \param ns The scope of the object name + * \param str The object name + */ + BOOST_LOG_API object_name(scope ns, std::string const& str); + + /*! + * Move assignment + */ + object_name& operator= (BOOST_RV_REF(object_name) that) BOOST_NOEXCEPT + { + m_name.clear(); + m_name.swap(that.m_name); + return *this; + } + + /*! + * Copy assignment + */ + object_name& operator= (BOOST_COPY_ASSIGN_REF(object_name) that) + { + m_name = that.m_name; + return *this; + } + + /*! + * Returns \c true if the object name is empty + */ + bool empty() const BOOST_NOEXCEPT { return m_name.empty(); } + + /*! + * Returns length of the name, in bytes + */ + std::size_t size() const BOOST_NOEXCEPT { return m_name.size(); } + + /*! + * Returns the name string + */ + const char* c_str() const BOOST_NOEXCEPT { return m_name.c_str(); } + + /*! + * Swaps the object name with another object name + */ + void swap(object_name& that) BOOST_NOEXCEPT { m_name.swap(that.m_name); } + + /*! + * Swaps two object names + */ + friend void swap(object_name& left, object_name& right) BOOST_NOEXCEPT + { + left.swap(right); + } + + /*! + * Returns string representation of the object name + */ + friend std::string to_string(object_name const& name) + { + return name.m_name; + } + + /*! + * Equality operator + */ + friend bool operator== (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name == right.m_name; + } + /*! + * Inequality operator + */ + friend bool operator!= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name != right.m_name; + } + /*! + * Less operator + */ + friend bool operator< (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name < right.m_name; + } + /*! + * Greater operator + */ + friend bool operator> (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name > right.m_name; + } + /*! + * Less or equal operator + */ + friend bool operator<= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name <= right.m_name; + } + /*! + * Greater or equal operator + */ + friend bool operator>= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name >= right.m_name; + } + + /*! + * Stream ouput operator + */ + template< typename CharT, typename TraitsT > + friend std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, object_name const& name) + { + strm << name.c_str(); + return strm; + } +}; + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ diff --git a/boost/log/utility/ipc/reliable_message_queue.hpp b/boost/log/utility/ipc/reliable_message_queue.hpp new file mode 100644 index 0000000000..934d6ab299 --- /dev/null +++ b/boost/log/utility/ipc/reliable_message_queue.hpp @@ -0,0 +1,776 @@ +/* + * Copyright Lingxi Li 2015. + * Copyright Andrey Semashev 2016. + * 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 utility/ipc/reliable_message_queue.hpp + * \author Lingxi Li + * \author Andrey Semashev + * \date 01.01.2016 + * + * The header contains declaration of a reliable interprocess message queue. + */ + +#ifndef BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <cstddef> +#include <boost/cstdint.hpp> +#include <boost/move/core.hpp> +#include <boost/log/keywords/open_mode.hpp> +#include <boost/log/keywords/name.hpp> +#include <boost/log/keywords/capacity.hpp> +#include <boost/log/keywords/block_size.hpp> +#include <boost/log/keywords/overflow_policy.hpp> +#include <boost/log/keywords/permissions.hpp> +#include <boost/log/utility/open_mode.hpp> +#include <boost/log/utility/permissions.hpp> +#include <boost/log/utility/ipc/object_name.hpp> +#include <boost/log/detail/parameter_tools.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +namespace aux { + +template< typename T, typename R > +struct enable_if_byte {}; +template< typename R > +struct enable_if_byte< char, R > { typedef R type; }; +template< typename R > +struct enable_if_byte< signed char, R > { typedef R type; }; +template< typename R > +struct enable_if_byte< unsigned char, R > { typedef R type; }; + +} // namespace aux + +/*! + * \brief A reliable interprocess message queue + * + * The queue implements a reliable one-way channel of passing messages from one or multiple writers to a single reader. + * The format of the messages is user-defined and must be consistent across all writers and the reader. The queue does + * not enforce any specific format of the messages, other than they should be supplied as a contiguous array of bytes. + * + * The queue internally uses a process-shared storage identified by an \c object_name (the queue name). Refer to \c object_name + * documentation for details on restrictions imposed on object names. + * + * The queue storage is organized as a fixed number of blocks of a fixed size. The block size must be an integer power of 2 and + * is expressed in bytes. Each written message, together with some metadata added by the queue, consumes an integer number + * of blocks. Each read message received by the reader releases the blocks allocated for that message. As such the maximum size + * of a message is slightly less than block size times capacity of the queue. For efficiency, it is recommended to choose + * block size large enough to accommodate most of the messages to be passed through the queue. + * + * The queue is considered empty when no messages are enqueued (all blocks are free). The queue is considered full at the point + * of enqueueing a message when there is not enough free blocks to accommodate the message. + * + * The queue is reliable in that it will not drop successfully sent messages that are not received by the reader, other than the + * case when a non-empty queue is destroyed by the last user. If a message cannot be enqueued by the writer because the queue is + * full, the queue can either block the writer or return an error or throw an exception, depending on the policy specified at + * the queue creation. The policy is object local, i.e. different writers and the reader can have different overflow policies. + * + * If the queue is empty and the reader attempts to dequeue a message, it will block until a message is enqueued by a writer. + * + * A blocked reader or writer can be unblocked by calling \c stop_local. After this method is called, all threads blocked on + * this particular object are released and return \c operation_result::aborted. The other instances of the queue (in the current + * or other processes) are unaffected. In order to restore the normal functioning of the queue instance after the \c stop_local + * call the user has to invoke \c reset_local. + * + * The queue does not guarantee any particular order of received messages from different writer threads. Messages sent by a + * particular writer thread will be received in the order of sending. + * + * Methods of this class are not thread-safe, unless otherwise specified. + */ +class reliable_message_queue +{ +public: + //! Result codes for various operations on the queue + enum operation_result + { + succeeded, //!< The operation has completed successfully + no_space, //!< The message could not be sent because the queue is full + aborted //!< The operation has been aborted because the queue method <tt>stop_local()</tt> has been called + }; + + //! Interprocess queue overflow policies + enum overflow_policy + { + //! Block the send operation when the queue is full + block_on_overflow, + //! Return \c operation_result::no_space when the queue is full + fail_on_overflow, + //! Throw \c capacity_limit_reached exception when the queue is full + throw_on_overflow + }; + + //! Queue message size type + typedef uint32_t size_type; + +#if !defined(BOOST_LOG_DOXYGEN_PASS) + + BOOST_MOVABLE_BUT_NOT_COPYABLE(reliable_message_queue) + +private: + typedef void (*receive_handler)(void* state, const void* data, size_type size); + + struct fixed_buffer_state + { + uint8_t* data; + size_type size; + }; + + struct implementation; + implementation* m_impl; + +#endif // !defined(BOOST_LOG_DOXYGEN_PASS) + +public: + /*! + * Default constructor. The method constructs an object that is not associated with any + * message queue. + * + * \post <tt>is_open() == false</tt> + */ + BOOST_CONSTEXPR reliable_message_queue() BOOST_NOEXCEPT : m_impl(NULL) + { + } + + /*! + * Constructor. The method is used to construct an object and create the associated + * message queue. The constructed object will be in running state if the message queue is + * successfully created. + * + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param capacity Maximum number of allocation blocks the queue can hold. + * \param block_size Size in bytes of allocation block. Must be a power of 2. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. + */ + reliable_message_queue + ( + open_mode::create_only_tag, + object_name const& name, + uint32_t capacity, + size_type block_size, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ) : + m_impl(NULL) + { + this->create(name, capacity, block_size, oflow_policy, perms); + } + + /*! + * Constructor. The method is used to construct an object and create or open the associated + * message queue. The constructed object will be in running state if the message queue is + * successfully created or opened. If the message queue that is identified by the name already + * exists then the other queue parameters are ignored. The actual queue parameters can be obtained + * with accessors from the constructed object. + * + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param capacity Maximum number of allocation blocks the queue can hold. + * \param block_size Size in bytes of allocation block. Must be a power of 2. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. + */ + reliable_message_queue + ( + open_mode::open_or_create_tag, + object_name const& name, + uint32_t capacity, + size_type block_size, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ) : + m_impl(NULL) + { + this->open_or_create(name, capacity, block_size, oflow_policy, perms); + } + + /*! + * Constructor. The method is used to construct an object and open the existing + * message queue. The constructed object will be in running state if the message queue is + * successfully opened. + * + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. The permissions will only be used + * if the queue implementation has to create system objects while operating. + * This parameter is currently not used on POSIX systems. + */ + reliable_message_queue + ( + open_mode::open_only_tag, + object_name const& name, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ) : + m_impl(NULL) + { + this->open(name, oflow_policy, perms); + } + + /*! + * Constructor with named parameters. The method is used to construct an object and create or open + * the associated message queue. The constructed object will be in running state if the message queue is + * successfully created. + * + * The following named parameters are accepted: + * + * * open_mode - One of the open mode tags: \c open_mode::create_only, \c open_mode::open_only or + * \c open_mode::open_or_create. + * * name - Name of the message queue to be associated with. + * * capacity - Maximum number of allocation blocks the queue can hold. Used only if the queue is created. + * * block_size - Size in bytes of allocation block. Must be a power of 2. Used only if the queue is created. + * * overflow_policy - Queue behavior policy in case of overflow, see \c overflow_policy. + * * permissions - Access permissions for the associated message queue. + * + * \post <tt>is_open() == true</tt> + */ +#if !defined(BOOST_LOG_DOXYGEN_PASS) + BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(reliable_message_queue, construct) +#else + template< typename... Args > + explicit reliable_message_queue(Args const&... args); +#endif + + /*! + * Destructor. Calls <tt>close()</tt>. + */ + ~reliable_message_queue() BOOST_NOEXCEPT + { + this->close(); + } + + /*! + * Move constructor. The method move-constructs an object from \c other. After + * the call, the constructed object becomes \c other, while \c other is left in + * default constructed state. + * + * \param that The object to be moved. + */ + reliable_message_queue(BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT : + m_impl(that.m_impl) + { + that.m_impl = NULL; + } + + /*! + * Move assignment operator. If the object is associated with a message queue, + * <tt>close()</tt> is first called and the precondition to calling <tt>close()</tt> + * applies. After the call, the object becomes \a that while \a that is left + * in default constructed state. + * + * \param that The object to be moved. + * + * \return A reference to the assigned object. + */ + reliable_message_queue& operator= (BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT + { + reliable_message_queue other(static_cast< BOOST_RV_REF(reliable_message_queue) >(that)); + this->swap(other); + return *this; + } + + /*! + * The method swaps the object with \a that. + * + * \param that The other object to swap with. + */ + void swap(reliable_message_queue& that) BOOST_NOEXCEPT + { + implementation* p = m_impl; + m_impl = that.m_impl; + that.m_impl = p; + } + + //! Swaps the two \c reliable_message_queue objects. + friend void swap(reliable_message_queue& a, reliable_message_queue& b) BOOST_NOEXCEPT + { + a.swap(b); + } + + /*! + * The method creates the message queue to be associated with the object. After the call, + * the object will be in running state if a message queue is successfully created. + * + * \pre <tt>is_open() == false</tt> + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param capacity Maximum number of allocation blocks the queue can hold. + * \param block_size Size in bytes of allocation block. Must be a power of 2. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. + */ + BOOST_LOG_API void create + ( + object_name const& name, + uint32_t capacity, + size_type block_size, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ); + + /*! + * The method creates or opens the message queue to be associated with the object. + * After the call, the object will be in running state if a message queue is successfully + * created or opened. If the message queue that is identified by the name already exists then + * the other queue parameters are ignored. The actual queue parameters can be obtained + * with accessors from this object after this method returns. + * + * \pre <tt>is_open() == false</tt> + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param capacity Maximum number of allocation blocks the queue can hold. + * \param block_size Size in bytes of allocation block. Must be a power of 2. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. + */ + BOOST_LOG_API void open_or_create + ( + object_name const& name, + uint32_t capacity, + size_type block_size, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ); + + /*! + * The method opens the existing message queue to be associated with the object. + * After the call, the object will be in running state if a message queue is successfully + * opened. + * + * \pre <tt>is_open() == false</tt> + * \post <tt>is_open() == true</tt> + * + * \param name Name of the message queue to be associated with. + * \param oflow_policy Queue behavior policy in case of overflow. + * \param perms Access permissions for the associated message queue. The permissions will only be used + * if the queue implementation has to create system objects while operating. + * This parameter is currently not used on POSIX systems. + */ + BOOST_LOG_API void open + ( + object_name const& name, + overflow_policy oflow_policy = block_on_overflow, + permissions const& perms = permissions() + ); + + /*! + * Tests whether the object is associated with any message queue. + * + * \return \c true if the object is associated with a message queue, and \c false otherwise. + */ + bool is_open() const BOOST_NOEXCEPT + { + return m_impl != NULL; + } + + /*! + * This method empties the associated message queue. Concurrent calls to this method, <tt>send()</tt>, + * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, and <tt>stop_local()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + */ + BOOST_LOG_API void clear(); + + /*! + * The method returns the name of the associated message queue. + * + * \pre <tt>is_open() == true</tt> + * + * \return Name of the associated message queue + */ + BOOST_LOG_API object_name const& name() const; + + /*! + * The method returns the maximum number of allocation blocks the associated message queue + * can hold. Note that the returned value may be different from the corresponding + * value passed to the constructor or <tt>open_or_create()</tt>, for the message queue may + * not have been created by this object. + * + * \pre <tt>is_open() == true</tt> + * + * \return Maximum number of allocation blocks the associated message queue can hold. + */ + BOOST_LOG_API uint32_t capacity() const; + + /*! + * The method returns the allocation block size, in bytes. Each message in the + * associated message queue consumes an integer number of allocation blocks. + * Note that the returned value may be different from the corresponding value passed + * to the constructor or <tt>open_or_create()</tt>, for the message queue may not + * have been created by this object. + * + * \pre <tt>is_open() == true</tt> + * + * \return Allocation block size, in bytes. + */ + BOOST_LOG_API size_type block_size() const; + + /*! + * The method wakes up all threads that are blocked in calls to <tt>send()</tt> or + * <tt>receive()</tt>. Those calls would then return \c false with \c errno \c EINTR. + * Note that, the method does not block until the woken-up threads have actually + * returned from <tt>send()</tt> or <tt>receive()</tt>. Other means is needed to ensure + * that calls to <tt>send()</tt> or <tt>receive()</tt> have returned, e.g., joining the + * threads that might be blocking on the calls. + * + * The method also puts the object in stopped state. When in stopped state, calls to + * <tt>send()</tt> or <tt>receive()</tt> will return immediately with return value + * \c false and \c errno \c EINTR when they would otherwise block in running state. + * + * Concurrent calls to this method, <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + */ + BOOST_LOG_API void stop_local(); + + /*! + * The method puts the object in running state where calls to <tt>send()</tt> or + * <tt>receive()</tt> may block. This method is not thread-safe. + * + * \pre <tt>is_open() == true</tt> + */ + BOOST_LOG_API void reset_local(); + + /*! + * The method disassociates the associated message queue, if any. No other threads + * should be using this object before calling this method. The <tt>stop_local()</tt> method + * can be used to have any threads currently blocked in <tt>send()</tt> or + * <tt>receive()</tt> return, and prevent further calls to them from blocking. Typically, + * before calling this method, one would first call <tt>stop_local()</tt> and then join all + * threads that might be blocking on <tt>send()</tt> or <tt>receive()</tt> to ensure that + * they have returned from the calls. The associated message queue is destroyed if the + * object represents the last outstanding reference to it. + * + * \post <tt>is_open() == false</tt> + */ + void close() BOOST_NOEXCEPT + { + if (is_open()) + do_close(); + } + + /*! + * The method sends a message to the associated message queue. When the object is in + * running state and the queue has no free space for the message, the method either blocks + * or throws an exception, depending on the overflow policy that was specified on the queue + * opening/creation. If blocking policy is in effect, the blocking can be interrupted by + * calling <tt>stop_local()</tt>, in which case the method returns \c operation_result::aborted. + * When the object is already in the stopped state, the method does not block but returns + * immediately with return value \c operation_result::aborted. + * + * It is possible to send an empty message by passing \c 0 to the parameter \c message_size. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, + * <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param message_data The message data to send. Ignored when \c message_size is \c 0. + * \param message_size Size of the message data in bytes. If the size is larger than + * the associated message queue capacity, an <tt>std::logic_error</tt> exception is thrown. + * + * \retval operation_result::succeeded if the operation is successful + * \retval operation_result::no_space if \c overflow_policy::fail_on_overflow is in effect and the queue is full + * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt> + * + * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue + * capacity, <tt>system_error</tt> in case if a native OS method fails. + */ + BOOST_LOG_API operation_result send(void const* message_data, size_type message_size); + + /*! + * The method performs an attempt to send a message to the associated message queue. + * The method is non-blocking, and always returns immediately. + * <tt>boost::system::system_error</tt> is thrown for errors resulting from native + * operating system calls. Note that it is possible to send an empty message by passing + * \c 0 to the parameter \c message_size. Concurrent calls to <tt>send()</tt>, + * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, <tt>stop_local()</tt>, + * and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param message_data The message data to send. Ignored when \c message_size is \c 0. + * \param message_size Size of the message data in bytes. If the size is larger than the + * maximum size allowed by the associated message queue, an + * <tt>std::logic_error</tt> exception is thrown. + * + * \return \c true if the message is successfully sent, and \c false otherwise (e.g., + * when the queue is full). + * + * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue + * capacity, <tt>system_error</tt> in case if a native OS method fails. + */ + BOOST_LOG_API bool try_send(void const* message_data, size_type message_size); + + /*! + * The method takes a message from the associated message queue. When the object is in + * running state and the queue is empty, the method blocks. The blocking is interrupted + * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted. + * When the object is already in the stopped state and the queue is empty, the method + * does not block but returns immediately with return value \c operation_result::aborted. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param buffer The memory buffer to store the received message in. + * \param buffer_size The size of the buffer, in bytes. + * \param message_size Receives the size of the received message, in bytes. + * + * \retval operation_result::succeeded if the operation is successful + * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt> + */ + operation_result receive(void* buffer, size_type buffer_size, size_type& message_size) + { + fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size }; + operation_result result = do_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state); + message_size = buffer_size - state.size; + return result; + } + + /*! + * The method takes a message from the associated message queue. When the object is in + * running state and the queue is empty, the method blocks. The blocking is interrupted + * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted. + * When the object is already in the stopped state and the queue is empty, the method + * does not block but returns immediately with return value \c operation_result::aborted. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param buffer The memory buffer to store the received message in. + * \param message_size Receives the size of the received message, in bytes. + * + * \retval operation_result::succeeded if the operation is successful + * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt> + */ + template< typename ElementT, size_type SizeV > +#if !defined(BOOST_LOG_DOXYGEN_PASS) + typename aux::enable_if_byte< ElementT, operation_result >::type +#else + operation_result +#endif + receive(ElementT (&buffer)[SizeV], size_type& message_size) + { + return receive(buffer, SizeV, message_size); + } + + /*! + * The method takes a message from the associated message queue. When the object is in + * running state and the queue is empty, the method blocks. The blocking is interrupted + * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted. + * When the object is already in the stopped state and the queue is empty, the method + * does not block but returns immediately with return value \c operation_result::aborted. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param container The container to store the received message in. The container should have + * value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt> + * and support inserting elements at the end. + * + * \retval operation_result::succeeded if the operation is successful + * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt> + */ + template< typename ContainerT > +#if !defined(BOOST_LOG_DOXYGEN_PASS) + typename aux::enable_if_byte< typename ContainerT::value_type, operation_result >::type +#else + operation_result +#endif + receive(ContainerT& container) + { + return do_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container); + } + + /*! + * The method performs an attempt to take a message from the associated message queue. The + * method is non-blocking, and always returns immediately. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param buffer The memory buffer to store the received message in. + * \param buffer_size The size of the buffer, in bytes. + * \param message_size Receives the size of the received message, in bytes. + * + * \return \c true if a message is successfully received, and \c false otherwise (e.g., + * when the queue is empty). + */ + bool try_receive(void* buffer, size_type buffer_size, size_type& message_size) + { + fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size }; + bool result = do_try_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state); + message_size = buffer_size - state.size; + return result; + } + + /*! + * The method performs an attempt to take a message from the associated message queue. The + * method is non-blocking, and always returns immediately. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param buffer The memory buffer to store the received message in. + * \param message_size Receives the size of the received message, in bytes. + * + * \return \c true if a message is successfully received, and \c false otherwise (e.g., + * when the queue is empty). + */ + template< typename ElementT, size_type SizeV > +#if !defined(BOOST_LOG_DOXYGEN_PASS) + typename aux::enable_if_byte< ElementT, bool >::type +#else + bool +#endif + try_receive(ElementT (&buffer)[SizeV], size_type& message_size) + { + return try_receive(buffer, SizeV, message_size); + } + + /*! + * The method performs an attempt to take a message from the associated message queue. The + * method is non-blocking, and always returns immediately. + * + * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, + * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed. + * + * \pre <tt>is_open() == true</tt> + * + * \param container The container to store the received message in. The container should have + * value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt> + * and support inserting elements at the end. + * + * \return \c true if a message is successfully received, and \c false otherwise (e.g., + * when the queue is empty). + */ + template< typename ContainerT > +#if !defined(BOOST_LOG_DOXYGEN_PASS) + typename aux::enable_if_byte< typename ContainerT::value_type, bool >::type +#else + bool +#endif + try_receive(ContainerT& container) + { + return do_try_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container); + } + + /*! + * The method frees system-wide resources, associated with the interprocess queue with the supplied name. + * The queue referred to by the specified name must not be opened in any process at the point of this call. + * After this call succeeds a new queue with the specified name can be created. + * + * This call can be useful to recover from an earlier process misbehavior (e.g. a crash without properly + * closing the message queue). In this case resources allocated for the interprocess queue may remain + * allocated after the last process closed the queue, which in turn may prevent creating a new queue with + * the same name. By calling this method before creating a queue the application can attempt to ensure + * it starts with a clean slate. + * + * On some platforms resources associated with the queue are automatically reclaimed by the operating system + * when the last process using those resources terminates (even if it terminates abnormally). On these + * platforms this call may be a no-op. However, portable code should still call this method at appropriate + * places to ensure compatibility with other platforms and future library versions, which may change implementation + * of the queue. + * + * \param name Name of the message queue to be removed. + */ + static BOOST_LOG_API void remove(object_name const& name); + +#if !defined(BOOST_LOG_DOXYGEN_PASS) +private: + //! Implementation of the constructor with named arguments + template< typename ArgsT > + void construct(ArgsT const& args) + { + m_impl = NULL; + construct_dispatch(args[keywords::open_mode], args); + } + + //! Implementation of the constructor with named arguments + template< typename ArgsT > + void construct_dispatch(open_mode::create_only_tag, ArgsT const& args) + { + this->create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + } + + //! Implementation of the constructor with named arguments + template< typename ArgsT > + void construct_dispatch(open_mode::open_or_create_tag, ArgsT const& args) + { + this->open_or_create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + } + + //! Implementation of the constructor with named arguments + template< typename ArgsT > + void construct_dispatch(open_mode::open_only_tag, ArgsT const& args) + { + this->open(args[keywords::name], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + } + + //! Closes the message queue, if it's open + BOOST_LOG_API void do_close() BOOST_NOEXCEPT; + + //! Receives the message from the queue and calls the handler to place the data in the user's storage + BOOST_LOG_API operation_result do_receive(receive_handler handler, void* state); + //! Attempts to receives the message from the queue and calls the handler to place the data in the user's storage + BOOST_LOG_API bool do_try_receive(receive_handler handler, void* state); + + //! Fixed buffer receive handler + static BOOST_LOG_API void fixed_buffer_receive_handler(void* state, const void* data, size_type size); + //! Receive handler for a container + template< typename ContainerT > + static void container_receive_handler(void* state, const void* data, size_type size) + { + ContainerT* const container = static_cast< ContainerT* >(state); + container->insert + ( + container->end(), + static_cast< typename ContainerT::value_type const* >(data), + static_cast< typename ContainerT::value_type const* >(data) + size + ); + } +#endif +}; + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_ diff --git a/boost/log/utility/manipulators/dump.hpp b/boost/log/utility/manipulators/dump.hpp index dc1856a47a..3341376f39 100644 --- a/boost/log/utility/manipulators/dump.hpp +++ b/boost/log/utility/manipulators/dump.hpp @@ -200,7 +200,7 @@ inline dump_manip dump_elements(T* data, std::size_t count) BOOST_NOEXCEPT * \brief Creates a stream manipulator that will output contents of a memory region in hexadecimal form * \param data The pointer to the beginning of the region * \param size The size of the region, in bytes - * \params max_size The maximum number of bytes of the region to output + * \param max_size The maximum number of bytes of the region to output * \return The manipulator that is to be put to a stream */ template< typename T > @@ -213,7 +213,7 @@ inline typename aux::enable_dump< T, bounded_dump_manip >::type dump(T* data, st * \brief Creates a stream manipulator that will dump elements of an array in hexadecimal form * \param data The pointer to the beginning of the array * \param count The size of the region, in number of \c T elements - * \params max_count The maximum number of elements to output + * \param max_count The maximum number of elements to output * \return The manipulator that is to be put to a stream */ template< typename T > diff --git a/boost/log/utility/open_mode.hpp b/boost/log/utility/open_mode.hpp new file mode 100644 index 0000000000..34a3d8d1aa --- /dev/null +++ b/boost/log/utility/open_mode.hpp @@ -0,0 +1,46 @@ +/* + * Copyright Andrey Semashev 2016. + * 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 open_mode.hpp + * \author Andrey Semashev + * \date 01.01.2016 + * + * The header defines resource opening modes. + */ + +#ifndef BOOST_LOG_UTILITY_OPEN_MODE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_OPEN_MODE_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace open_mode { + +//! Create a new resource; fail if exists already +struct create_only_tag {} const create_only = create_only_tag(); +//! Opens an existing resource; fail if not exist +struct open_only_tag {} const open_only = open_only_tag(); +//! Creates a new resource or opens an existing one +struct open_or_create_tag {} const open_or_create = open_or_create_tag(); + +} // namespace open_mode + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_UTILITY_OPEN_MODE_HPP_INCLUDED_ diff --git a/boost/log/utility/permissions.hpp b/boost/log/utility/permissions.hpp new file mode 100644 index 0000000000..e35649a185 --- /dev/null +++ b/boost/log/utility/permissions.hpp @@ -0,0 +1,213 @@ +/* + * Copyright Lingxi Li 2015. + * Copyright Andrey Semashev 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 permissions.hpp + * \author Lingxi Li + * \author Andrey Semashev + * \date 14.10.2015 + * + * The header contains an abstraction wrapper for security permissions. + */ + +#ifndef BOOST_LOG_UTILITY_PERMISSIONS_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_PERMISSIONS_HPP_INCLUDED_ + +#include <boost/log/detail/config.hpp> +#include <boost/log/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifdef BOOST_WINDOWS +extern "C" { +struct _SECURITY_ATTRIBUTES; +} +#endif // BOOST_WINDOWS + +namespace boost { + +#ifdef BOOST_WINDOWS +namespace detail { +namespace winapi { +struct BOOST_LOG_MAY_ALIAS _SECURITY_ATTRIBUTES; +} +} +#endif + +namespace interprocess { +class permissions; +} // namespace interprocess + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * \brief Access permissions wrapper. + * + * On Windows platforms, it represents a pointer to \c SECURITY_ATTRIBUTES. The user is responsible + * for allocating and reclaiming resources associated with the pointer, \c permissions instance does + * not own them. + * + * On POSIX platforms, it represents a \c mode_t value. + */ +class permissions +{ +public: +#if defined(BOOST_LOG_DOXYGEN_PASS) + //! The type of security permissions, specific to the operating system + typedef implementation_defined native_type; +#elif defined(BOOST_WINDOWS) + typedef ::_SECURITY_ATTRIBUTES* native_type; +#else + // Equivalent to POSIX mode_t + typedef unsigned int native_type; +#endif + +#if !defined(BOOST_LOG_DOXYGEN_PASS) +private: + native_type m_perms; +#endif + +public: + /*! + * Default constructor. The method constructs an object that represents + * a null \c SECURITY_ATTRIBUTES pointer on Windows platforms, and a + * \c mode_t value \c 0644 on POSIX platforms. + */ + permissions() BOOST_NOEXCEPT + { + set_default(); + } + + /*! + * Copy constructor. + */ + permissions(permissions const& that) BOOST_NOEXCEPT : m_perms(that.m_perms) + { + } + + /*! + * Copy assignment. + */ + permissions& operator=(permissions const& that) BOOST_NOEXCEPT + { + m_perms = that.m_perms; + return *this; + } + + /*! + * Initializing constructor. + */ + permissions(native_type perms) BOOST_NOEXCEPT : m_perms(perms) + { + } + +#ifdef BOOST_WINDOWS + permissions(boost::detail::winapi::_SECURITY_ATTRIBUTES* perms) BOOST_NOEXCEPT : m_perms(reinterpret_cast< native_type >(perms)) + { + } +#endif + + /*! + * Initializing constructor. + */ + BOOST_LOG_API permissions(boost::interprocess::permissions const& perms) BOOST_NOEXCEPT; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + /*! + * Move constructor. + */ + permissions(permissions&& that) BOOST_NOEXCEPT : m_perms(that.m_perms) + { + that.set_default(); + } + + /*! + * Move assignment. + */ + permissions& operator=(permissions&& that) BOOST_NOEXCEPT + { + m_perms = that.m_perms; + that.set_default(); + return *this; + } +#endif + + /*! + * Sets permissions from the OS-specific permissions. + */ + void set_native(native_type perms) BOOST_NOEXCEPT + { + m_perms = perms; + } + + /*! + * Returns the underlying OS-specific permissions. + */ + native_type get_native() const BOOST_NOEXCEPT + { + return m_perms; + } + + /*! + * Sets the default permissions, which are equivalent to \c NULL \c SECURITY_ATTRIBUTES + * on Windows and \c 0644 on POSIX platforms. + */ + void set_default() BOOST_NOEXCEPT + { +#if defined(BOOST_WINDOWS) + m_perms = 0; +#else + m_perms = 0644; +#endif + } + + /*! + * Sets unrestricted permissions, which are equivalent to \c SECURITY_ATTRIBUTES with \c NULL DACL + * on Windows and \c 0666 on POSIX platforms. + */ + void set_unrestricted() + { +#if defined(BOOST_WINDOWS) + m_perms = get_unrestricted_security_attributes(); +#else + m_perms = 0666; +#endif + } + + /*! + * The method swaps the object with \a that. + * + * \param that The other object to swap with. + */ + void swap(permissions& that) BOOST_NOEXCEPT + { + native_type perms = m_perms; + m_perms = that.m_perms; + that.m_perms = perms; + } + + //! Swaps the two \c permissions objects. + friend void swap(permissions& a, permissions& b) BOOST_NOEXCEPT + { + a.swap(b); + } + +#if !defined(BOOST_LOG_DOXYGEN_PASS) && defined(BOOST_WINDOWS) +private: + static BOOST_LOG_API native_type get_unrestricted_security_attributes(); +#endif +}; + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include <boost/log/detail/footer.hpp> + +#endif // BOOST_LOG_UTILITY_PERMISSIONS_HPP_INCLUDED_ diff --git a/boost/log/utility/record_ordering.hpp b/boost/log/utility/record_ordering.hpp index f77cd49c43..f9963f62b8 100644 --- a/boost/log/utility/record_ordering.hpp +++ b/boost/log/utility/record_ordering.hpp @@ -15,7 +15,7 @@ #ifndef BOOST_LOG_UTILITY_RECORD_ORDERING_HPP_INCLUDED_ #define BOOST_LOG_UTILITY_RECORD_ORDERING_HPP_INCLUDED_ -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/function_traits.hpp> @@ -196,10 +196,10 @@ namespace aux { //! An ordering predicate constructor that uses SFINAE to disable invalid instantiations template< typename FunT, - typename ArityCheckT = typename enable_if_c< aux::arity_of< FunT >::value == 2 >::type, + typename ArityCheckT = typename boost::enable_if_c< aux::arity_of< FunT >::value == 2 >::type, typename Arg1T = typename aux::first_argument_type_of< FunT >::type, typename Arg2T = typename aux::second_argument_type_of< FunT >::type, - typename ArgsCheckT = typename enable_if< is_same< Arg1T, Arg2T > >::type + typename ArgsCheckT = typename boost::enable_if_c< is_same< Arg1T, Arg2T >::value >::type > struct make_attr_ordering_type { diff --git a/boost/log/utility/setup/filter_parser.hpp b/boost/log/utility/setup/filter_parser.hpp index 854ac72caf..f9aa831caf 100644 --- a/boost/log/utility/setup/filter_parser.hpp +++ b/boost/log/utility/setup/filter_parser.hpp @@ -21,7 +21,7 @@ #include <boost/smart_ptr/make_shared_object.hpp> #include <boost/phoenix/operator/comparison.hpp> #include <boost/type_traits/is_base_and_derived.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/log/detail/setup_config.hpp> #include <boost/log/detail/code_conversion.hpp> #include <boost/log/exceptions.hpp> @@ -242,8 +242,8 @@ BOOST_LOG_SETUP_API void register_filter_factory( * \param factory The filter factory */ template< typename FactoryT > -inline typename enable_if< - is_base_and_derived< filter_factory< typename FactoryT::char_type >, FactoryT > +inline typename boost::enable_if_c< + is_base_and_derived< filter_factory< typename FactoryT::char_type >, FactoryT >::value >::type register_filter_factory(attribute_name const& name, shared_ptr< FactoryT > const& factory) { typedef filter_factory< typename FactoryT::char_type > factory_base; diff --git a/boost/log/utility/setup/formatter_parser.hpp b/boost/log/utility/setup/formatter_parser.hpp index 8bdc2bca86..250c75c1d2 100644 --- a/boost/log/utility/setup/formatter_parser.hpp +++ b/boost/log/utility/setup/formatter_parser.hpp @@ -21,7 +21,7 @@ #include <string> #include <boost/smart_ptr/shared_ptr.hpp> #include <boost/smart_ptr/make_shared_object.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/log/detail/setup_config.hpp> #include <boost/log/attributes/attribute_name.hpp> @@ -136,8 +136,8 @@ BOOST_LOG_SETUP_API void register_formatter_factory( * \param factory Pointer to the formatter factory */ template< typename FactoryT > -inline typename enable_if< - is_base_and_derived< formatter_factory< typename FactoryT::char_type >, FactoryT > +inline typename boost::enable_if_c< + is_base_and_derived< formatter_factory< typename FactoryT::char_type >, FactoryT >::value >::type register_formatter_factory(attribute_name const& attr_name, shared_ptr< FactoryT > const& factory) { typedef formatter_factory< typename FactoryT::char_type > factory_base; diff --git a/boost/log/utility/setup/from_settings.hpp b/boost/log/utility/setup/from_settings.hpp index 27691bf2da..be1c1bc0b6 100644 --- a/boost/log/utility/setup/from_settings.hpp +++ b/boost/log/utility/setup/from_settings.hpp @@ -18,7 +18,7 @@ #include <string> #include <boost/smart_ptr/shared_ptr.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/log/detail/setup_config.hpp> #include <boost/log/sinks/sink.hpp> @@ -126,8 +126,8 @@ inline void register_sink_factory(std::string const& sink_name, shared_ptr< sink * \param factory Pointer to the custom sink factory. Must not be NULL. */ template< typename FactoryT > -inline typename enable_if< - is_base_and_derived< sink_factory< typename FactoryT::char_type >, FactoryT > +inline typename boost::enable_if_c< + is_base_and_derived< sink_factory< typename FactoryT::char_type >, FactoryT >::value >::type register_sink_factory(const char* sink_name, shared_ptr< FactoryT > const& factory) { typedef sink_factory< typename FactoryT::char_type > factory_base; @@ -147,8 +147,8 @@ inline typename enable_if< * \param factory Pointer to the custom sink factory. Must not be NULL. */ template< typename FactoryT > -inline typename enable_if< - is_base_and_derived< sink_factory< typename FactoryT::char_type >, FactoryT > +inline typename boost::enable_if_c< + is_base_and_derived< sink_factory< typename FactoryT::char_type >, FactoryT >::value >::type register_sink_factory(std::string const& sink_name, shared_ptr< FactoryT > const& factory) { typedef sink_factory< typename FactoryT::char_type > factory_base; diff --git a/boost/log/utility/setup/settings.hpp b/boost/log/utility/setup/settings.hpp index 67b1f2339e..e63fea1200 100644 --- a/boost/log/utility/setup/settings.hpp +++ b/boost/log/utility/setup/settings.hpp @@ -28,7 +28,7 @@ #include <boost/log/detail/native_typeof.hpp> #include <boost/utility/explicit_operator_bool.hpp> #if !defined(BOOST_LOG_TYPEOF) -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #endif #if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) #include <boost/utility/declval.hpp> @@ -254,7 +254,7 @@ private: } template< typename T > - typename enable_if< boost::property_tree::detail::is_character< T >, std::basic_string< T > >::type + 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) diff --git a/boost/log/utility/strictest_lock.hpp b/boost/log/utility/strictest_lock.hpp index 9735961f92..5dd48b4ffb 100644 --- a/boost/log/utility/strictest_lock.hpp +++ b/boost/log/utility/strictest_lock.hpp @@ -79,6 +79,11 @@ struct thread_access_mode_of< lock_guard< MutexT > > : mpl::integral_c< lock_acc }; template< typename MutexT > +struct thread_access_mode_of< shared_lock_guard< MutexT > > : mpl::integral_c< lock_access_mode, shared_access > +{ +}; + +template< typename MutexT > struct thread_access_mode_of< unique_lock< MutexT > > : mpl::integral_c< lock_access_mode, exclusive_access > { }; diff --git a/boost/log/utility/string_literal.hpp b/boost/log/utility/string_literal.hpp index 0b737000bf..af5bf3640a 100644 --- a/boost/log/utility/string_literal.hpp +++ b/boost/log/utility/string_literal.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2016. * 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) @@ -21,12 +21,11 @@ #include <ios> // std::streamsize #include <string> #include <iterator> -#include <boost/operators.hpp> #include <boost/throw_exception.hpp> #include <boost/type_traits/is_same.hpp> -#include <boost/utility/enable_if.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/utility/string_literal_fwd.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #include <boost/log/detail/header.hpp> #ifdef BOOST_HAS_PRAGMA_ONCE @@ -50,16 +49,6 @@ BOOST_LOG_OPEN_NAMESPACE */ template< typename CharT, typename TraitsT > class basic_string_literal - //! \cond - : public totally_ordered1< basic_string_literal< CharT, TraitsT >, - totally_ordered2< basic_string_literal< CharT, TraitsT >, const CharT*, - totally_ordered2< - basic_string_literal< CharT, TraitsT >, - std::basic_string< CharT, TraitsT > - > - > - > - //! \endcond { //! Self type typedef basic_string_literal< CharT, TraitsT > this_type; @@ -84,8 +73,12 @@ private: //! Length size_type m_Len; - //! Empty string literal to support clear + //! Empty string literal to support \c clear +#if !defined(BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS) + static constexpr value_type g_EmptyString[1] = { 0 }; +#else static const value_type g_EmptyString[1]; +#endif public: /*! @@ -93,7 +86,7 @@ public: * * \post <tt>empty() == true</tt> */ - basic_string_literal() BOOST_NOEXCEPT { clear(); } + BOOST_CONSTEXPR basic_string_literal() BOOST_NOEXCEPT : m_pStart(g_EmptyString), m_Len(0) { } /*! * Constructor from a string literal @@ -102,9 +95,9 @@ public: * \param p A zero-terminated constant sequence of characters */ template< typename T, size_type LenV > - basic_string_literal(T(&p)[LenV] + BOOST_CONSTEXPR basic_string_literal(T(&p)[LenV] //! \cond - , typename enable_if< is_same< T, const value_type >, int >::type = 0 + , typename boost::enable_if_c< is_same< T, const value_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy() //! \endcond ) BOOST_NOEXCEPT : m_pStart(p), m_Len(LenV - 1) @@ -117,7 +110,7 @@ public: * \post <tt>*this == that</tt> * \param that Source literal to copy string from */ - basic_string_literal(basic_string_literal const& that) BOOST_NOEXCEPT : m_pStart(that.m_pStart), m_Len(that.m_Len) {} + BOOST_CONSTEXPR basic_string_literal(basic_string_literal const& that) BOOST_NOEXCEPT : m_pStart(that.m_pStart), m_Len(that.m_Len) {} /*! * Assignment operator @@ -125,7 +118,7 @@ public: * \post <tt>*this == that</tt> * \param that Source literal to copy string from */ - this_type& operator= (this_type const& that) BOOST_NOEXCEPT + BOOST_CXX14_CONSTEXPR this_type& operator= (this_type const& that) BOOST_NOEXCEPT { return assign(that); } @@ -136,9 +129,10 @@ public: * \param p A zero-terminated constant sequence of characters */ template< typename T, size_type LenV > + BOOST_CXX14_CONSTEXPR #ifndef BOOST_LOG_DOXYGEN_PASS - typename enable_if< - is_same< T, const value_type >, + typename boost::enable_if_c< + is_same< T, const value_type >::value, this_type& >::type #else @@ -175,12 +169,43 @@ public: * \param that Comparand * \return \c true if the comparand string equals to this string, \c false otherwise */ - bool operator== (string_type const& that) const + bool operator== (string_type const& that) const BOOST_NOEXCEPT { return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) == 0); } /*! + * Lexicographical comparison (inequality) + * + * \param that Comparand + * \return \c true if the comparand string is not equal to this string, \c false otherwise + */ + bool operator!= (this_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) != 0); + } + /*! + * Lexicographical comparison (inequality) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if the comparand string is not equal to this string, \c false otherwise + */ + bool operator!= (const_pointer str) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) != 0); + } + /*! + * Lexicographical comparison (inequality) + * + * \param that Comparand + * \return \c true if the comparand string is not equal to this string, \c false otherwise + */ + bool operator!= (string_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) != 0); + } + + /*! * Lexicographical comparison (less ordering) * * \param that Comparand @@ -206,12 +231,43 @@ public: * \param that Comparand * \return \c true if this string is less than the comparand, \c false otherwise */ - bool operator< (string_type const& that) const + bool operator< (string_type const& that) const BOOST_NOEXCEPT { return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) < 0); } /*! + * Lexicographical comparison (less or equal ordering) + * + * \param that Comparand + * \return \c true if this string is less or equal to the comparand, \c false otherwise + */ + bool operator<= (this_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) <= 0); + } + /*! + * Lexicographical comparison (less or equal ordering) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if this string is less or equal to the comparand, \c false otherwise + */ + bool operator<= (const_pointer str) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) <= 0); + } + /*! + * Lexicographical comparison (less or equal ordering) + * + * \param that Comparand + * \return \c true if this string is less or equal to the comparand, \c false otherwise + */ + bool operator<= (string_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) <= 0); + } + + /*! * Lexicographical comparison (greater ordering) * * \param that Comparand @@ -237,19 +293,50 @@ public: * \param that Comparand * \return \c true if this string is greater than the comparand, \c false otherwise */ - bool operator> (string_type const& that) const + bool operator> (string_type const& that) const BOOST_NOEXCEPT { return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) > 0); } /*! + * Lexicographical comparison (greater or equal ordering) + * + * \param that Comparand + * \return \c true if this string is greater or equal to the comparand, \c false otherwise + */ + bool operator>= (this_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) >= 0); + } + /*! + * Lexicographical comparison (greater or qual ordering) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if this string is greater or equal to the comparand, \c false otherwise + */ + bool operator>= (const_pointer str) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) >= 0); + } + /*! + * Lexicographical comparison (greater or equal ordering) + * + * \param that Comparand + * \return \c true if this string is greater or equal to the comparand, \c false otherwise + */ + bool operator>= (string_type const& that) const BOOST_NOEXCEPT + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) >= 0); + } + + /*! * Subscript operator * * \pre <tt>i < size()</tt> * \param i Requested character index * \return Constant reference to the requested character */ - const_reference operator[] (size_type i) const BOOST_NOEXCEPT + BOOST_CONSTEXPR const_reference operator[] (size_type i) const BOOST_NOEXCEPT { return m_pStart[i]; } @@ -263,7 +350,7 @@ public: */ const_reference at(size_type i) const { - if (i >= m_Len) + if (BOOST_UNLIKELY(i >= m_Len)) BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::at: the index value is out of range")); return m_pStart[i]; } @@ -271,24 +358,24 @@ public: /*! * \return Pointer to the beginning of the literal */ - const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; } + BOOST_CONSTEXPR const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; } /*! * \return Pointer to the beginning of the literal */ - const_pointer data() const BOOST_NOEXCEPT { return m_pStart; } + BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT { return m_pStart; } /*! * \return Length of the literal */ - size_type size() const BOOST_NOEXCEPT { return m_Len; } + BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT { return m_Len; } /*! * \return Length of the literal */ - size_type length() const BOOST_NOEXCEPT { return m_Len; } + BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT { return m_Len; } /*! * \return \c true if the literal is an empty string, \c false otherwise */ - bool empty() const BOOST_NOEXCEPT + BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return (m_Len == 0); } @@ -296,11 +383,11 @@ public: /*! * \return Iterator that points to the first character of the literal */ - const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; } + BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; } /*! * \return Iterator that points after the last character of the literal */ - const_iterator end() const BOOST_NOEXCEPT { return m_pStart + m_Len; } + BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT { return m_pStart + m_Len; } /*! * \return Reverse iterator that points to the last character of the literal */ @@ -323,7 +410,7 @@ public: * * \post <tt>empty() == true</tt> */ - void clear() BOOST_NOEXCEPT + BOOST_CXX14_CONSTEXPR void clear() BOOST_NOEXCEPT { m_pStart = g_EmptyString; m_Len = 0; @@ -331,7 +418,7 @@ public: /*! * The method swaps two literals */ - void swap(this_type& that) BOOST_NOEXCEPT + BOOST_CXX14_CONSTEXPR void swap(this_type& that) BOOST_NOEXCEPT { const_pointer p = m_pStart; m_pStart = that.m_pStart; @@ -348,7 +435,7 @@ public: * \post <tt>*this == that</tt> * \param that Source literal to copy string from */ - this_type& assign(this_type const& that) BOOST_NOEXCEPT + BOOST_CXX14_CONSTEXPR this_type& assign(this_type const& that) BOOST_NOEXCEPT { m_pStart = that.m_pStart; m_Len = that.m_Len; @@ -361,9 +448,10 @@ public: * \param p A zero-terminated constant sequence of characters */ template< typename T, size_type LenV > + BOOST_CXX14_CONSTEXPR #ifndef BOOST_LOG_DOXYGEN_PASS - typename enable_if< - is_same< T, const value_type >, + typename boost::enable_if_c< + is_same< T, const value_type >::value, this_type& >::type #else @@ -390,7 +478,7 @@ public: */ size_type copy(value_type* str, size_type n, size_type pos = 0) const { - if (pos > m_Len) + if (BOOST_UNLIKELY(pos > m_Len)) BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::copy: the position is out of range")); size_type len = m_Len - pos; @@ -415,7 +503,7 @@ public: */ int compare(size_type pos, size_type n, const_pointer str, size_type len) const { - if (pos > m_Len) + if (BOOST_UNLIKELY(pos > m_Len)) BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::compare: the position is out of range")); size_type compare_size = m_Len - pos; @@ -508,9 +596,15 @@ private: #endif // BOOST_LOG_DOXYGEN_PASS }; +#if !defined(BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS) template< typename CharT, typename TraitsT > -typename basic_string_literal< CharT, TraitsT >::value_type const +constexpr typename basic_string_literal< CharT, TraitsT >::value_type +basic_string_literal< CharT, TraitsT >::g_EmptyString[1]; +#else +template< typename CharT, typename TraitsT > +const typename basic_string_literal< CharT, TraitsT >::value_type basic_string_literal< CharT, TraitsT >::g_EmptyString[1] = { 0 }; +#endif namespace aux { @@ -569,7 +663,7 @@ inline std::basic_ostream< CharT, StrmTraitsT >& operator<< ( //! External swap template< typename CharT, typename TraitsT > -inline void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_literal< CharT, TraitsT >& right) BOOST_NOEXCEPT +inline BOOST_CXX14_CONSTEXPR void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_literal< CharT, TraitsT >& right) BOOST_NOEXCEPT { left.swap(right); } @@ -577,16 +671,16 @@ inline void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_lite //! Creates a string literal wrapper from a constant string literal #ifdef BOOST_LOG_USE_CHAR template< typename T, std::size_t LenV > -inline +inline BOOST_CONSTEXPR #ifndef BOOST_LOG_DOXYGEN_PASS -typename enable_if< - is_same< T, const char >, +typename boost::enable_if_c< + is_same< T, const char >::value, string_literal >::type #else basic_string_literal< T > #endif // BOOST_LOG_DOXYGEN_PASS -str_literal(T(&p)[LenV]) +str_literal(T(&p)[LenV]) BOOST_NOEXCEPT { return string_literal(p); } @@ -596,11 +690,11 @@ str_literal(T(&p)[LenV]) #ifdef BOOST_LOG_USE_WCHAR_T template< typename T, std::size_t LenV > -inline typename enable_if< - is_same< T, const wchar_t >, +inline BOOST_CONSTEXPR typename boost::enable_if_c< + is_same< T, const wchar_t >::value, wstring_literal >::type -str_literal(T(&p)[LenV]) +str_literal(T(&p)[LenV]) BOOST_NOEXCEPT { return wstring_literal(p); } diff --git a/boost/log/utility/type_dispatch/static_type_dispatcher.hpp b/boost/log/utility/type_dispatch/static_type_dispatcher.hpp index c580213d66..dcf2cd033d 100644 --- a/boost/log/utility/type_dispatch/static_type_dispatcher.hpp +++ b/boost/log/utility/type_dispatch/static_type_dispatcher.hpp @@ -29,7 +29,7 @@ #include <boost/mpl/deref.hpp> #include <boost/mpl/next.hpp> #include <boost/mpl/is_sequence.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/core/addressof.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/utility/once_block.hpp> #include <boost/log/utility/type_dispatch/type_dispatcher.hpp> diff --git a/boost/log/utility/value_ref.hpp b/boost/log/utility/value_ref.hpp index 438f5db68b..1f9a360785 100644 --- a/boost/log/utility/value_ref.hpp +++ b/boost/log/utility/value_ref.hpp @@ -29,15 +29,14 @@ #include <boost/mpl/equal_to.hpp> #include <boost/mpl/contains.hpp> #include <boost/mpl/index_of.hpp> -#include <boost/utility/addressof.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/core/explicit_operator_bool.hpp> +#include <boost/core/addressof.hpp> #include <boost/optional/optional_fwd.hpp> -#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_void.hpp> #include <boost/log/detail/config.hpp> #include <boost/log/detail/parameter_tools.hpp> #include <boost/log/detail/value_ref_visitation.hpp> -#include <boost/utility/explicit_operator_bool.hpp> +#include <boost/log/detail/sfinae_tools.hpp> #include <boost/log/utility/formatting_ostream_fwd.hpp> #include <boost/log/utility/functional/logical.hpp> #include <boost/log/utility/functional/bind.hpp> @@ -78,6 +77,21 @@ private: result_type m_def_val; }; +//! Traits for testing type compatibility with the reference wrapper +struct singular_ref_compatibility_traits +{ + template< typename T, typename U > + struct is_compatible + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template< typename T > + struct is_compatible< T, T > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +}; + //! Attribute value reference implementation for a single type case template< typename T, typename TagT > class singular_ref @@ -89,17 +103,8 @@ public: typedef TagT tag_type; protected: - //! The metafunction tests if the type is compatible with the reference wrapper -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template< typename U > - using is_compatible = is_same< U, value_type >; -#else - template< typename U > - struct is_compatible : - public is_same< U, value_type > - { - }; -#endif + //! Traits for testing type compatibility with the reference wrapper + typedef singular_ref_compatibility_traits compatibility_traits; protected: //! Pointer to the value @@ -132,7 +137,7 @@ public: //! Returns a pointer to the referred value template< typename U > - typename enable_if< is_compatible< U >, const U* >::type get_ptr() const BOOST_NOEXCEPT + typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, const U* >::type get_ptr() const BOOST_NOEXCEPT { return m_ptr; } @@ -153,7 +158,7 @@ public: //! Returns a reference to the value template< typename U > - typename enable_if< is_compatible< U >, U const& >::type get() const BOOST_NOEXCEPT + typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, U const& >::type get() const BOOST_NOEXCEPT { BOOST_ASSERT(m_ptr != NULL); return *m_ptr; @@ -190,7 +195,7 @@ public: //! Applies a visitor function object to the referred value template< typename VisitorT > - typename enable_if< is_void< typename VisitorT::result_type >, bool >::type apply_visitor_optional(VisitorT visitor) const + typename boost::enable_if_c< is_void< typename VisitorT::result_type >::value, bool >::type apply_visitor_optional(VisitorT visitor) const { if (m_ptr) { @@ -203,7 +208,7 @@ public: //! Applies a visitor function object to the referred value template< typename VisitorT > - typename disable_if< is_void< typename VisitorT::result_type >, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const + typename boost::disable_if_c< is_void< typename VisitorT::result_type >::value, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const { typedef optional< typename VisitorT::result_type > result_type; if (m_ptr) @@ -233,6 +238,16 @@ public: } }; +//! Traits for testing type compatibility with the reference wrapper +struct variant_ref_compatibility_traits +{ + template< typename T, typename U > + struct is_compatible + { + BOOST_STATIC_CONSTANT(bool, value = (mpl::contains< T, U >::type::value)); + }; +}; + //! Attribute value reference implementation for multiple types case template< typename T, typename TagT > class variant_ref @@ -244,17 +259,8 @@ public: typedef TagT tag_type; protected: - //! The metafunction tests if the type is compatible with the reference wrapper -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template< typename U > - using is_compatible = mpl::contains< value_type, U >; -#else - template< typename U > - struct is_compatible : - public mpl::contains< value_type, U > - { - }; -#endif + //! Traits for testing type compatibility with the reference wrapper + typedef variant_ref_compatibility_traits compatibility_traits; protected: //! Pointer to the value @@ -284,7 +290,7 @@ public: //! Returns a pointer to the referred value template< typename U > - typename enable_if< is_compatible< U >, const U* >::type get_ptr() const BOOST_NOEXCEPT + typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, const U* >::type get_ptr() const BOOST_NOEXCEPT { if (m_type_idx == static_cast< unsigned int >(mpl::index_of< value_type, U >::type::value)) return static_cast< const U* >(m_ptr); @@ -294,7 +300,7 @@ public: //! Returns a reference to the value template< typename U > - typename enable_if< is_compatible< U >, U const& >::type get() const BOOST_NOEXCEPT + typename boost::enable_if_c< compatibility_traits::is_compatible< value_type, U >::value, U const& >::type get() const BOOST_NOEXCEPT { const U* const p = get_ptr< U >(); BOOST_ASSERT(p != NULL); @@ -328,7 +334,7 @@ public: //! Applies a visitor function object to the referred value template< typename VisitorT > - typename enable_if< is_void< typename VisitorT::result_type >, bool >::type apply_visitor_optional(VisitorT visitor) const + typename boost::enable_if_c< is_void< typename VisitorT::result_type >::value, bool >::type apply_visitor_optional(VisitorT visitor) const { if (m_ptr) { @@ -341,7 +347,7 @@ public: //! Applies a visitor function object to the referred value template< typename VisitorT > - typename disable_if< is_void< typename VisitorT::result_type >, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const + typename boost::disable_if_c< is_void< typename VisitorT::result_type >::value, optional< typename VisitorT::result_type > >::type apply_visitor_optional(VisitorT visitor) const { typedef optional< typename VisitorT::result_type > result_type; if (m_ptr) @@ -423,6 +429,19 @@ public: private: //! Base implementation type typedef typename aux::value_ref_base< T, TagT >::type base_type; + //! Traits for testing type compatibility with the reference wrapper + typedef typename base_type::compatibility_traits compatibility_traits; + +public: +#ifndef BOOST_LOG_DOXYGEN_PASS + //! Referenced value type + typedef typename base_type::value_type value_type; +#else + //! Referenced value type + typedef T value_type; + //! Tag type + typedef TagT tag_type; +#endif public: /*! @@ -439,7 +458,14 @@ public: * Initializing constructor. Creates a reference wrapper that refers to the specified value. */ template< typename U > - explicit value_ref(U const& val, typename enable_if< typename base_type::BOOST_NESTED_TEMPLATE is_compatible< U >, int >::type = 0) BOOST_NOEXCEPT : + explicit value_ref(U const& val +#ifndef BOOST_LOG_DOXYGEN_PASS +// MSVC-8 can't handle SFINAE in this case properly and often wrongly disables this constructor +#if !defined(_MSC_VER) || (_MSC_VER + 0) >= 1500 + , typename boost::enable_if_c< compatibility_traits::BOOST_NESTED_TEMPLATE is_compatible< value_type, U >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy() +#endif +#endif + ) BOOST_NOEXCEPT : base_type(boost::addressof(val)) { } |