1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00
rpcs3/Utilities/StrFmt.cpp

395 lines
8.6 KiB
C++
Raw Normal View History

2016-02-01 22:55:43 +01:00
#include "StrFmt.h"
#include "BEType.h"
#include "StrUtil.h"
#include "cfmt.h"
2016-05-13 16:01:48 +02:00
#include <algorithm>
2016-08-14 02:22:19 +02:00
#ifdef _WIN32
#include <Windows.h>
#else
#include <errno.h>
#endif
void fmt_class_string<const void*>::format(std::string& out, u64 arg)
2015-01-12 21:37:29 +01:00
{
2016-08-15 15:57:51 +02:00
if (arg)
{
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
}
else
{
out += "(NULL)";
}
2015-01-12 21:37:29 +01:00
}
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
2015-01-12 21:37:29 +01:00
{
2016-08-15 15:57:51 +02:00
if (arg)
{
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
}
else
{
out += "(NULL)";
}
2015-01-12 21:37:29 +01:00
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<std::string>::format(std::string& out, u64 arg)
{
out += get_object(arg).c_str(); // TODO?
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<std::vector<char>>::format(std::string& out, u64 arg)
{
const std::vector<char>& obj = get_object(arg);
out.append(obj.cbegin(), obj.cend());
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<char>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#hhx", static_cast<char>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<uchar>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#hhx", static_cast<uchar>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<schar>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#hhx", static_cast<schar>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<short>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#hx", static_cast<short>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<ushort>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#hx", static_cast<ushort>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<int>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#x", static_cast<int>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<uint>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#x", static_cast<uint>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<long>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#lx", static_cast<long>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<ulong>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#lx", static_cast<ulong>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<llong>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#llx", static_cast<llong>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<ullong>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
fmt::append(out, "%#llx", static_cast<ullong>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<float>::format(std::string& out, u64 arg)
{
2016-08-05 18:49:45 +02:00
fmt::append(out, "%gf", static_cast<float>(reinterpret_cast<f64&>(arg)));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<double>::format(std::string& out, u64 arg)
{
2016-08-05 18:49:45 +02:00
fmt::append(out, "%g", reinterpret_cast<f64&>(arg));
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<bool>::format(std::string& out, u64 arg)
{
2016-08-06 12:25:05 +02:00
out += arg ? "true" : "false";
}
2016-08-13 15:36:04 +02:00
template <>
void fmt_class_string<v128>::format(std::string& out, u64 arg)
{
const v128& vec = get_object(arg);
fmt::append(out, "0x%016llx%016llx", vec._u64[1], vec._u64[0]);
}
namespace fmt
{
void raw_error(const char* msg)
{
2016-08-14 02:22:19 +02:00
throw std::runtime_error{msg};
2016-08-13 15:36:04 +02:00
}
2016-08-15 12:18:47 +02:00
void raw_verify_error(const char* msg, const fmt_type_info* sup, u64 arg)
2016-08-13 15:36:04 +02:00
{
std::string out{"Verification failed"};
2016-08-14 02:22:19 +02:00
// Print error code (may be irrelevant)
#ifdef _WIN32
if (DWORD error = GetLastError())
{
2017-01-31 18:37:02 +01:00
fmt::append(out, " (e=%#x)", error);
2016-08-14 02:22:19 +02:00
}
#else
if (int error = errno)
{
2017-01-31 18:37:02 +01:00
fmt::append(out, " (e=%d)", error);
2016-08-14 02:22:19 +02:00
}
#endif
2016-08-15 12:18:47 +02:00
if (sup)
2016-08-13 15:36:04 +02:00
{
2016-08-15 12:18:47 +02:00
out += " (";
sup->fmt_string(out, arg); // Print value
2016-08-13 15:36:04 +02:00
out += ")";
}
2016-08-15 12:18:47 +02:00
if (msg)
{
out += ": ";
out += msg;
}
2016-08-13 15:36:04 +02:00
throw std::runtime_error{out};
}
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
{
2016-08-13 15:36:04 +02:00
std::string out{"Narrow error"};
2016-08-15 12:18:47 +02:00
if (sup)
{
out += " (";
sup->fmt_string(out, arg); // Print value
out += ")";
}
if (msg)
{
2016-08-15 12:18:47 +02:00
out += ": ";
out += msg;
}
2016-08-13 15:36:04 +02:00
throw std::range_error{out};
}
// Hidden template
2016-08-13 15:36:04 +02:00
template <typename T>
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
{
std::string out;
raw_append(out, fmt, sup, args);
throw T{out};
}
// Explicit instantiations (not exhaustive)
template void raw_throw_exception<std::runtime_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::logic_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::domain_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::invalid_argument>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::out_of_range>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::range_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::overflow_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::underflow_error>(const char*, const fmt_type_info*, const u64*);
struct cfmt_src;
}
// Temporary implementation
struct fmt::cfmt_src
{
2016-08-05 18:49:45 +02:00
const fmt_type_info* sup;
const u64* args;
2016-08-05 18:49:45 +02:00
bool test(std::size_t index) const
{
2016-08-05 18:49:45 +02:00
if (!sup[index].fmt_string)
{
2016-08-05 18:49:45 +02:00
return false;
}
return true;
}
2016-08-13 15:36:04 +02:00
template <typename T>
2016-08-05 18:49:45 +02:00
T get(std::size_t index) const
{
return reinterpret_cast<const T&>(args[index]);
}
void skip(std::size_t extra)
{
++sup += extra;
++args += extra;
}
2016-08-05 18:49:45 +02:00
std::size_t fmt_string(std::string& out, std::size_t extra) const
{
const std::size_t start = out.size();
2016-08-05 18:49:45 +02:00
sup[extra].fmt_string(out, args[extra]);
return out.size() - start;
}
2016-08-05 18:49:45 +02:00
2016-08-06 12:25:05 +02:00
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
2016-08-05 18:49:45 +02:00
std::size_t type(std::size_t extra) const
{
2016-08-13 15:36:04 +02:00
// Hack: use known function pointers to determine type
#define TYPE(type) \
if (sup[extra].fmt_string == &fmt_class_string<type>::format) return sizeof(type);
2016-08-05 18:49:45 +02:00
2016-08-06 12:25:05 +02:00
TYPE(int);
TYPE(llong);
2016-08-05 18:49:45 +02:00
TYPE(schar);
TYPE(short);
2016-08-06 12:25:05 +02:00
if (std::is_signed<char>::value) TYPE(char);
2016-08-05 18:49:45 +02:00
TYPE(long);
#undef TYPE
return 0;
}
};
2016-08-05 18:49:45 +02:00
void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
{
cfmt_append(out, fmt, cfmt_src{sup, args});
}
std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to)
{
auto pos = src.find(from);
if (pos == std::string::npos)
{
return src;
}
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
}
2016-08-13 15:36:04 +02:00
std::string fmt::replace_all(const std::string& src, const std::string& from, const std::string& to)
{
std::string target = src;
for (auto pos = target.find(from); pos != std::string::npos; pos = target.find(from, pos + 1))
{
target = (pos ? target.substr(0, pos) + to : to) + std::string(target.c_str() + pos + from.length());
pos += to.length();
}
return target;
}
2014-11-29 14:16:53 +01:00
std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
{
std::vector<std::string> result;
size_t cursor_begin = 0;
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
{
2016-08-13 15:36:04 +02:00
for (auto& separator : separators)
2014-11-29 14:16:53 +01:00
{
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
{
std::string candidate = source.substr(cursor_begin, cursor_end - cursor_begin);
if (!is_skip_empty || !candidate.empty())
result.push_back(candidate);
cursor_begin = cursor_end + separator.length();
2016-08-13 15:36:04 +02:00
cursor_end = cursor_begin - 1;
2014-11-29 14:16:53 +01:00
break;
}
}
}
if (cursor_begin != source.length())
{
result.push_back(source.substr(cursor_begin));
}
return std::move(result);
}
std::string fmt::trim(const std::string& source, const std::string& values)
{
std::size_t begin = source.find_first_not_of(values);
if (begin == source.npos)
2016-08-13 15:36:04 +02:00
return {};
return source.substr(begin, source.find_last_not_of(values) + 1);
}
std::string fmt::to_upper(const std::string& string)
2016-02-01 22:55:43 +01:00
{
std::string result;
result.resize(string.size());
std::transform(string.begin(), string.end(), result.begin(), ::toupper);
2016-02-01 22:55:43 +01:00
return result;
}
2016-08-13 15:36:04 +02:00
bool fmt::match(const std::string& source, const std::string& mask)
{
std::size_t source_position = 0, mask_position = 0;
for (; source_position < source.size() && mask_position < mask.size(); ++mask_position, ++source_position)
{
switch (mask[mask_position])
{
case '?': break;
case '*':
for (std::size_t test_source_position = source_position; test_source_position < source.size(); ++test_source_position)
{
if (match(source.substr(test_source_position), mask.substr(mask_position + 1)))
{
return true;
}
}
return false;
default:
if (source[source_position] != mask[mask_position])
{
return false;
}
break;
}
}
if (source_position != source.size())
return false;
if (mask_position != mask.size())
return false;
return true;
}