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