1 /*
2 * Copyright Andrey Semashev 2007 - 2015.
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 */
basic_string_literal()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 >
basic_string_literal(T (& p)[LenV],typename enable_if<is_same<T,const value_type>,int>::type=0)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 */
basic_string_literal(basic_string_literal const & that)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 */
operator =(this_type const & that)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
operator =(T (& p)[LenV])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 */
operator ==(this_type const & that) const158 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 */
operator ==(const_pointer str) const168 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 */
operator ==(string_type const & that) const178 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 */
operator <(this_type const & that) const189 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 */
operator <(const_pointer str) const199 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 */
operator <(string_type const & that) const209 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 */
operator >(this_type const & that) const220 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 */
operator >(const_pointer str) const230 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 */
operator >(string_type const & that) const240 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 */
operator [](size_type i) const252 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 */
at(size_type i) const264 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 */
c_str() const274 const_pointer c_str() const BOOST_NOEXCEPT { return m_pStart; }
275 /*!
276 * \return Pointer to the beginning of the literal
277 */
data() const278 const_pointer data() const BOOST_NOEXCEPT { return m_pStart; }
279 /*!
280 * \return Length of the literal
281 */
size() const282 size_type size() const BOOST_NOEXCEPT { return m_Len; }
283 /*!
284 * \return Length of the literal
285 */
length() const286 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 */
empty() const291 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 */
begin() const299 const_iterator begin() const BOOST_NOEXCEPT { return m_pStart; }
300 /*!
301 * \return Iterator that points after the last character of the literal
302 */
end() const303 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 */
rbegin() const307 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 */
rend() const311 const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); }
312
313 /*!
314 * \return STL string constructed from the literal
315 */
str() const316 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 */
clear()326 void clear() BOOST_NOEXCEPT
327 {
328 m_pStart = g_EmptyString;
329 m_Len = 0;
330 }
331 /*!
332 * The method swaps two literals
333 */
swap(this_type & that)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 */
assign(this_type const & that)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
assign(T (& p)[LenV])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 */
copy(value_type * str,size_type n,size_type pos=0) const391 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 */
compare(size_type pos,size_type n,const_pointer str,size_type len) const416 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 */
compare(size_type pos,size_type n,const_pointer str) const440 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 */
compare(size_type pos,size_type n,this_type const & that) const456 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 */
compare(const_pointer str,size_type len) const468 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 */
compare(const_pointer str) const479 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 */
compare(this_type const & that) const490 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
compare_internal(const_pointer pLeft,size_type LeftLen,const_pointer pRight,size_type RightLen)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 >
insert_fill_chars(std::basic_ostream<CharT,TraitsT> & strm,std::size_t n)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 >
insert_aligned(std::basic_ostream<CharT,TraitsT> & strm,const CharT * p,std::size_t size)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 >
operator <<(std::basic_ostream<CharT,StrmTraitsT> & strm,basic_string_literal<CharT,LitTraitsT> const & lit)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 >
swap(basic_string_literal<CharT,TraitsT> & left,basic_string_literal<CharT,TraitsT> & right)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
str_literal(T (& p)[LenV])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
str_literal(T (& p)[LenV])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_
618