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

View File

@ -21,6 +21,8 @@
#pragma once #pragma once
#include "../macros.h" #include "../macros.h"
#include <string> #include <string>
#include <cstring>
#include <cstdio>
namespace easy2d namespace easy2d
{ {
@ -39,18 +41,22 @@ namespace easy2d
using const_reference = const value_type &; using const_reference = const value_type &;
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using traits = std::char_traits<wchar_t>; using traits = std::char_traits<value_type>;
using allocator = std::allocator<wchar_t>; using allocator = std::allocator<value_type>;
String(); String();
String(const wchar_t* cstr, bool const_str = true); String(const wchar_t* cstr, bool const_str = true);
String(const wchar_t* cstr, size_type count); String(const wchar_t* cstr, size_type count);
String(size_type count, wchar_t ch);
String(std::wstring const& str); String(std::wstring const& str);
String(String const& rhs); String(String const& rhs);
String(String const& rhs, size_type pos, size_type count = npos); String(String const& rhs, size_type pos, size_type count = npos);
String(String && rhs); String(String && rhs);
~String(); ~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 const wchar_t* c_str() const { return const_str_ ? const_str_ : L""; }
inline wchar_t at(size_t i) const { return (*this)[i]; } inline wchar_t at(size_t i) const { return (*this)[i]; }
inline size_type size() const { return size_; } inline size_type size() const { return size_; }
@ -58,10 +64,10 @@ namespace easy2d
inline size_type capacity() const { return capacity_; } inline size_type capacity() const { return capacity_; }
inline size_type max_size() const { return (static_cast<size_type>(-1) / sizeof(value_type)); } inline size_type max_size() const { return (static_cast<size_type>(-1) / sizeof(value_type)); }
inline bool empty() const { return size_ == 0; } 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); 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; int compare(const wchar_t* const str) const;
inline int compare(String const& str) const { return compare(str.c_str()); } 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) { 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; } 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); 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 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; } 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 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 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::string to_string() const;
std::wstring to_wstring() 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]; } inline const_reference back() const { if (empty()) throw std::out_of_range("back() called on empty string"); return const_str_[size_ - 1]; }
public: 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) 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]; } 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 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 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!=(String const& rhs) { return compare(rhs) != 0; }
inline bool operator!=(const wchar_t* cstr) { return compare(cstr) != 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"); } 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); } 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: private:
union 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 // operator+ for String
// //
@ -229,6 +264,37 @@ namespace easy2d
// operator<<>> for String // 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>& inline std::basic_ostream<String::traits::char_type, String::traits>&
operator<<(std::basic_ostream<String::traits::char_type, String::traits>& os, const String & str) operator<<(std::basic_ostream<String::traits::char_type, String::traits>& os, const String & str)
{ {
@ -249,27 +315,29 @@ namespace easy2d
{ {
const Ctype& ctype_fac = std::use_facet<Ctype>(is.getloc()); const Ctype& ctype_fac = std::use_facet<Ctype>(is.getloc());
str.erase(); str.erase();
try try
{ {
SizeType size = (0 < is.width() && static_cast<SizeType>(is.width()) < str.max_size()) SizeType size = (0 < is.width() && static_cast<SizeType>(is.width()) < str.max_size()) ? static_cast<SizeType>(is.width()) : str.max_size();
? static_cast<SizeType>(is.width()) : str.max_size(); String::traits::int_type meta = is.rdbuf()->sgetc();
typename String::traits::int_type meta = is.rdbuf()->sgetc();
for (; 0 < size; --size, meta = is.rdbuf()->snextc()) for (; 0 < size; --size, meta = is.rdbuf()->snextc())
{
if (String::traits::eq_int_type(String::traits::eof(), meta)) if (String::traits::eq_int_type(String::traits::eof(), meta))
{ {
state |= std::ios_base::eofbit; state |= std::ios_base::eofbit;
break; break;
} }
else if (ctype_fac.is(Ctype::space, String::traits::to_char_type(meta))) else if (ctype_fac.is(Ctype::space, String::traits::to_char_type(meta)))
{
break; break;
}
else else
{ {
str.push_back(String::traits::to_char_type(meta)); str.push_back(String::traits::to_char_type(meta));
changed = true; changed = true;
} }
} }
}
catch (...) catch (...)
{ {
is.setstate(std::ios_base::badbit, true); is.setstate(std::ios_base::badbit, true);
@ -282,6 +350,116 @@ namespace easy2d
is.setstate(state); is.setstate(state);
return is; 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 namespace std