mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-16 11:48:36 +12:00
Experimental template formatting with be_t<> support
This commit is contained in:
parent
ad2b2c9c62
commit
b6ec618f97
29 changed files with 577 additions and 86 deletions
|
@ -1,18 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
class wxString;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
namespace fmt{
|
||||
using std::string;
|
||||
using std::ostream;
|
||||
using std::ostringstream;
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
struct empty_t{};
|
||||
|
||||
extern const string placeholder;
|
||||
extern const std::string placeholder;
|
||||
|
||||
template <typename T>
|
||||
std::string AfterLast(const std::string& source, T searchstr)
|
||||
|
@ -51,11 +49,11 @@ namespace fmt{
|
|||
// `fmt::placeholder` after `pos` everything in `fmt` after pos is written
|
||||
// to `os`. Then `arg` is written to `os` after appending a space character
|
||||
template<typename T>
|
||||
empty_t write(const string &fmt, ostream &os, string::size_type &pos, T &&arg)
|
||||
empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg)
|
||||
{
|
||||
string::size_type ins = fmt.find(placeholder, pos);
|
||||
std::string::size_type ins = fmt.find(placeholder, pos);
|
||||
|
||||
if (ins == string::npos)
|
||||
if (ins == std::string::npos)
|
||||
{
|
||||
os.write(fmt.data() + pos, fmt.size() - pos);
|
||||
os << ' ' << arg;
|
||||
|
@ -77,10 +75,10 @@ namespace fmt{
|
|||
// inserted use `fmt::placeholder`. If there's not enough placeholders
|
||||
// the rest of the arguments are appended at the end, seperated by spaces
|
||||
template<typename ... Args>
|
||||
string SFormat(const string &fmt, Args&& ... parameters)
|
||||
std::string SFormat(const std::string &fmt, Args&& ... parameters)
|
||||
{
|
||||
ostringstream os;
|
||||
string::size_type pos = 0;
|
||||
std::ostringstream os;
|
||||
std::string::size_type pos = 0;
|
||||
std::initializer_list<empty_t> { write(fmt, os, pos, parameters)... };
|
||||
|
||||
if (!fmt.empty())
|
||||
|
@ -88,7 +86,7 @@ namespace fmt{
|
|||
os.write(fmt.data() + pos, fmt.size() - pos);
|
||||
}
|
||||
|
||||
string result = os.str();
|
||||
std::string result = os.str();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -98,10 +96,10 @@ namespace fmt{
|
|||
|
||||
//wrapper to deal with advance sprintf formating options with automatic length finding
|
||||
template<typename ... Args>
|
||||
string Format(const char* fmt, Args ... parameters)
|
||||
std::string Format(const char* fmt, Args ... parameters)
|
||||
{
|
||||
size_t length = 256;
|
||||
string str;
|
||||
std::string str;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -116,7 +114,7 @@ namespace fmt{
|
|||
#endif
|
||||
if (printlen < length)
|
||||
{
|
||||
str = string(buffptr.data(), printlen);
|
||||
str = std::string(buffptr.data(), printlen);
|
||||
break;
|
||||
}
|
||||
length *= 2;
|
||||
|
@ -175,13 +173,490 @@ namespace fmt{
|
|||
return src;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
static std::string to_hex(u64 value, size_t count = 1)
|
||||
{
|
||||
assert(count - 1 < 16);
|
||||
count = std::max<u64>(count, 16 - cntlz64(value) / 4);
|
||||
|
||||
char res[16] = {};
|
||||
|
||||
for (size_t i = count - 1; ~i; i--, value /= 16)
|
||||
{
|
||||
res[i] = "0123456789abcdef"[value % 16];
|
||||
}
|
||||
|
||||
return std::string(res, count);
|
||||
}
|
||||
|
||||
static size_t get_fmt_start(const char* fmt, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (fmt[i] == '%')
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t get_fmt_len(const char* fmt, size_t len)
|
||||
{
|
||||
assert(len >= 2 && fmt[0] == '%');
|
||||
|
||||
size_t res = 2;
|
||||
|
||||
if (fmt[1] == '.' || fmt[1] == '0')
|
||||
{
|
||||
assert(len >= 4 && fmt[2] - '1' < 9);
|
||||
res += 2;
|
||||
fmt += 2;
|
||||
len -= 2;
|
||||
|
||||
if (fmt[1] == '1')
|
||||
{
|
||||
assert(len >= 3 && fmt[2] - '0' < 7);
|
||||
res++;
|
||||
fmt++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt[1] == 'l')
|
||||
{
|
||||
assert(len >= 3);
|
||||
res++;
|
||||
fmt++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (fmt[1] == 'l')
|
||||
{
|
||||
assert(len >= 3);
|
||||
res++;
|
||||
fmt++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static size_t get_fmt_precision(const char* fmt, size_t len)
|
||||
{
|
||||
assert(len >= 2);
|
||||
|
||||
if (fmt[1] == '.' || fmt[1] == '0')
|
||||
{
|
||||
assert(len >= 4 && fmt[2] - '1' < 9);
|
||||
|
||||
if (fmt[2] == '1')
|
||||
{
|
||||
assert(len >= 5 && fmt[3] - '0' < 7);
|
||||
return 10 + fmt[3] - '0';
|
||||
}
|
||||
|
||||
return fmt[2] - '0';
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename T, bool is_enum = std::is_enum<T>::value>
|
||||
struct get_fmt
|
||||
{
|
||||
static_assert(is_enum, "Unsupported fmt::format argument");
|
||||
typedef typename std::underlying_type<T>::type underlying_type;
|
||||
|
||||
static std::string text(const char* fmt, size_t len, const T& arg)
|
||||
{
|
||||
return get_fmt<underlying_type>::text(fmt, len, (underlying_type)arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename T2>
|
||||
struct get_fmt<be_t<T, T2>, false>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, const be_t<T, T2>& arg)
|
||||
{
|
||||
return get_fmt<T>::text(fmt, len, arg.value());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<u8>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, u8 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string((u32)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (u8)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<u16>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, u16 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string((u32)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (u16)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<u32>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, u32 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (u32)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<u64>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, u64 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (u64)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<s8>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, s8 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u8)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string((s32)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (s8)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<s16>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, s16 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u16)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string((s32)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (s16)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<s32>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, s32 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u32)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (s32)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<s64>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, s64 arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u64)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (s64)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<float>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, float arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u32&)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'f')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (float)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<double>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, double arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex((u64&)arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'f')
|
||||
{
|
||||
return std::to_string(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (double)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<bool>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, bool arg)
|
||||
{
|
||||
if (fmt[len - 1] == 'x')
|
||||
{
|
||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
||||
}
|
||||
else if (fmt[len - 1] == 'd')
|
||||
{
|
||||
return arg ? "1" : "0";
|
||||
}
|
||||
else if (fmt[len - 1] == 's')
|
||||
{
|
||||
return arg ? "true" : "false";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (bool)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<char*>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, char* arg)
|
||||
{
|
||||
if (fmt[len - 1] == 's')
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (char*)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<const char*>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, const char* arg)
|
||||
{
|
||||
if (fmt[len - 1] == 's')
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (const char*)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t size>
|
||||
struct get_fmt<const char[size], false>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, const char(&arg)[size])
|
||||
{
|
||||
if (fmt[len - 1] == 's')
|
||||
{
|
||||
return std::string(arg, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (const char[size])";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_fmt<std::string>
|
||||
{
|
||||
static std::string text(const char* fmt, size_t len, const std::string& arg)
|
||||
{
|
||||
if (fmt[len - 1] == 's')
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Invalid formatting (std::string)";
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static std::string format(const char* fmt, size_t len, const T& arg, Args... args)
|
||||
{
|
||||
const size_t fmt_start = get_fmt_start(fmt, len);
|
||||
const size_t fmt_len = get_fmt_len(fmt + fmt_start, len - fmt_start);
|
||||
const size_t fmt_end = fmt_start + fmt_len;
|
||||
|
||||
return std::string(fmt, fmt_start) + get_fmt<T>::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...);
|
||||
}
|
||||
|
||||
static std::string format(const char* fmt, size_t len)
|
||||
{
|
||||
const size_t fmt_start = get_fmt_start(fmt, len);
|
||||
assert(fmt_start == len);
|
||||
|
||||
return std::string(fmt, len);
|
||||
}
|
||||
};
|
||||
|
||||
// formatting function with very limited functionality (compared to printf-like formatting) and be_t<> support
|
||||
/*
|
||||
Supported types:
|
||||
|
||||
u8, s8 (%x, %d)
|
||||
u16, s16 (%x, %d)
|
||||
u32, s32 (%x, %d)
|
||||
u64, s64 (%x, %d)
|
||||
float (%x, %f)
|
||||
double (%x, %f)
|
||||
bool (%x, %d, %s)
|
||||
char*, const char*, const char[N], std::string (%s)
|
||||
be_t<> of any appropriate type in this list
|
||||
|
||||
Supported formatting:
|
||||
%d - decimal; only basic std::to_string() functionality
|
||||
%x - hexadecimal; %.8x - hexadecimal with the precision (from .2 to .16)
|
||||
%s - string; generates "true" or "false" for bool
|
||||
%f - floating point; only basic std::to_string() functionality
|
||||
|
||||
Other features are not supported.
|
||||
*/
|
||||
template<typename... Args>
|
||||
__forceinline static std::string format(const char* fmt, Args... args)
|
||||
{
|
||||
return detail::format(fmt, strlen(fmt), args...);
|
||||
}
|
||||
|
||||
//convert a wxString to a std::string encoded in utf8
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
std::string ToUTF8(const wxString& right);
|
||||
|
||||
//convert a std::string encoded in utf8 to a wxString
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
wxString FromUTF8(const string& right);
|
||||
wxString FromUTF8(const std::string& right);
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue