Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / log / utility / string_literal.hpp
1 /*
2  *          Copyright Andrey Semashev 2007 - 2014.
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)
6  */
7 /*!
8  * \file   string_literal.hpp
9  * \author Andrey Semashev
10  * \date   24.06.2007
11  *
12  * The header contains implementation of a constant string literal wrapper.
13  */
14
15 #ifndef BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_
17
18 #include <cstddef>
19 #include <stdexcept>
20 #include <iosfwd>
21 #include <ios> // std::streamsize
22 #include <string>
23 #include <iterator>
24 #include <boost/operators.hpp>
25 #include <boost/throw_exception.hpp>
26 #include <boost/type_traits/is_same.hpp>
27 #include <boost/utility/enable_if.hpp>
28 #include <boost/log/detail/config.hpp>
29 #include <boost/log/utility/string_literal_fwd.hpp>
30 #include <boost/log/detail/header.hpp>
31
32 #ifdef BOOST_HAS_PRAGMA_ONCE
33 #pragma once
34 #endif
35
36 namespace boost {
37
38 BOOST_LOG_OPEN_NAMESPACE
39
40 /*!
41  * \brief String literal wrapper
42  *
43  * The \c basic_string_literal is a thin wrapper around a constant string literal.
44  * It provides interface similar to STL strings, but because of read-only nature
45  * of string literals, lacks ability to modify string contents. However,
46  * \c basic_string_literal objects can be assigned to and cleared.
47  *
48  * The main advantage of this class comparing to other string classes is that
49  * it doesn't dynamically allocate memory and therefore is fast, thin and exception safe.
50  */
51 template< typename CharT, typename TraitsT >
52 class basic_string_literal
53     //! \cond
54     : public totally_ordered1< basic_string_literal< CharT, TraitsT >,
55         totally_ordered2< basic_string_literal< CharT, TraitsT >, const CharT*,
56             totally_ordered2<
57                 basic_string_literal< CharT, TraitsT >,
58                 std::basic_string< CharT, TraitsT >
59             >
60         >
61     >
62     //! \endcond
63 {
64     //! Self type
65     typedef basic_string_literal< CharT, TraitsT > this_type;
66
67 public:
68     typedef CharT value_type;
69     typedef TraitsT traits_type;
70
71     typedef std::size_t size_type;
72     typedef std::ptrdiff_t difference_type;
73     typedef const value_type* const_pointer;
74     typedef value_type const& const_reference;
75     typedef const value_type* const_iterator;
76     typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
77
78     //! Corresponding STL string type
79     typedef std::basic_string< value_type, traits_type > string_type;
80
81 private:
82     //! Pointer to the beginning of the literal
83     const_pointer m_pStart;
84     //! Length
85     size_type m_Len;
86
87     //! Empty string literal to support clear
88     static const value_type g_EmptyString[1];
89
90 public:
91     /*!
92      * Constructor
93      *
94      * \post <tt>empty() == true</tt>
95      */
96     basic_string_literal() BOOST_NOEXCEPT { clear(); }
97
98     /*!
99      * Constructor from a string literal
100      *
101      * \post <tt>*this == p</tt>
102      * \param p A zero-terminated constant sequence of characters
103      */
104     template< typename T, size_type LenV >
105     basic_string_literal(T(&p)[LenV]
106         //! \cond
107         , typename enable_if< is_same< T, const value_type >, int >::type = 0
108         //! \endcond
109         ) BOOST_NOEXCEPT
110         : m_pStart(p), m_Len(LenV - 1)
111     {
112     }
113
114     /*!
115      * Copy constructor
116      *
117      * \post <tt>*this == that</tt>
118      * \param that Source literal to copy string from
119      */
120     basic_string_literal(basic_string_literal const& that) BOOST_NOEXCEPT : m_pStart(that.m_pStart), m_Len(that.m_Len) {}
121
122     /*!
123      * Assignment operator
124      *
125      * \post <tt>*this == that</tt>
126      * \param that Source literal to copy string from
127      */
128     this_type& operator= (this_type const& that) BOOST_NOEXCEPT
129     {
130         return assign(that);
131     }
132     /*!
133      * Assignment from a string literal
134      *
135      * \post <tt>*this == p</tt>
136      * \param p A zero-terminated constant sequence of characters
137      */
138     template< typename T, size_type LenV >
139 #ifndef BOOST_LOG_DOXYGEN_PASS
140     typename enable_if<
141         is_same< T, const value_type >,
142         this_type&
143     >::type
144 #else
145     this_type&
146 #endif // BOOST_LOG_DOXYGEN_PASS
147     operator= (T(&p)[LenV]) BOOST_NOEXCEPT
148     {
149         return assign(p);
150     }
151
152     /*!
153      * Lexicographical comparison (equality)
154      *
155      * \param that Comparand
156      * \return \c true if the comparand string equals to this string, \c false otherwise
157      */
158     bool operator== (this_type const& that) const BOOST_NOEXCEPT
159     {
160         return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) == 0);
161     }
162     /*!
163      * Lexicographical comparison (equality)
164      *
165      * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
166      * \return \c true if the comparand string equals to this string, \c false otherwise
167      */
168     bool operator== (const_pointer str) const BOOST_NOEXCEPT
169     {
170         return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) == 0);
171     }
172     /*!
173      * Lexicographical comparison (equality)
174      *
175      * \param that Comparand
176      * \return \c true if the comparand string equals to this string, \c false otherwise
177      */
178     bool operator== (string_type const& that) const
179     {
180         return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) == 0);
181     }
182
183     /*!
184      * Lexicographical comparison (less ordering)
185      *
186      * \param that Comparand
187      * \return \c true if this string is less than the comparand, \c false otherwise
188      */
189     bool operator< (this_type const& that) const BOOST_NOEXCEPT
190     {
191         return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) < 0);
192     }
193     /*!
194      * Lexicographical comparison (less ordering)
195      *
196      * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
197      * \return \c true if this string is less than the comparand, \c false otherwise
198      */
199     bool operator< (const_pointer str) const BOOST_NOEXCEPT
200     {
201         return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) < 0);
202     }
203     /*!
204      * Lexicographical comparison (less ordering)
205      *
206      * \param that Comparand
207      * \return \c true if this string is less than the comparand, \c false otherwise
208      */
209     bool operator< (string_type const& that) const
210     {
211         return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) < 0);
212     }
213
214     /*!
215      * Lexicographical comparison (greater ordering)
216      *
217      * \param that Comparand
218      * \return \c true if this string is greater than the comparand, \c false otherwise
219      */
220     bool operator> (this_type const& that) const BOOST_NOEXCEPT
221     {
222         return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) > 0);
223     }
224     /*!
225      * Lexicographical comparison (greater ordering)
226      *
227      * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
228      * \return \c true if this string is greater than the comparand, \c false otherwise
229      */
230     bool operator> (const_pointer str) const BOOST_NOEXCEPT
231     {
232         return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) > 0);
233     }
234     /*!
235      * Lexicographical comparison (greater ordering)
236      *
237      * \param that Comparand
238      * \return \c true if this string is greater than the comparand, \c false otherwise
239      */
240     bool operator> (string_type const& that) const
241     {
242         return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) > 0);
243     }
244
245     /*!
246      * Subscript operator
247      *
248      * \pre <tt>i < size()</tt>
249      * \param i Requested character index
250      * \return Constant reference to the requested character
251      */
252     const_reference operator[] (size_type i) const BOOST_NOEXCEPT
253     {
254         return m_pStart[i];
255     }
256     /*!
257      * Checked subscript
258      *
259      * \param i Requested character index
260      * \return Constant reference to the requested character
261      *
262      * \b Throws: An <tt>std::exception</tt>-based exception if index \a i is out of string boundaries
263      */
264     const_reference at(size_type i) const
265     {
266         if (i >= m_Len)
267             BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::at: the index value is out of range"));
268         return m_pStart[i];
269     }
270
271     /*!
272      * \return Pointer to the beginning of the literal
273      */
274     const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; }
275     /*!
276      * \return Pointer to the beginning of the literal
277      */
278     const_pointer data() const BOOST_NOEXCEPT { return m_pStart; }
279     /*!
280      * \return Length of the literal
281      */
282     size_type size() const BOOST_NOEXCEPT { return m_Len; }
283     /*!
284      * \return Length of the literal
285      */
286     size_type length() const BOOST_NOEXCEPT { return m_Len; }
287
288     /*!
289      * \return \c true if the literal is an empty string, \c false otherwise
290      */
291     bool empty() const BOOST_NOEXCEPT
292     {
293         return (m_Len == 0);
294     }
295
296     /*!
297      * \return Iterator that points to the first character of the literal
298      */
299     const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; }
300     /*!
301      * \return Iterator that points after the last character of the literal
302      */
303     const_iterator end() const BOOST_NOEXCEPT { return m_pStart + m_Len; }
304     /*!
305      * \return Reverse iterator that points to the last character of the literal
306      */
307     const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); }
308     /*!
309      * \return Reverse iterator that points before the first character of the literal
310      */
311     const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); }
312
313     /*!
314      * \return STL string constructed from the literal
315      */
316     string_type str() const
317     {
318         return string_type(m_pStart, m_Len);
319     }
320
321     /*!
322      * The method clears the literal
323      *
324      * \post <tt>empty() == true</tt>
325      */
326     void clear() BOOST_NOEXCEPT
327     {
328         m_pStart = g_EmptyString;
329         m_Len = 0;
330     }
331     /*!
332      * The method swaps two literals
333      */
334     void swap(this_type& that) BOOST_NOEXCEPT
335     {
336         const_pointer p = m_pStart;
337         m_pStart = that.m_pStart;
338         that.m_pStart = p;
339
340         size_type l = m_Len;
341         m_Len = that.m_Len;
342         that.m_Len = l;
343     }
344
345     /*!
346      * Assignment from another literal
347      *
348      * \post <tt>*this == that</tt>
349      * \param that Source literal to copy string from
350      */
351     this_type& assign(this_type const& that) BOOST_NOEXCEPT
352     {
353         m_pStart = that.m_pStart;
354         m_Len = that.m_Len;
355         return *this;
356     }
357     /*!
358      * Assignment from another literal
359      *
360      * \post <tt>*this == p</tt>
361      * \param p A zero-terminated constant sequence of characters
362      */
363     template< typename T, size_type LenV >
364 #ifndef BOOST_LOG_DOXYGEN_PASS
365     typename enable_if<
366         is_same< T, const value_type >,
367         this_type&
368     >::type
369 #else
370     this_type&
371 #endif // BOOST_LOG_DOXYGEN_PASS
372     assign(T(&p)[LenV]) BOOST_NOEXCEPT
373     {
374         m_pStart = p;
375         m_Len = LenV - 1;
376         return *this;
377     }
378
379     /*!
380      * The method copies the literal or its portion to an external buffer
381      *
382      * \pre <tt>pos <= size()</tt>
383      * \param str Pointer to the external buffer beginning. Must not be NULL.
384      *            The buffer must have enough capacity to accommodate the requested number of characters.
385      * \param n Maximum number of characters to copy
386      * \param pos Starting position to start copying from
387      * \return Number of characters copied
388      *
389      * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
390      */
391     size_type copy(value_type* str, size_type n, size_type pos = 0) const
392     {
393         if (pos > m_Len)
394             BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::copy: the position is out of range"));
395
396         size_type len = m_Len - pos;
397         if (len > n)
398             len = n;
399         traits_type::copy(str, m_pStart + pos, len);
400         return len;
401     }
402
403     /*!
404      * Lexicographically compares the argument string to a part of this string
405      *
406      * \pre <tt>pos <= size()</tt>
407      * \param pos Starting position within this string to perform comparison to
408      * \param n Length of the substring of this string to perform comparison to
409      * \param str Comparand. Must point to a sequence of characters, must not be NULL.
410      * \param len Number of characters in the sequence \a str.
411      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
412      *         a positive value if this string is greater than the comparand.
413      *
414      * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
415      */
416     int compare(size_type pos, size_type n, const_pointer str, size_type len) const
417     {
418         if (pos > m_Len)
419             BOOST_THROW_EXCEPTION(std::out_of_range("basic_string_literal::compare: the position is out of range"));
420
421         size_type compare_size = m_Len - pos;
422         if (compare_size > len)
423             compare_size = len;
424         if (compare_size > n)
425             compare_size = n;
426         return compare_internal(m_pStart + pos, compare_size, str, compare_size);
427     }
428     /*!
429      * Lexicographically compares the argument string to a part of this string
430      *
431      * \pre <tt>pos <= size()</tt>
432      * \param pos Starting position within this string to perform comparison to
433      * \param n Length of the substring of this string to perform comparison to
434      * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
435      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
436      *         a positive value if this string is greater than the comparand.
437      *
438      * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
439      */
440     int compare(size_type pos, size_type n, const_pointer str) const BOOST_NOEXCEPT
441     {
442         return compare(pos, n, str, traits_type::length(str));
443     }
444     /*!
445      * Lexicographically compares the argument string literal to a part of this string
446      *
447      * \pre <tt>pos <= size()</tt>
448      * \param pos Starting position within this string to perform comparison to
449      * \param n Length of the substring of this string to perform comparison to
450      * \param that Comparand
451      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
452      *         a positive value if this string is greater than the comparand.
453      *
454      * \b Throws: An <tt>std::exception</tt>-based exception if \a pos is out of range.
455      */
456     int compare(size_type pos, size_type n, this_type const& that) const BOOST_NOEXCEPT
457     {
458         return compare(pos, n, that.c_str(), that.size());
459     }
460     /*!
461      * Lexicographically compares the argument string to this string
462      *
463      * \param str Comparand. Must point to a sequence of characters, must not be NULL.
464      * \param len Number of characters in the sequence \a str.
465      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
466      *         a positive value if this string is greater than the comparand.
467      */
468     int compare(const_pointer str, size_type len) const BOOST_NOEXCEPT
469     {
470         return compare(0, m_Len, str, len);
471     }
472     /*!
473      * Lexicographically compares the argument string to this string
474      *
475      * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL.
476      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
477      *         a positive value if this string is greater than the comparand.
478      */
479     int compare(const_pointer str) const BOOST_NOEXCEPT
480     {
481         return compare(0, m_Len, str, traits_type::length(str));
482     }
483     /*!
484      * Lexicographically compares the argument string to this string
485      *
486      * \param that Comparand
487      * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand,
488      *         a positive value if this string is greater than the comparand.
489      */
490     int compare(this_type const& that) const BOOST_NOEXCEPT
491     {
492         return compare(0, m_Len, that.c_str(), that.size());
493     }
494
495 private:
496 #ifndef BOOST_LOG_DOXYGEN_PASS
497     //! Internal comparison implementation
498     static int compare_internal(const_pointer pLeft, size_type LeftLen, const_pointer pRight, size_type RightLen) BOOST_NOEXCEPT
499     {
500         if (pLeft != pRight)
501         {
502             const int result = traits_type::compare(pLeft, pRight, (LeftLen < RightLen ? LeftLen : RightLen));
503             if (result != 0)
504                 return result;
505         }
506         return LeftLen < RightLen ? -1 : (LeftLen > RightLen ? 1 : 0);
507     }
508 #endif // BOOST_LOG_DOXYGEN_PASS
509 };
510
511 template< typename CharT, typename TraitsT >
512 typename basic_string_literal< CharT, TraitsT >::value_type const
513 basic_string_literal< CharT, TraitsT >::g_EmptyString[1] = { 0 };
514
515 namespace aux {
516
517 template< typename CharT, typename TraitsT >
518 inline void insert_fill_chars(std::basic_ostream< CharT, TraitsT >& strm, std::size_t n)
519 {
520     enum { chunk_size = 8 };
521     CharT fill_chars[chunk_size];
522     const CharT filler = strm.fill();
523     for (unsigned int i = 0; i < chunk_size; ++i)
524         fill_chars[i] = filler;
525     for (; n >= chunk_size && strm.good(); n -= chunk_size)
526         strm.write(fill_chars, static_cast< std::size_t >(chunk_size));
527     if (n > 0 && strm.good())
528         strm.write(fill_chars, n);
529 }
530
531 template< typename CharT, typename TraitsT >
532 void insert_aligned(std::basic_ostream< CharT, TraitsT >& strm, const CharT* p, std::size_t size)
533 {
534     const std::size_t alignment_size = static_cast< std::size_t >(strm.width()) - size;
535     const bool align_left = (strm.flags() & std::basic_ostream< CharT, TraitsT >::adjustfield) == std::basic_ostream< CharT, TraitsT >::left;
536     if (align_left)
537     {
538         strm.write(p, size);
539         if (strm.good())
540             aux::insert_fill_chars(strm, alignment_size);
541     }
542     else
543     {
544         aux::insert_fill_chars(strm, alignment_size);
545         if (strm.good())
546             strm.write(p, size);
547     }
548 }
549
550 } // namespace aux
551
552 //! Output operator
553 template< typename CharT, typename StrmTraitsT, typename LitTraitsT >
554 inline std::basic_ostream< CharT, StrmTraitsT >& operator<< (
555     std::basic_ostream< CharT, StrmTraitsT >& strm, basic_string_literal< CharT, LitTraitsT > const& lit)
556 {
557     if (strm.good())
558     {
559         const std::size_t size = lit.size();
560         const std::size_t w = static_cast< std::size_t >(strm.width());
561         if (w <= size)
562             strm.write(lit.c_str(), static_cast< std::streamsize >(size));
563         else
564             aux::insert_aligned(strm, lit.c_str(), lit.size());
565         strm.width(0);
566     }
567     return strm;
568 }
569
570 //! External swap
571 template< typename CharT, typename TraitsT >
572 inline void swap(basic_string_literal< CharT, TraitsT >& left, basic_string_literal< CharT, TraitsT >& right) BOOST_NOEXCEPT
573 {
574     left.swap(right);
575 }
576
577 //! Creates a string literal wrapper from a constant string literal
578 #ifdef BOOST_LOG_USE_CHAR
579 template< typename T, std::size_t LenV >
580 inline
581 #ifndef BOOST_LOG_DOXYGEN_PASS
582 typename enable_if<
583     is_same< T, const char >,
584     string_literal
585 >::type
586 #else
587 basic_string_literal< T >
588 #endif // BOOST_LOG_DOXYGEN_PASS
589 str_literal(T(&p)[LenV])
590 {
591     return string_literal(p);
592 }
593 #endif
594
595 #ifndef BOOST_LOG_DOXYGEN_PASS
596
597 #ifdef BOOST_LOG_USE_WCHAR_T
598 template< typename T, std::size_t LenV >
599 inline typename enable_if<
600     is_same< T, const wchar_t >,
601     wstring_literal
602 >::type
603 str_literal(T(&p)[LenV])
604 {
605     return wstring_literal(p);
606 }
607 #endif
608
609 #endif // BOOST_LOG_DOXYGEN_PASS
610
611 BOOST_LOG_CLOSE_NAMESPACE // namespace log
612
613 } // namespace boost
614
615 #include <boost/log/detail/footer.hpp>
616
617 #endif // BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_