stackstring.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //
  2. // Copyright (c) 2012 Artyom Beilis (Tonkikh)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. #ifndef BOOST_NOWIDE_STACKSTRING_HPP_INCLUDED
  9. #define BOOST_NOWIDE_STACKSTRING_HPP_INCLUDED
  10. #include <boost/nowide/convert.hpp>
  11. #include <cassert>
  12. #include <cstring>
  13. namespace boost {
  14. namespace nowide {
  15. ///
  16. /// \brief A class that allows to create a temporary wide or narrow UTF strings from
  17. /// wide or narrow UTF source.
  18. ///
  19. /// It uses a stack buffer if the string is short enough
  20. /// otherwise allocates a buffer on the heap.
  21. ///
  22. /// Invalid UTF characters are replaced by the substitution character, see #BOOST_NOWIDE_REPLACEMENT_CHARACTER
  23. ///
  24. /// If a NULL pointer is passed to the constructor or convert method, NULL will be returned by c_str.
  25. /// Similarily a default constructed stackstring will return NULL on calling c_str.
  26. ///
  27. template<typename CharOut = wchar_t, typename CharIn = char, size_t BufferSize = 256>
  28. class basic_stackstring
  29. {
  30. public:
  31. /// Size of the stack buffer
  32. static const size_t buffer_size = BufferSize;
  33. /// Type of the output character (converted to)
  34. typedef CharOut output_char;
  35. /// Type of the input character (converted from)
  36. typedef CharIn input_char;
  37. /// Creates a NULL stackstring
  38. basic_stackstring() : data_(NULL)
  39. {
  40. buffer_[0] = 0;
  41. }
  42. /// Convert the NULL terminated string input and store in internal buffer
  43. /// If input is NULL, nothing will be stored
  44. explicit basic_stackstring(const input_char* input) : data_(NULL)
  45. {
  46. convert(input);
  47. }
  48. /// Convert the sequence [begin, end) and store in internal buffer
  49. /// If begin is NULL, nothing will be stored
  50. basic_stackstring(const input_char* begin, const input_char* end) : data_(NULL)
  51. {
  52. convert(begin, end);
  53. }
  54. /// Copy construct from other
  55. basic_stackstring(const basic_stackstring& other) : data_(NULL)
  56. {
  57. *this = other;
  58. }
  59. /// Copy assign from other
  60. basic_stackstring& operator=(const basic_stackstring& other)
  61. {
  62. if(this != &other)
  63. {
  64. clear();
  65. const size_t len = other.length();
  66. if(other.uses_stack_memory())
  67. data_ = buffer_;
  68. else if(other.data_)
  69. data_ = new output_char[len + 1];
  70. else
  71. {
  72. data_ = NULL;
  73. return *this;
  74. }
  75. std::memcpy(data_, other.data_, sizeof(output_char) * (len + 1));
  76. }
  77. return *this;
  78. }
  79. ~basic_stackstring()
  80. {
  81. clear();
  82. }
  83. /// Convert the NULL terminated string input and store in internal buffer
  84. /// If input is NULL, the current buffer will be reset to NULL
  85. output_char* convert(const input_char* input)
  86. {
  87. if(input)
  88. return convert(input, input + detail::strlen(input));
  89. clear();
  90. return get();
  91. }
  92. /// Convert the sequence [begin, end) and store in internal buffer
  93. /// If begin is NULL, the current buffer will be reset to NULL
  94. output_char* convert(const input_char* begin, const input_char* end)
  95. {
  96. clear();
  97. if(begin)
  98. {
  99. const size_t input_len = end - begin;
  100. // Minimum size required: 1 output char per input char + trailing NULL
  101. const size_t min_output_size = input_len + 1;
  102. // If there is a chance the converted string fits on stack, try it
  103. if(min_output_size <= buffer_size && detail::convert_buffer(buffer_, buffer_size, begin, end))
  104. data_ = buffer_;
  105. else
  106. {
  107. // Fallback: Allocate a buffer that is surely large enough on heap
  108. // Max size: Every input char is transcoded to the output char with maximum with + trailing NULL
  109. const size_t max_output_size = input_len * detail::utf::utf_traits<output_char>::max_width + 1;
  110. data_ = new output_char[max_output_size];
  111. const bool success = detail::convert_buffer(data_, max_output_size, begin, end) == data_;
  112. assert(success);
  113. (void)success;
  114. }
  115. }
  116. return get();
  117. }
  118. /// Return the converted, NULL-terminated string or NULL if no string was converted
  119. output_char* get()
  120. {
  121. return data_;
  122. }
  123. /// Return the converted, NULL-terminated string or NULL if no string was converted
  124. const output_char* get() const
  125. {
  126. return data_;
  127. }
  128. /// Reset the internal buffer to NULL
  129. void clear()
  130. {
  131. if(!uses_stack_memory())
  132. delete[] data_;
  133. data_ = NULL;
  134. }
  135. /// Swap lhs with rhs
  136. friend void swap(basic_stackstring& lhs, basic_stackstring& rhs)
  137. {
  138. if(lhs.uses_stack_memory())
  139. {
  140. if(rhs.uses_stack_memory())
  141. {
  142. for(size_t i = 0; i < buffer_size; i++)
  143. std::swap(lhs.buffer_[i], rhs.buffer_[i]);
  144. } else
  145. {
  146. lhs.data_ = rhs.data_;
  147. rhs.data_ = rhs.buffer_;
  148. for(size_t i = 0; i < buffer_size; i++)
  149. rhs.buffer_[i] = lhs.buffer_[i];
  150. }
  151. } else if(rhs.uses_stack_memory())
  152. {
  153. rhs.data_ = lhs.data_;
  154. lhs.data_ = lhs.buffer_;
  155. for(size_t i = 0; i < buffer_size; i++)
  156. lhs.buffer_[i] = rhs.buffer_[i];
  157. } else
  158. std::swap(lhs.data_, rhs.data_);
  159. }
  160. protected:
  161. /// True if the stack memory is used
  162. bool uses_stack_memory() const
  163. {
  164. return data_ == buffer_;
  165. }
  166. /// Return the current length of the string excluding the NULL terminator
  167. /// If NULL is stored returns NULL
  168. size_t length() const
  169. {
  170. if(!data_)
  171. return 0;
  172. size_t len = 0;
  173. while(data_[len])
  174. len++;
  175. return len;
  176. }
  177. private:
  178. output_char buffer_[buffer_size];
  179. output_char* data_;
  180. }; // basic_stackstring
  181. ///
  182. /// Convenience typedef
  183. ///
  184. typedef basic_stackstring<wchar_t, char, 256> wstackstring;
  185. ///
  186. /// Convenience typedef
  187. ///
  188. typedef basic_stackstring<char, wchar_t, 256> stackstring;
  189. ///
  190. /// Convenience typedef
  191. ///
  192. typedef basic_stackstring<wchar_t, char, 16> wshort_stackstring;
  193. ///
  194. /// Convenience typedef
  195. ///
  196. typedef basic_stackstring<char, wchar_t, 16> short_stackstring;
  197. } // namespace nowide
  198. } // namespace boost
  199. #endif