• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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