Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file string_literal.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 24.06.2007 Chris@16: * Chris@16: * The header contains implementation of a constant string literal wrapper. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include // std::streamsize Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: /*! Chris@16: * \brief String literal wrapper Chris@16: * Chris@16: * The \c basic_string_literal is a thin wrapper around a constant string literal. Chris@16: * It provides interface similar to STL strings, but because of read-only nature Chris@16: * of string literals, lacks ability to modify string contents. However, Chris@16: * \c basic_string_literal objects can be assigned to and cleared. Chris@16: * Chris@16: * The main advantage of this class comparing to other string classes is that Chris@16: * it doesn't dynamically allocate memory and therefore is fast, thin and exception safe. Chris@16: */ Chris@16: template< typename CharT, typename TraitsT > Chris@16: class basic_string_literal Chris@16: //! \cond Chris@16: : public totally_ordered1< basic_string_literal< CharT, TraitsT >, Chris@16: totally_ordered2< basic_string_literal< CharT, TraitsT >, const CharT*, Chris@16: totally_ordered2< Chris@16: basic_string_literal< CharT, TraitsT >, Chris@16: std::basic_string< CharT, TraitsT > Chris@16: > Chris@16: > Chris@16: > Chris@16: //! \endcond Chris@16: { Chris@16: //! Self type Chris@16: typedef basic_string_literal< CharT, TraitsT > this_type; Chris@16: Chris@16: public: Chris@16: typedef CharT value_type; Chris@16: typedef TraitsT traits_type; Chris@16: Chris@16: typedef std::size_t size_type; Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: typedef const value_type* const_pointer; Chris@16: typedef value_type const& const_reference; Chris@16: typedef const value_type* const_iterator; Chris@16: typedef std::reverse_iterator< const_iterator > const_reverse_iterator; Chris@16: Chris@16: //! Corresponding STL string type Chris@16: typedef std::basic_string< value_type, traits_type > string_type; Chris@16: Chris@16: private: Chris@16: //! Pointer to the beginning of the literal Chris@16: const_pointer m_pStart; Chris@16: //! Length Chris@16: size_type m_Len; Chris@16: Chris@16: //! Empty string literal to support clear Chris@16: static const value_type g_EmptyString[1]; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Constructor Chris@16: * Chris@16: * \post empty() == true Chris@16: */ Chris@16: basic_string_literal() BOOST_NOEXCEPT { clear(); } Chris@16: Chris@16: /*! Chris@16: * Constructor from a string literal Chris@16: * Chris@16: * \post *this == p Chris@16: * \param p A zero-terminated constant sequence of characters Chris@16: */ Chris@16: template< typename T, size_type LenV > Chris@16: basic_string_literal(T(&p)[LenV] Chris@16: //! \cond Chris@16: , typename enable_if< is_same< T, const value_type >, int >::type = 0 Chris@16: //! \endcond Chris@16: ) BOOST_NOEXCEPT Chris@16: : m_pStart(p), m_Len(LenV - 1) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Copy constructor Chris@16: * Chris@16: * \post *this == that Chris@16: * \param that Source literal to copy string from Chris@16: */ Chris@16: basic_string_literal(basic_string_literal const& that) BOOST_NOEXCEPT : m_pStart(that.m_pStart), m_Len(that.m_Len) {} Chris@16: Chris@16: /*! Chris@16: * Assignment operator Chris@16: * Chris@16: * \post *this == that Chris@16: * \param that Source literal to copy string from Chris@16: */ Chris@16: this_type& operator= (this_type const& that) BOOST_NOEXCEPT Chris@16: { Chris@16: return assign(that); Chris@16: } Chris@16: /*! Chris@16: * Assignment from a string literal Chris@16: * Chris@16: * \post *this == p Chris@16: * \param p A zero-terminated constant sequence of characters Chris@16: */ Chris@16: template< typename T, size_type LenV > Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: typename enable_if< Chris@16: is_same< T, const value_type >, Chris@16: this_type& Chris@16: >::type Chris@16: #else Chris@16: this_type& Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: operator= (T(&p)[LenV]) BOOST_NOEXCEPT Chris@16: { Chris@16: return assign(p); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Lexicographical comparison (equality) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if the comparand string equals to this string, \c false otherwise Chris@16: */ Chris@16: bool operator== (this_type const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) == 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (equality) Chris@16: * Chris@16: * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. Chris@16: * \return \c true if the comparand string equals to this string, \c false otherwise Chris@16: */ Chris@16: bool operator== (const_pointer str) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) == 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (equality) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if the comparand string equals to this string, \c false otherwise Chris@16: */ Chris@16: bool operator== (string_type const& that) const Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) == 0); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Lexicographical comparison (less ordering) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if this string is less than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator< (this_type const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) < 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (less ordering) Chris@16: * Chris@16: * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. Chris@16: * \return \c true if this string is less than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator< (const_pointer str) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) < 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (less ordering) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if this string is less than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator< (string_type const& that) const Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) < 0); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Lexicographical comparison (greater ordering) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if this string is greater than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator> (this_type const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) > 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (greater ordering) Chris@16: * Chris@16: * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. Chris@16: * \return \c true if this string is greater than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator> (const_pointer str) const BOOST_NOEXCEPT Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) > 0); Chris@16: } Chris@16: /*! Chris@16: * Lexicographical comparison (greater ordering) Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return \c true if this string is greater than the comparand, \c false otherwise Chris@16: */ Chris@16: bool operator> (string_type const& that) const Chris@16: { Chris@16: return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) > 0); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Subscript operator Chris@16: * Chris@16: * \pre i < size() Chris@16: * \param i Requested character index Chris@16: * \return Constant reference to the requested character Chris@16: */ Chris@16: const_reference operator[] (size_type i) const BOOST_NOEXCEPT Chris@16: { Chris@16: return m_pStart[i]; Chris@16: } Chris@16: /*! Chris@16: * Checked subscript Chris@16: * Chris@16: * \param i Requested character index Chris@16: * \return Constant reference to the requested character Chris@16: * Chris@16: * \b Throws: An std::exception-based exception if index \a i is out of string boundaries Chris@16: */ Chris@16: const_reference at(size_type i) const Chris@16: { Chris@16: if (i >= m_Len) Chris@16: BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::at: the index value is out of range")); Chris@16: return m_pStart[i]; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * \return Pointer to the beginning of the literal Chris@16: */ Chris@16: const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; } Chris@16: /*! Chris@16: * \return Pointer to the beginning of the literal Chris@16: */ Chris@16: const_pointer data() const BOOST_NOEXCEPT { return m_pStart; } Chris@16: /*! Chris@16: * \return Length of the literal Chris@16: */ Chris@16: size_type size() const BOOST_NOEXCEPT { return m_Len; } Chris@16: /*! Chris@16: * \return Length of the literal Chris@16: */ Chris@16: size_type length() const BOOST_NOEXCEPT { return m_Len; } Chris@16: Chris@16: /*! Chris@16: * \return \c true if the literal is an empty string, \c false otherwise Chris@16: */ Chris@16: bool empty() const BOOST_NOEXCEPT Chris@16: { Chris@16: return (m_Len == 0); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * \return Iterator that points to the first character of the literal Chris@16: */ Chris@16: const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; } Chris@16: /*! Chris@16: * \return Iterator that points after the last character of the literal Chris@16: */ Chris@16: const_iterator end() const BOOST_NOEXCEPT { return m_pStart + m_Len; } Chris@16: /*! Chris@16: * \return Reverse iterator that points to the last character of the literal Chris@16: */ Chris@16: const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } Chris@16: /*! Chris@16: * \return Reverse iterator that points before the first character of the literal Chris@16: */ Chris@16: const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } Chris@16: Chris@16: /*! Chris@16: * \return STL string constructed from the literal Chris@16: */ Chris@16: string_type str() const Chris@16: { Chris@16: return string_type(m_pStart, m_Len); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method clears the literal Chris@16: * Chris@16: * \post empty() == true Chris@16: */ Chris@16: void clear() BOOST_NOEXCEPT Chris@16: { Chris@16: m_pStart = g_EmptyString; Chris@16: m_Len = 0; Chris@16: } Chris@16: /*! Chris@16: * The method swaps two literals Chris@16: */ Chris@16: void swap(this_type& that) BOOST_NOEXCEPT Chris@16: { Chris@101: const_pointer p = m_pStart; Chris@16: m_pStart = that.m_pStart; Chris@16: that.m_pStart = p; Chris@16: Chris@101: size_type l = m_Len; Chris@16: m_Len = that.m_Len; Chris@16: that.m_Len = l; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Assignment from another literal Chris@16: * Chris@16: * \post *this == that Chris@16: * \param that Source literal to copy string from Chris@16: */ Chris@16: this_type& assign(this_type const& that) BOOST_NOEXCEPT Chris@16: { Chris@16: m_pStart = that.m_pStart; Chris@16: m_Len = that.m_Len; Chris@16: return *this; Chris@16: } Chris@16: /*! Chris@16: * Assignment from another literal Chris@16: * Chris@16: * \post *this == p Chris@16: * \param p A zero-terminated constant sequence of characters Chris@16: */ Chris@16: template< typename T, size_type LenV > Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: typename enable_if< Chris@16: is_same< T, const value_type >, Chris@16: this_type& Chris@16: >::type Chris@16: #else Chris@16: this_type& Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: assign(T(&p)[LenV]) BOOST_NOEXCEPT Chris@16: { Chris@16: m_pStart = p; Chris@16: m_Len = LenV - 1; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method copies the literal or its portion to an external buffer Chris@16: * Chris@16: * \pre pos <= size() Chris@16: * \param str Pointer to the external buffer beginning. Must not be NULL. Chris@16: * The buffer must have enough capacity to accommodate the requested number of characters. Chris@16: * \param n Maximum number of characters to copy Chris@16: * \param pos Starting position to start copying from Chris@16: * \return Number of characters copied Chris@16: * Chris@16: * \b Throws: An std::exception-based exception if \a pos is out of range. Chris@16: */ Chris@16: size_type copy(value_type* str, size_type n, size_type pos = 0) const Chris@16: { Chris@16: if (pos > m_Len) Chris@16: BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::copy: the position is out of range")); Chris@16: Chris@101: size_type len = m_Len - pos; Chris@16: if (len > n) Chris@16: len = n; Chris@16: traits_type::copy(str, m_pStart + pos, len); Chris@16: return len; Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Lexicographically compares the argument string to a part of this string Chris@16: * Chris@16: * \pre pos <= size() Chris@16: * \param pos Starting position within this string to perform comparison to Chris@16: * \param n Length of the substring of this string to perform comparison to Chris@16: * \param str Comparand. Must point to a sequence of characters, must not be NULL. Chris@16: * \param len Number of characters in the sequence \a str. Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: * Chris@16: * \b Throws: An std::exception-based exception if \a pos is out of range. Chris@16: */ Chris@16: int compare(size_type pos, size_type n, const_pointer str, size_type len) const Chris@16: { Chris@16: if (pos > m_Len) Chris@16: BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::compare: the position is out of range")); Chris@16: Chris@101: size_type compare_size = m_Len - pos; Chris@16: if (compare_size > len) Chris@16: compare_size = len; Chris@16: if (compare_size > n) Chris@16: compare_size = n; Chris@16: return compare_internal(m_pStart + pos, compare_size, str, compare_size); Chris@16: } Chris@16: /*! Chris@16: * Lexicographically compares the argument string to a part of this string Chris@16: * Chris@16: * \pre pos <= size() Chris@16: * \param pos Starting position within this string to perform comparison to Chris@16: * \param n Length of the substring of this string to perform comparison to Chris@16: * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: * Chris@16: * \b Throws: An std::exception-based exception if \a pos is out of range. Chris@16: */ Chris@16: int compare(size_type pos, size_type n, const_pointer str) const BOOST_NOEXCEPT Chris@16: { Chris@16: return compare(pos, n, str, traits_type::length(str)); Chris@16: } Chris@16: /*! Chris@16: * Lexicographically compares the argument string literal to a part of this string Chris@16: * Chris@16: * \pre pos <= size() Chris@16: * \param pos Starting position within this string to perform comparison to Chris@16: * \param n Length of the substring of this string to perform comparison to Chris@16: * \param that Comparand Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: * Chris@16: * \b Throws: An std::exception-based exception if \a pos is out of range. Chris@16: */ Chris@16: int compare(size_type pos, size_type n, this_type const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return compare(pos, n, that.c_str(), that.size()); Chris@16: } Chris@16: /*! Chris@16: * Lexicographically compares the argument string to this string Chris@16: * Chris@16: * \param str Comparand. Must point to a sequence of characters, must not be NULL. Chris@16: * \param len Number of characters in the sequence \a str. Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: */ Chris@16: int compare(const_pointer str, size_type len) const BOOST_NOEXCEPT Chris@16: { Chris@16: return compare(0, m_Len, str, len); Chris@16: } Chris@16: /*! Chris@16: * Lexicographically compares the argument string to this string Chris@16: * Chris@16: * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: */ Chris@16: int compare(const_pointer str) const BOOST_NOEXCEPT Chris@16: { Chris@16: return compare(0, m_Len, str, traits_type::length(str)); Chris@16: } Chris@16: /*! Chris@16: * Lexicographically compares the argument string to this string Chris@16: * Chris@16: * \param that Comparand Chris@16: * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, Chris@16: * a positive value if this string is greater than the comparand. Chris@16: */ Chris@16: int compare(this_type const& that) const BOOST_NOEXCEPT Chris@16: { Chris@16: return compare(0, m_Len, that.c_str(), that.size()); Chris@16: } Chris@16: Chris@16: private: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: //! Internal comparison implementation Chris@16: static int compare_internal(const_pointer pLeft, size_type LeftLen, const_pointer pRight, size_type RightLen) BOOST_NOEXCEPT Chris@16: { Chris@16: if (pLeft != pRight) Chris@16: { Chris@101: const int result = traits_type::compare(pLeft, pRight, (LeftLen < RightLen ? LeftLen : RightLen)); Chris@16: if (result != 0) Chris@16: return result; Chris@16: } Chris@16: return LeftLen < RightLen ? -1 : (LeftLen > RightLen ? 1 : 0); Chris@16: } Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: }; Chris@16: Chris@16: template< typename CharT, typename TraitsT > Chris@16: typename basic_string_literal< CharT, TraitsT >::value_type const Chris@16: basic_string_literal< CharT, TraitsT >::g_EmptyString[1] = { 0 }; Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: template< typename CharT, typename TraitsT > Chris@16: inline void insert_fill_chars(std::basic_ostream< CharT, TraitsT >& strm, std::size_t n) Chris@16: { Chris@16: enum { chunk_size = 8 }; Chris@16: CharT fill_chars[chunk_size]; Chris@16: const CharT filler = strm.fill(); Chris@16: for (unsigned int i = 0; i < chunk_size; ++i) Chris@16: fill_chars[i] = filler; Chris@16: for (; n >= chunk_size && strm.good(); n -= chunk_size) Chris@16: strm.write(fill_chars, static_cast< std::size_t >(chunk_size)); Chris@16: if (n > 0 && strm.good()) Chris@16: strm.write(fill_chars, n); Chris@16: } Chris@16: Chris@16: template< typename CharT, typename TraitsT > Chris@16: void insert_aligned(std::basic_ostream< CharT, TraitsT >& strm, const CharT* p, std::size_t size) Chris@16: { Chris@16: const std::size_t alignment_size = static_cast< std::size_t >(strm.width()) - size; Chris@16: const bool align_left = (strm.flags() & std::basic_ostream< CharT, TraitsT >::adjustfield) == std::basic_ostream< CharT, TraitsT >::left; Chris@16: if (align_left) Chris@16: { Chris@16: strm.write(p, size); Chris@16: if (strm.good()) Chris@16: aux::insert_fill_chars(strm, alignment_size); Chris@16: } Chris@16: else Chris@16: { Chris@16: aux::insert_fill_chars(strm, alignment_size); Chris@16: if (strm.good()) Chris@16: strm.write(p, size); Chris@16: } Chris@16: } Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: //! Output operator Chris@16: template< typename CharT, typename StrmTraitsT, typename LitTraitsT > Chris@16: inline std::basic_ostream< CharT, StrmTraitsT >& operator<< ( Chris@16: std::basic_ostream< CharT, StrmTraitsT >& strm, basic_string_literal< CharT, LitTraitsT > const& lit) Chris@16: { Chris@16: if (strm.good()) Chris@16: { Chris@16: const std::size_t size = lit.size(); Chris@16: const std::size_t w = static_cast< std::size_t >(strm.width()); Chris@16: if (w <= size) Chris@16: strm.write(lit.c_str(), static_cast< std::streamsize >(size)); Chris@16: else Chris@16: aux::insert_aligned(strm, lit.c_str(), lit.size()); Chris@16: strm.width(0); Chris@16: } Chris@16: return strm; Chris@16: } Chris@16: Chris@16: //! External swap Chris@16: template< typename CharT, typename TraitsT > Chris@16: inline void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_literal< CharT, TraitsT >& right) BOOST_NOEXCEPT Chris@16: { Chris@16: left.swap(right); Chris@16: } Chris@16: Chris@16: //! Creates a string literal wrapper from a constant string literal Chris@16: #ifdef BOOST_LOG_USE_CHAR Chris@16: template< typename T, std::size_t LenV > Chris@16: inline Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: typename enable_if< Chris@16: is_same< T, const char >, Chris@16: string_literal Chris@16: >::type Chris@16: #else Chris@16: basic_string_literal< T > Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: str_literal(T(&p)[LenV]) Chris@16: { Chris@16: return string_literal(p); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: #ifdef BOOST_LOG_USE_WCHAR_T Chris@16: template< typename T, std::size_t LenV > Chris@16: inline typename enable_if< Chris@16: is_same< T, const wchar_t >, Chris@16: wstring_literal Chris@16: >::type Chris@16: str_literal(T(&p)[LenV]) Chris@16: { Chris@16: return wstring_literal(p); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_