add to_wstring & format_wstring

This commit is contained in:
Nomango 2019-03-13 15:38:18 +08:00 committed by Nomango
parent be74b49196
commit b0978251b8
2 changed files with 213 additions and 40 deletions

View File

@ -19,7 +19,6 @@
// THE SOFTWARE.
#include "String.h"
#include <cstring>
namespace easy2d
{
@ -135,6 +134,12 @@ namespace easy2d
assign(cstr, count);
}
String::String(size_type count, wchar_t ch)
: String()
{
assign(count, ch);
}
String::String(std::wstring const & str)
: String(str.c_str(), false)
{
@ -171,18 +176,13 @@ namespace easy2d
if (count > capacity_)
{
destroy();
capacity_ = size_ = count;
str_ = allocate(capacity_ + 1);
traits::assign(str_, count, ch);
str_ = allocate(count + 1);
capacity_ = count;
}
else
{
capacity_ = size_ = count;
traits::assign(str_, count, ch);
}
traits::assign(str_[size_], wchar_t());
size_ = count;
traits::assign(str_, count, ch);
traits::assign(str_[size_], value_type());
}
else
@ -201,18 +201,13 @@ namespace easy2d
if (count > capacity_)
{
destroy();
capacity_ = size_ = count;
str_ = allocate(capacity_ + 1);
traits::move(str_, cstr, size_);
str_ = allocate(count + 1);
capacity_ = count;
}
else
{
capacity_ = size_ = count;
traits::move(str_, cstr, size_);
}
traits::assign(str_[size_], wchar_t());
size_ = count;
traits::move(str_, cstr, size_);
traits::assign(str_[size_], value_type());
}
else
{
@ -375,7 +370,7 @@ namespace easy2d
traits::move(new_str, str_, size_);
traits::assign(new_str + size_, count, ch);
traits::assign(new_str[new_size], wchar_t());
traits::assign(new_str[new_size], value_type());
destroy();
@ -395,7 +390,7 @@ namespace easy2d
traits::move(new_str, str_, size_);
traits::move(new_str + size_, cstr, count);
traits::assign(new_str[new_size], wchar_t());
traits::assign(new_str[new_size], value_type());
destroy();
@ -420,7 +415,7 @@ namespace easy2d
traits::move(new_str, str_, size_);
traits::move(new_str + size_, other.begin() + pos, count);
traits::assign(new_str[new_size], wchar_t());
traits::assign(new_str[new_size], value_type());
destroy();

View File

@ -21,6 +21,8 @@
#pragma once
#include "../macros.h"
#include <string>
#include <cstring>
#include <cstdio>
namespace easy2d
{
@ -39,18 +41,22 @@ namespace easy2d
using const_reference = const value_type &;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using traits = std::char_traits<wchar_t>;
using allocator = std::allocator<wchar_t>;
using traits = std::char_traits<value_type>;
using allocator = std::allocator<value_type>;
String();
String(const wchar_t* cstr, bool const_str = true);
String(const wchar_t* cstr, size_type count);
String(size_type count, wchar_t ch);
String(std::wstring const& str);
String(String const& rhs);
String(String const& rhs, size_type pos, size_type count = npos);
String(String && rhs);
~String();
template <typename _Iter>
String(_Iter first, _Iter last) : String() { assign_iter(first, last); }
inline const wchar_t* c_str() const { return const_str_ ? const_str_ : L""; }
inline wchar_t at(size_t i) const { return (*this)[i]; }
inline size_type size() const { return size_; }
@ -58,10 +64,10 @@ namespace easy2d
inline size_type capacity() const { return capacity_; }
inline size_type max_size() const { return (static_cast<size_type>(-1) / sizeof(value_type)); }
inline bool empty() const { return size_ == 0; }
inline void clear() { discard_const_data(); if (str_) { str_[0] = wchar_t(); } size_ = 0; }
inline void clear() { discard_const_data(); if (str_) { str_[0] = value_type(); } size_ = 0; }
void reserve(const size_type new_cap = 0);
inline void resize(const size_type new_size, const wchar_t ch = wchar_t()) { check_operability(); if (new_size < size_) str_[size_ = new_size] = wchar_t(); else append(new_size - size_, ch); }
inline void resize(const size_type new_size, const wchar_t ch = value_type()) { check_operability(); if (new_size < size_) str_[size_ = new_size] = value_type(); else append(new_size - size_, ch); }
int compare(const wchar_t* const str) const;
inline int compare(String const& str) const { return compare(str.c_str()); }
@ -104,6 +110,9 @@ namespace easy2d
inline String& assign(String const& rhs) { String{ rhs }.swap(*this); return *this; }
inline String& assign(String const& rhs, size_type pos, size_type count = npos) { String(rhs, pos, count).swap(*this); return *this; }
template <typename _Iter>
inline String& assign(_Iter first, _Iter last) { assign_iter(first, last); return(*this); }
String& erase(size_type offset = 0, size_type count = npos);
iterator erase(const const_iterator where) { size_type off = where - cbegin(); erase(off, 1); return begin() + off; }
iterator erase(const const_iterator first, const const_iterator last) { size_type off = first - cbegin(); erase(first - cbegin(), last - first); return begin() + off; }
@ -119,7 +128,7 @@ namespace easy2d
inline iterator insert(const_iterator pos, wchar_t ch) { return insert(pos, 1, ch); }
inline void push_back(const wchar_t ch) { append(1, ch); }
inline wchar_t pop_back() { if (empty()) throw std::out_of_range("pop_back() called on empty string"); check_operability(); wchar_t ch = str_[--size_]; str_[size_] = wchar_t(); return ch; }
inline wchar_t pop_back() { if (empty()) throw std::out_of_range("pop_back() called on empty string"); check_operability(); wchar_t ch = str_[--size_]; str_[size_] = value_type(); return ch; }
std::string to_string() const;
std::wstring to_wstring() const;
@ -147,8 +156,6 @@ namespace easy2d
inline const_reference back() const { if (empty()) throw std::out_of_range("back() called on empty string"); return const_str_[size_ - 1]; }
public:
inline operator const wchar_t*() const { return const_str_ ? const_str_ : L""; }
inline operator wchar_t*() { check_operability(); return str_; }
inline wchar_t operator[](size_type off) const { if(off >= size_) throw std::out_of_range("string subscript out of range"); return const_str_[off]; }
inline wchar_t& operator[](size_type off) { if (off >= size_) throw std::out_of_range("string subscript out of range"); check_operability(); return str_[off]; }
@ -169,9 +176,6 @@ namespace easy2d
inline String& operator=(String const& rhs) { if (this != &rhs) String{ rhs }.swap(*this); return *this; }
inline String& operator=(String && rhs) { if (this != &rhs) String{ rhs }.swap(*this); return *this; }
inline bool operator==(String const& rhs) { return compare(rhs) == 0; }
inline bool operator==(const wchar_t* cstr) { return compare(cstr) == 0; }
inline bool operator!=(String const& rhs) { return compare(rhs) != 0; }
inline bool operator!=(const wchar_t* cstr) { return compare(cstr) != 0; }
@ -189,6 +193,29 @@ namespace easy2d
void check_offset(size_type offset) const { if (offset > size()) throw std::out_of_range("invalid string position"); }
size_type clamp_suffix_size(size_type off, size_type count) const { return std::min(size() - off, count); }
template <typename _Iter>
void assign_iter(_Iter first, _Iter last)
{
size_type diff = static_cast<size_type>(std::distance(first, last));
if (diff == 0)
return;
discard_const_data();
if (diff > capacity_)
{
destroy();
str_ = allocate(diff + 1);
capacity_ = diff;
}
size_ = diff;
for (size_type index = 0; first != last; ++first, ++index)
{
traits::assign(str_[index], traits::to_char_type(*first));
}
traits::assign(str_[size_], value_type());
}
private:
union
{
@ -210,6 +237,14 @@ namespace easy2d
};
//
// operator== for String
//
inline bool operator==(String const& lhs, String const& rhs) { return lhs.compare(rhs) == 0; }
inline bool operator==(const wchar_t* lhs, String const& rhs) { return rhs.compare(rhs) == 0; }
inline bool operator==(String const& lhs, const wchar_t* rhs) { return lhs.compare(rhs) == 0; }
//
// operator+ for String
//
@ -229,6 +264,37 @@ namespace easy2d
// operator<<>> for String
//
std::basic_ostream<String::traits::char_type, String::traits>& operator<<(std::basic_ostream<String::traits::char_type, String::traits>& os, const String & str);
std::basic_istream<String::traits::char_type, String::traits>& operator>>(std::basic_istream<String::traits::char_type, String::traits>& is, String & str);
//
// to_string functions
//
String to_wstring(int val);
String to_wstring(unsigned int val);
String to_wstring(long val);
String to_wstring(unsigned long val);
String to_wstring(long long val);
String to_wstring(unsigned long long val);
String to_wstring(float val);
String to_wstring(double val);
String to_wstring(long double val);
//
// format_wstring
//
template<typename ..._Args>
inline String format_wstring(const wchar_t* const fmt, _Args&&... args);
}
namespace easy2d
{
//
// details of operator<<>>
//
inline std::basic_ostream<String::traits::char_type, String::traits>&
operator<<(std::basic_ostream<String::traits::char_type, String::traits>& os, const String & str)
{
@ -249,26 +315,28 @@ namespace easy2d
{
const Ctype& ctype_fac = std::use_facet<Ctype>(is.getloc());
str.erase();
try
{
SizeType size = (0 < is.width() && static_cast<SizeType>(is.width()) < str.max_size())
? static_cast<SizeType>(is.width()) : str.max_size();
typename String::traits::int_type meta = is.rdbuf()->sgetc();
SizeType size = (0 < is.width() && static_cast<SizeType>(is.width()) < str.max_size()) ? static_cast<SizeType>(is.width()) : str.max_size();
String::traits::int_type meta = is.rdbuf()->sgetc();
for (; 0 < size; --size, meta = is.rdbuf()->snextc())
{
if (String::traits::eq_int_type(String::traits::eof(), meta))
{
state |= std::ios_base::eofbit;
break;
}
else if (ctype_fac.is(Ctype::space, String::traits::to_char_type(meta)))
{
break;
}
else
{
str.push_back(String::traits::to_char_type(meta));
changed = true;
}
}
}
catch (...)
{
@ -282,6 +350,116 @@ namespace easy2d
is.setstate(state);
return is;
}
//
// details of to_string functions
//
namespace __to_string_detail
{
template<typename _Ty>
inline String FloatingToString(const wchar_t *fmt, _Ty val);
template <typename _Ty>
inline String IntegralToString(const _Ty val);
}
inline String to_wstring(int val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(unsigned int val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(long val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(unsigned long val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(long long val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(unsigned long long val)
{
return (__to_string_detail::IntegralToString(val));
}
inline String to_wstring(float val)
{
return (__to_string_detail::FloatingToString(L"%f", val));
}
inline String to_wstring(double val)
{
return (__to_string_detail::FloatingToString(L"%f", val));
}
inline String to_wstring(long double val)
{
return (__to_string_detail::FloatingToString(L"%Lf", val));
}
template<typename ..._Args>
inline String format_wstring(const wchar_t* const fmt, _Args&&... args)
{
const auto len = static_cast<String::size_type>(::_scwprintf(fmt, std::forward<_Args&&>(args)...));
if (len)
{
String str(len, L'\0');
::swprintf_s(&str[0], len + 1, fmt, std::forward<_Args>(args)...);
return str;
}
return String{};
}
namespace __to_string_detail
{
template<typename _Ty>
inline String FloatingToString(const wchar_t *fmt, _Ty val)
{
static_assert(std::is_floating_point_v<_Ty>, "_Ty must be floating point");
return format_wstring(fmt, val);
}
template <typename _Ty>
inline String IntegralToString(const _Ty val)
{
static_assert(std::is_integral_v<_Ty>, "_Ty must be integral");
using _UTy = std::make_unsigned_t<_Ty>;
using _Elem = String::traits::char_type;
_Elem buffer[21];
_Elem* const buffer_end = std::end(buffer);
_Elem* next = buffer_end;
auto uval = static_cast<_UTy>(val);
if (val < 0)
uval = 0 - uval;
do
{
*--next = static_cast<_Elem>('0' + uval % 10);
uval /= 10;
} while (uval != 0);
if (val < 0)
*--next = static_cast<_Elem>('-');
return String(next, buffer_end);
}
}
}
namespace std