string_literal.hpp 20 KB

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