2 * Copyright Andrey Semashev 2007 - 2016.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
8 * \file string_literal.hpp
9 * \author Andrey Semashev
12 * The header contains implementation of a constant string literal wrapper.
15 #ifndef BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_
21 #include <ios> // std::streamsize
24 #include <boost/throw_exception.hpp>
25 #include <boost/type_traits/is_same.hpp>
26 #include <boost/log/detail/config.hpp>
27 #include <boost/log/utility/string_literal_fwd.hpp>
28 #include <boost/log/detail/sfinae_tools.hpp>
29 #include <boost/log/detail/header.hpp>
31 #ifdef BOOST_HAS_PRAGMA_ONCE
37 BOOST_LOG_OPEN_NAMESPACE
40 * \brief String literal wrapper
42 * The \c basic_string_literal is a thin wrapper around a constant string literal.
43 * It provides interface similar to STL strings, but because of read-only nature
44 * of string literals, lacks ability to modify string contents. However,
45 * \c basic_string_literal objects can be assigned to and cleared.
47 * The main advantage of this class comparing to other string classes is that
48 * it doesn't dynamically allocate memory and therefore is fast, thin and exception safe.
50 template< typename CharT, typename TraitsT >
51 class basic_string_literal
54 typedef basic_string_literal< CharT, TraitsT > this_type;
57 typedef CharT value_type;
58 typedef TraitsT traits_type;
60 typedef std::size_t size_type;
61 typedef std::ptrdiff_t difference_type;
62 typedef const value_type* const_pointer;
63 typedef value_type const& const_reference;
64 typedef const value_type* const_iterator;
65 typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
67 //! Corresponding STL string type
68 typedef std::basic_string< value_type, traits_type > string_type;
71 //! Pointer to the beginning of the literal
72 const_pointer m_pStart;
76 //! Empty string literal to support \c clear
77 #if !defined(BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS)
78 static constexpr value_type g_EmptyString[1] = { 0 };
80 static const value_type g_EmptyString[1];
87 * \post <tt>empty() == true</tt>
89 BOOST_CONSTEXPR basic_string_literal() BOOST_NOEXCEPT : m_pStart(g_EmptyString), m_Len(0) { }
92 * Constructor from a string literal
94 * \post <tt>*this == p</tt>
95 * \param p A zero-terminated constant sequence of characters
97 template< typename T, size_type LenV >
98 BOOST_CONSTEXPR basic_string_literal(T(&p)[LenV]
100 , typename boost::enable_if_c< is_same< T, const value_type >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()
103 : m_pStart(p), m_Len(LenV - 1)
110 * \post <tt>*this == that</tt>
111 * \param that Source literal to copy string from
113 BOOST_CONSTEXPR basic_string_literal(basic_string_literal const& that) BOOST_NOEXCEPT : m_pStart(that.m_pStart), m_Len(that.m_Len) {}
116 * Assignment operator
118 * \post <tt>*this == that</tt>
119 * \param that Source literal to copy string from
121 BOOST_CXX14_CONSTEXPR this_type& operator= (this_type const& that) BOOST_NOEXCEPT
126 * Assignment from a string literal
128 * \post <tt>*this == p</tt>
129 * \param p A zero-terminated constant sequence of characters
131 template< typename T, size_type LenV >
132 BOOST_CXX14_CONSTEXPR
133 #ifndef BOOST_LOG_DOXYGEN_PASS
134 typename boost::enable_if_c<
135 is_same< T, const value_type >::value,
140 #endif // BOOST_LOG_DOXYGEN_PASS
141 operator= (T(&p)[LenV]) BOOST_NOEXCEPT
147 * Lexicographical comparison (equality)
149 * \param that Comparand
150 * \return \c true if the comparand string equals to this string, \c false otherwise
152 bool operator== (this_type const& that) const BOOST_NOEXCEPT
154 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) == 0);
157 * Lexicographical comparison (equality)
159 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
160 * \return \c true if the comparand string equals to this string, \c false otherwise
162 bool operator== (const_pointer str) const BOOST_NOEXCEPT
164 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) == 0);
167 * Lexicographical comparison (equality)
169 * \param that Comparand
170 * \return \c true if the comparand string equals to this string, \c false otherwise
172 bool operator== (string_type const& that) const BOOST_NOEXCEPT
174 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) == 0);
178 * Lexicographical comparison (inequality)
180 * \param that Comparand
181 * \return \c true if the comparand string is not equal to this string, \c false otherwise
183 bool operator!= (this_type const& that) const BOOST_NOEXCEPT
185 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) != 0);
188 * Lexicographical comparison (inequality)
190 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
191 * \return \c true if the comparand string is not equal to this string, \c false otherwise
193 bool operator!= (const_pointer str) const BOOST_NOEXCEPT
195 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) != 0);
198 * Lexicographical comparison (inequality)
200 * \param that Comparand
201 * \return \c true if the comparand string is not equal to this string, \c false otherwise
203 bool operator!= (string_type const& that) const BOOST_NOEXCEPT
205 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) != 0);
209 * Lexicographical comparison (less ordering)
211 * \param that Comparand
212 * \return \c true if this string is less than the comparand, \c false otherwise
214 bool operator< (this_type const& that) const BOOST_NOEXCEPT
216 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) < 0);
219 * Lexicographical comparison (less ordering)
221 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
222 * \return \c true if this string is less than the comparand, \c false otherwise
224 bool operator< (const_pointer str) const BOOST_NOEXCEPT
226 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) < 0);
229 * Lexicographical comparison (less ordering)
231 * \param that Comparand
232 * \return \c true if this string is less than the comparand, \c false otherwise
234 bool operator< (string_type const& that) const BOOST_NOEXCEPT
236 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) < 0);
240 * Lexicographical comparison (less or equal ordering)
242 * \param that Comparand
243 * \return \c true if this string is less or equal to the comparand, \c false otherwise
245 bool operator<= (this_type const& that) const BOOST_NOEXCEPT
247 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) <= 0);
250 * Lexicographical comparison (less or equal ordering)
252 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
253 * \return \c true if this string is less or equal to the comparand, \c false otherwise
255 bool operator<= (const_pointer str) const BOOST_NOEXCEPT
257 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) <= 0);
260 * Lexicographical comparison (less or equal ordering)
262 * \param that Comparand
263 * \return \c true if this string is less or equal to the comparand, \c false otherwise
265 bool operator<= (string_type const& that) const BOOST_NOEXCEPT
267 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) <= 0);
271 * Lexicographical comparison (greater ordering)
273 * \param that Comparand
274 * \return \c true if this string is greater than the comparand, \c false otherwise
276 bool operator> (this_type const& that) const BOOST_NOEXCEPT
278 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) > 0);
281 * Lexicographical comparison (greater ordering)
283 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
284 * \return \c true if this string is greater than the comparand, \c false otherwise
286 bool operator> (const_pointer str) const BOOST_NOEXCEPT
288 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) > 0);
291 * Lexicographical comparison (greater ordering)
293 * \param that Comparand
294 * \return \c true if this string is greater than the comparand, \c false otherwise
296 bool operator> (string_type const& that) const BOOST_NOEXCEPT
298 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) > 0);
302 * Lexicographical comparison (greater or equal ordering)
304 * \param that Comparand
305 * \return \c true if this string is greater or equal to the comparand, \c false otherwise
307 bool operator>= (this_type const& that) const BOOST_NOEXCEPT
309 return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) >= 0);
312 * Lexicographical comparison (greater or qual ordering)
314 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
315 * \return \c true if this string is greater or equal to the comparand, \c false otherwise
317 bool operator>= (const_pointer str) const BOOST_NOEXCEPT
319 return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) >= 0);
322 * Lexicographical comparison (greater or equal ordering)
324 * \param that Comparand
325 * \return \c true if this string is greater or equal to the comparand, \c false otherwise
327 bool operator>= (string_type const& that) const BOOST_NOEXCEPT
329 return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) >= 0);
335 * \pre <tt>i < size()</tt>
336 * \param i Requested character index
337 * \return Constant reference to the requested character
339 BOOST_CONSTEXPR const_reference operator[] (size_type i) const BOOST_NOEXCEPT
346 * \param i Requested character index
347 * \return Constant reference to the requested character
349 * \b Throws: An <tt>std::exception</tt>-based exception if index \a i is out of string boundaries
351 const_reference at(size_type i) const
353 if (BOOST_UNLIKELY(i >= m_Len))
354 BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::at: the index value is out of range"));
359 * \return Pointer to the beginning of the literal
361 BOOST_CONSTEXPR const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; }
363 * \return Pointer to the beginning of the literal
365 BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT { return m_pStart; }
367 * \return Length of the literal
369 BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT { return m_Len; }
371 * \return Length of the literal
373 BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT { return m_Len; }
376 * \return \c true if the literal is an empty string, \c false otherwise
378 BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
384 * \return Iterator that points to the first character of the literal
386 BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; }
388 * \return Iterator that points after the last character of the literal
390 BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT { return m_pStart + m_Len; }
392 * \return Reverse iterator that points to the last character of the literal
394 const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); }
396 * \return Reverse iterator that points before the first character of the literal
398 const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); }
401 * \return STL string constructed from the literal
403 string_type str() const
405 return string_type(m_pStart, m_Len);
409 * The method clears the literal
411 * \post <tt>empty() == true</tt>
413 BOOST_CXX14_CONSTEXPR void clear() BOOST_NOEXCEPT
415 m_pStart = g_EmptyString;
419 * The method swaps two literals
421 BOOST_CXX14_CONSTEXPR void swap(this_type& that) BOOST_NOEXCEPT
423 const_pointer p = m_pStart;
424 m_pStart = that.m_pStart;
433 * Assignment from another literal
435 * \post <tt>*this == that</tt>
436 * \param that Source literal to copy string from
438 BOOST_CXX14_CONSTEXPR this_type& assign(this_type const& that) BOOST_NOEXCEPT
440 m_pStart = that.m_pStart;
445 * Assignment from another literal
447 * \post <tt>*this == p</tt>
448 * \param p A zero-terminated constant sequence of characters
450 template< typename T, size_type LenV >
451 BOOST_CXX14_CONSTEXPR
452 #ifndef BOOST_LOG_DOXYGEN_PASS
453 typename boost::enable_if_c<
454 is_same< T, const value_type >::value,
459 #endif // BOOST_LOG_DOXYGEN_PASS
460 assign(T(&p)[LenV]) BOOST_NOEXCEPT
468 * The method copies the literal or its portion to an external buffer
470 * \pre <tt>pos <= size()</tt>
471 * \param str Pointer to the external buffer beginning. Must not be NULL.
472 * The buffer must have enough capacity to accommodate the requested number of characters.
473 * \param n Maximum number of characters to copy
474 * \param pos Starting position to start copying from
475 * \return Number of characters copied
477 * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
479 size_type copy(value_type* str, size_type n, size_type pos = 0) const
481 if (BOOST_UNLIKELY(pos > m_Len))
482 BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::copy: the position is out of range"));
484 size_type len = m_Len - pos;
487 traits_type::copy(str, m_pStart + pos, len);
492 * Lexicographically compares the argument string to a part of this string
494 * \pre <tt>pos <= size()</tt>
495 * \param pos Starting position within this string to perform comparison to
496 * \param n Length of the substring of this string to perform comparison to
497 * \param str Comparand. Must point to a sequence of characters, must not be NULL.
498 * \param len Number of characters in the sequence \a str.
499 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
500 * a positive value if this string is greater than the comparand.
502 * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
504 int compare(size_type pos, size_type n, const_pointer str, size_type len) const
506 if (BOOST_UNLIKELY(pos > m_Len))
507 BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::compare: the position is out of range"));
509 size_type compare_size = m_Len - pos;
510 if (compare_size > len)
512 if (compare_size > n)
514 return compare_internal(m_pStart + pos, compare_size, str, compare_size);
517 * Lexicographically compares the argument string to a part of this string
519 * \pre <tt>pos <= size()</tt>
520 * \param pos Starting position within this string to perform comparison to
521 * \param n Length of the substring of this string to perform comparison to
522 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
523 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
524 * a positive value if this string is greater than the comparand.
526 * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
528 int compare(size_type pos, size_type n, const_pointer str) const BOOST_NOEXCEPT
530 return compare(pos, n, str, traits_type::length(str));
533 * Lexicographically compares the argument string literal to a part of this string
535 * \pre <tt>pos <= size()</tt>
536 * \param pos Starting position within this string to perform comparison to
537 * \param n Length of the substring of this string to perform comparison to
538 * \param that Comparand
539 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
540 * a positive value if this string is greater than the comparand.
542 * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
544 int compare(size_type pos, size_type n, this_type const& that) const BOOST_NOEXCEPT
546 return compare(pos, n, that.c_str(), that.size());
549 * Lexicographically compares the argument string to this string
551 * \param str Comparand. Must point to a sequence of characters, must not be NULL.
552 * \param len Number of characters in the sequence \a str.
553 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
554 * a positive value if this string is greater than the comparand.
556 int compare(const_pointer str, size_type len) const BOOST_NOEXCEPT
558 return compare(0, m_Len, str, len);
561 * Lexicographically compares the argument string to this string
563 * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
564 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
565 * a positive value if this string is greater than the comparand.
567 int compare(const_pointer str) const BOOST_NOEXCEPT
569 return compare(0, m_Len, str, traits_type::length(str));
572 * Lexicographically compares the argument string to this string
574 * \param that Comparand
575 * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
576 * a positive value if this string is greater than the comparand.
578 int compare(this_type const& that) const BOOST_NOEXCEPT
580 return compare(0, m_Len, that.c_str(), that.size());
584 #ifndef BOOST_LOG_DOXYGEN_PASS
585 //! Internal comparison implementation
586 static int compare_internal(const_pointer pLeft, size_type LeftLen, const_pointer pRight, size_type RightLen) BOOST_NOEXCEPT
590 const int result = traits_type::compare(pLeft, pRight, (LeftLen < RightLen ? LeftLen : RightLen));
594 return LeftLen < RightLen ? -1 : (LeftLen > RightLen ? 1 : 0);
596 #endif // BOOST_LOG_DOXYGEN_PASS
599 #if !defined(BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS)
600 template< typename CharT, typename TraitsT >
601 constexpr typename basic_string_literal< CharT, TraitsT >::value_type
602 basic_string_literal< CharT, TraitsT >::g_EmptyString[1];
604 template< typename CharT, typename TraitsT >
605 const typename basic_string_literal< CharT, TraitsT >::value_type
606 basic_string_literal< CharT, TraitsT >::g_EmptyString[1] = { 0 };
611 template< typename CharT, typename TraitsT >
612 inline void insert_fill_chars(std::basic_ostream< CharT, TraitsT >& strm, std::size_t n)
614 enum { chunk_size = 8 };
615 CharT fill_chars[chunk_size];
616 const CharT filler = strm.fill();
617 for (unsigned int i = 0; i < chunk_size; ++i)
618 fill_chars[i] = filler;
619 for (; n >= chunk_size && strm.good(); n -= chunk_size)
620 strm.write(fill_chars, static_cast< std::size_t >(chunk_size));
621 if (n > 0 && strm.good())
622 strm.write(fill_chars, n);
625 template< typename CharT, typename TraitsT >
626 void insert_aligned(std::basic_ostream< CharT, TraitsT >& strm, const CharT* p, std::size_t size)
628 const std::size_t alignment_size = static_cast< std::size_t >(strm.width()) - size;
629 const bool align_left = (strm.flags() & std::basic_ostream< CharT, TraitsT >::adjustfield) == std::basic_ostream< CharT, TraitsT >::left;
634 aux::insert_fill_chars(strm, alignment_size);
638 aux::insert_fill_chars(strm, alignment_size);
647 template< typename CharT, typename StrmTraitsT, typename LitTraitsT >
648 inline std::basic_ostream< CharT, StrmTraitsT >& operator<< (
649 std::basic_ostream< CharT, StrmTraitsT >& strm, basic_string_literal< CharT, LitTraitsT > const& lit)
653 const std::size_t size = lit.size();
654 const std::size_t w = static_cast< std::size_t >(strm.width());
656 strm.write(lit.c_str(), static_cast< std::streamsize >(size));
658 aux::insert_aligned(strm, lit.c_str(), lit.size());
665 template< typename CharT, typename TraitsT >
666 inline BOOST_CXX14_CONSTEXPR void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_literal< CharT, TraitsT >& right) BOOST_NOEXCEPT
671 //! Creates a string literal wrapper from a constant string literal
672 #ifdef BOOST_LOG_USE_CHAR
673 template< typename T, std::size_t LenV >
674 inline BOOST_CONSTEXPR
675 #ifndef BOOST_LOG_DOXYGEN_PASS
676 typename boost::enable_if_c<
677 is_same< T, const char >::value,
681 basic_string_literal< T >
682 #endif // BOOST_LOG_DOXYGEN_PASS
683 str_literal(T(&p)[LenV]) BOOST_NOEXCEPT
685 return string_literal(p);
689 #ifndef BOOST_LOG_DOXYGEN_PASS
691 #ifdef BOOST_LOG_USE_WCHAR_T
692 template< typename T, std::size_t LenV >
693 inline BOOST_CONSTEXPR typename boost::enable_if_c<
694 is_same< T, const wchar_t >::value,
697 str_literal(T(&p)[LenV]) BOOST_NOEXCEPT
699 return wstring_literal(p);
703 #endif // BOOST_LOG_DOXYGEN_PASS
705 BOOST_LOG_CLOSE_NAMESPACE // namespace log
709 #include <boost/log/detail/footer.hpp>
711 #endif // BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_