mirror of https://github.com/AxioDL/logvisor.git
214 lines
7.2 KiB
C++
214 lines
7.2 KiB
C++
//
|
|
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
#ifndef NOWIDE_STACKSTRING_HPP_INCLUDED
|
|
#define NOWIDE_STACKSTRING_HPP_INCLUDED
|
|
|
|
#include <nowide/convert.hpp>
|
|
#include <nowide/utf/utf.hpp>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
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 #NOWIDE_REPLACEMENT_CHARACTER
|
|
///
|
|
/// If a NULL pointer is passed to the constructor or convert method, NULL will be returned by c_str.
|
|
/// Similarily 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() : data_(NULL)
|
|
{
|
|
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) : data_(NULL)
|
|
{
|
|
convert(input);
|
|
}
|
|
explicit basic_stackstring(std::string_view input) : data_(NULL) {
|
|
convert(input.data(), input.data() + input.size());
|
|
}
|
|
/// 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) : data_(NULL)
|
|
{
|
|
convert(begin, end);
|
|
}
|
|
/// Copy construct from other
|
|
basic_stackstring(const basic_stackstring& other) : data_(NULL)
|
|
{
|
|
*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_ = NULL;
|
|
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_ = NULL;
|
|
}
|
|
/// 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_;
|
|
}; // 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
|
|
|
|
#endif
|