123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- //
- // Copyright (c) 2012 Artyom Beilis (Tonkikh)
- //
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- #ifndef BOOST_NOWIDE_STACKSTRING_HPP_INCLUDED
- #define BOOST_NOWIDE_STACKSTRING_HPP_INCLUDED
- #include <boost/nowide/convert.hpp>
- #include <boost/nowide/utf/utf.hpp>
- #include <cassert>
- #include <cstring>
- namespace boost {
- namespace nowide {
- ///
- /// \brief A class that allows to create a temporary wide or narrow UTF strings from
- /// wide or narrow UTF source.
- ///
- /// It uses a stack buffer if the string is short enough
- /// otherwise allocates a buffer on the heap.
- ///
- /// Invalid UTF characters are replaced by the substitution character, see #BOOST_NOWIDE_REPLACEMENT_CHARACTER
- ///
- /// If a NULL pointer is passed to the constructor or convert method, NULL will be returned by c_str.
- /// Similarly a default constructed stackstring will return NULL on calling c_str.
- ///
- template<typename CharOut = wchar_t, typename CharIn = char, size_t BufferSize = 256>
- class basic_stackstring
- {
- public:
- /// Size of the stack buffer
- static const size_t buffer_size = BufferSize;
- /// Type of the output character (converted to)
- using output_char = CharOut;
- /// Type of the input character (converted from)
- using input_char = CharIn;
- /// Creates a NULL stackstring
- basic_stackstring()
- {
- buffer_[0] = 0;
- }
- /// Convert the NULL terminated string input and store in internal buffer
- /// If input is NULL, nothing will be stored
- explicit basic_stackstring(const input_char* input)
- {
- convert(input);
- }
- /// Convert the sequence [begin, end) and store in internal buffer
- /// If begin is NULL, nothing will be stored
- basic_stackstring(const input_char* begin, const input_char* end)
- {
- convert(begin, end);
- }
- /// Copy construct from other
- basic_stackstring(const basic_stackstring& other)
- {
- *this = other;
- }
- /// Copy assign from other
- basic_stackstring& operator=(const basic_stackstring& other)
- {
- if(this != &other)
- {
- clear();
- const size_t len = other.length();
- if(other.uses_stack_memory())
- data_ = buffer_;
- else if(other.data_)
- data_ = new output_char[len + 1];
- else
- {
- data_ = nullptr;
- return *this;
- }
- std::memcpy(data_, other.data_, sizeof(output_char) * (len + 1));
- }
- return *this;
- }
- ~basic_stackstring()
- {
- clear();
- }
- /// Convert the NULL terminated string input and store in internal buffer
- /// If input is NULL, the current buffer will be reset to NULL
- output_char* convert(const input_char* input)
- {
- if(input)
- return convert(input, input + utf::strlen(input));
- clear();
- return get();
- }
- /// Convert the sequence [begin, end) and store in internal buffer
- /// If begin is NULL, the current buffer will be reset to NULL
- output_char* convert(const input_char* begin, const input_char* end)
- {
- clear();
- if(begin)
- {
- const size_t input_len = end - begin;
- // Minimum size required: 1 output char per input char + trailing NULL
- const size_t min_output_size = input_len + 1;
- // If there is a chance the converted string fits on stack, try it
- if(min_output_size <= buffer_size && utf::convert_buffer(buffer_, buffer_size, begin, end))
- data_ = buffer_;
- else
- {
- // Fallback: Allocate a buffer that is surely large enough on heap
- // Max size: Every input char is transcoded to the output char with maximum with + trailing NULL
- const size_t max_output_size = input_len * utf::utf_traits<output_char>::max_width + 1;
- data_ = new output_char[max_output_size];
- const bool success = utf::convert_buffer(data_, max_output_size, begin, end) == data_;
- assert(success);
- (void)success;
- }
- }
- return get();
- }
- /// Return the converted, NULL-terminated string or NULL if no string was converted
- output_char* get()
- {
- return data_;
- }
- /// Return the converted, NULL-terminated string or NULL if no string was converted
- const output_char* get() const
- {
- return data_;
- }
- /// Reset the internal buffer to NULL
- void clear()
- {
- if(!uses_stack_memory())
- delete[] data_;
- data_ = nullptr;
- }
- /// Swap lhs with rhs
- friend void swap(basic_stackstring& lhs, basic_stackstring& rhs)
- {
- if(lhs.uses_stack_memory())
- {
- if(rhs.uses_stack_memory())
- {
- for(size_t i = 0; i < buffer_size; i++)
- std::swap(lhs.buffer_[i], rhs.buffer_[i]);
- } else
- {
- lhs.data_ = rhs.data_;
- rhs.data_ = rhs.buffer_;
- for(size_t i = 0; i < buffer_size; i++)
- rhs.buffer_[i] = lhs.buffer_[i];
- }
- } else if(rhs.uses_stack_memory())
- {
- rhs.data_ = lhs.data_;
- lhs.data_ = lhs.buffer_;
- for(size_t i = 0; i < buffer_size; i++)
- lhs.buffer_[i] = rhs.buffer_[i];
- } else
- std::swap(lhs.data_, rhs.data_);
- }
- protected:
- /// True if the stack memory is used
- bool uses_stack_memory() const
- {
- return data_ == buffer_;
- }
- /// Return the current length of the string excluding the NULL terminator
- /// If NULL is stored returns NULL
- size_t length() const
- {
- if(!data_)
- return 0;
- size_t len = 0;
- while(data_[len])
- len++;
- return len;
- }
- private:
- output_char buffer_[buffer_size];
- output_char* data_ = nullptr;
- }; // basic_stackstring
- ///
- /// Convenience typedef
- ///
- using wstackstring = basic_stackstring<wchar_t, char, 256>;
- ///
- /// Convenience typedef
- ///
- using stackstring = basic_stackstring<char, wchar_t, 256>;
- ///
- /// Convenience typedef
- ///
- using wshort_stackstring = basic_stackstring<wchar_t, char, 16>;
- ///
- /// Convenience typedef
- ///
- using short_stackstring = basic_stackstring<char, wchar_t, 16>;
- } // namespace nowide
- } // namespace boost
- #endif
|