add to_wstring & format_wstring
This commit is contained in:
parent
be74b49196
commit
b0978251b8
|
|
@ -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);
|
|
||||||
|
|
||||||
traits::assign(str_, count, ch);
|
|
||||||
}
|
}
|
||||||
else
|
size_ = count;
|
||||||
{
|
|
||||||
capacity_ = size_ = count;
|
traits::assign(str_, count, ch);
|
||||||
traits::assign(str_, count, ch);
|
traits::assign(str_[size_], value_type());
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
traits::move(str_, cstr, size_);
|
|
||||||
}
|
}
|
||||||
else
|
size_ = count;
|
||||||
{
|
|
||||||
capacity_ = size_ = count;
|
traits::move(str_, cstr, size_);
|
||||||
traits::move(str_, cstr, size_);
|
traits::assign(str_[size_], value_type());
|
||||||
}
|
|
||||||
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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,26 +315,28 @@ 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 (...)
|
||||||
{
|
{
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue