mirror of
https://github.com/RPCSX/rpcsx-ui.git
synced 2026-01-31 01:05:23 +01:00
avoid std::format usage
This commit is contained in:
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -33,10 +33,10 @@ jobs:
|
||||
arch: x64
|
||||
machine: ubuntu-latest
|
||||
|
||||
# - name: macOS arm64
|
||||
# platform: darwin
|
||||
# arch: arm64
|
||||
# machine: macos-15
|
||||
- name: macOS arm64
|
||||
platform: darwin
|
||||
arch: arm64
|
||||
machine: macos-15
|
||||
|
||||
|
||||
runs-on: ${{ matrix.machine }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "./sfo.hpp"
|
||||
#include <print>
|
||||
#include "rpcsx/ui/log.hpp"
|
||||
#include <rpcsx/ui/extension.hpp>
|
||||
#include <thread>
|
||||
|
||||
@@ -91,7 +91,7 @@ tryFetchGame(const std::filesystem::directory_entry &entry) {
|
||||
|
||||
auto data = sfo::load(paramSfoPath.string());
|
||||
if (data.errc != sfo::error::ok) {
|
||||
std::println(stderr, "{}: error {}", entry.path().string(), data.errc);
|
||||
elog("%s: error %d", entry.path().c_str(), data.errc);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "sfo.hpp"
|
||||
#include "rpcsx/ui/file.hpp"
|
||||
#include "rpcsx/ui/format.hpp"
|
||||
#include "rpcsx/ui/log.hpp"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@@ -81,7 +80,7 @@ std::uint32_t sfo::entry::size() const {
|
||||
return sizeof(std::uint32_t);
|
||||
}
|
||||
|
||||
fatal("sfo: invalid format ({})", m_format);
|
||||
fatal("sfo: invalid format (%d)", static_cast<int>(m_format));
|
||||
}
|
||||
|
||||
bool sfo::entry::is_valid() const {
|
||||
@@ -104,8 +103,11 @@ sfo::load_result_t sfo::load(ReadableByteStream stream,
|
||||
#define PSF_CHECK(cond, err) \
|
||||
if (!static_cast<bool>(cond)) { \
|
||||
if (true || err != error::stream) \
|
||||
elog("sfo: Error loading '{}': {}. {}", filename, err, \
|
||||
std::source_location::current()); \
|
||||
elog("sfo: Error loading '%s': %d. %s:%u:%u", \
|
||||
std::string(filename).c_str(), static_cast<int>(err), \
|
||||
std::source_location::current().file_name(), \
|
||||
std::source_location::current().line(), \
|
||||
std::source_location::current().column()); \
|
||||
result.sfo.clear(); \
|
||||
result.errc = err; \
|
||||
return result; \
|
||||
@@ -192,10 +194,10 @@ sfo::load_result_t sfo::load(ReadableByteStream stream,
|
||||
std::move(value)));
|
||||
} else {
|
||||
// Possibly unsupported format, entry ignored
|
||||
elog("sfo: Unknown entry format (key='{}', fmt={}, len=0x{:x}, "
|
||||
"max=0x{:x})",
|
||||
key, indices[i].param_fmt, indices[i].param_len,
|
||||
indices[i].param_max);
|
||||
elog("sfo: Unknown entry format (key='%s', fmt=%d, len=0x%x, "
|
||||
"max=0x%x)",
|
||||
std::string(key).c_str(), static_cast<int>(indices[i].param_fmt),
|
||||
indices[i].param_len, indices[i].param_max);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,11 +264,13 @@ bool sfo::check_registry(
|
||||
|
||||
if (!entry_ok) {
|
||||
if (value.type() == format::string) {
|
||||
elog("sfo: {}: Entry '{}' is invalid: string='{}'", src_loc, key,
|
||||
value.as_string());
|
||||
elog("sfo: %s:%u:%u: Entry '%s' is invalid: string='%s'",
|
||||
src_loc.file_name(), src_loc.line(), src_loc.column(), key.c_str(),
|
||||
value.as_string().c_str());
|
||||
} else {
|
||||
// TODO: Better logging of other types
|
||||
elog("sfo: {}: Entry {} is invalid", src_loc, key, value.as_string());
|
||||
elog("sfo: %s:%u:%u: Entry %s is invalid", src_loc.file_name(),
|
||||
src_loc.line(), src_loc.column(), key.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "rpcsx/ui/file.hpp"
|
||||
#include "rpcsx/ui/refl.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <source_location>
|
||||
@@ -155,102 +153,3 @@ constexpr bool is_cat_hdd(std::string_view cat) {
|
||||
return cat.size() == 2u && cat[1] != 'D' && cat != "DG" && cat != "MS";
|
||||
}
|
||||
} // namespace sfo
|
||||
|
||||
template <> struct std::formatter<sfo::format> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(sfo::format format,
|
||||
std::format_context &ctx) const {
|
||||
std::string_view name;
|
||||
switch (format) {
|
||||
case sfo::format::array:
|
||||
name = rpcsx::ui::getNameOf<sfo::format::array>();
|
||||
break;
|
||||
case sfo::format::string:
|
||||
name = rpcsx::ui::getNameOf<sfo::format::string>();
|
||||
break;
|
||||
case sfo::format::integer:
|
||||
name = rpcsx::ui::getNameOf<sfo::format::integer>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
std::format_to(ctx.out(), "({}){:#x}",
|
||||
rpcsx::ui::getNameOf<sfo::format>(),
|
||||
std::to_underlying(format));
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{}", name);
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct std::formatter<std::source_location> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(const std::source_location &location,
|
||||
std::format_context &ctx) const {
|
||||
std::format_to(ctx.out(), "{}:{}", location.file_name(), location.line());
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct std::formatter<sfo::registry> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(const sfo::registry ®istry,
|
||||
std::format_context &ctx) const {
|
||||
for (const auto &entry : registry) {
|
||||
if (entry.second.type() == sfo::format::array) {
|
||||
// Format them last
|
||||
continue;
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{}: ", entry.first);
|
||||
|
||||
const sfo::entry &data = entry.second;
|
||||
|
||||
if (data.type() == sfo::format::integer) {
|
||||
std::format_to(ctx.out(), "0x{:x}\n", data.as_integer());
|
||||
} else {
|
||||
std::format_to(ctx.out(), "\"{}\"\n", data.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &entry : registry) {
|
||||
if (entry.second.type() != sfo::format::array) {
|
||||
// Formatted before
|
||||
continue;
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{}: [", entry.first);
|
||||
|
||||
for (bool first = true; auto byte : std::span<const std::uint8_t>(
|
||||
reinterpret_cast<const std::uint8_t *>(
|
||||
entry.second.as_string().data()),
|
||||
entry.second.size())) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
std::format_to(ctx.out(), ", ");
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{:x}", byte);
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "]\n");
|
||||
}
|
||||
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Protocol.hpp" // IWYU pragma: export
|
||||
#include "format.hpp" // IWYU pragma: export
|
||||
#include "refl.hpp" // IWYU pragma: export
|
||||
#include <expected>
|
||||
#include <rpcsx-ui.hpp>
|
||||
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
#pragma once
|
||||
#include "refl.hpp"
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace rpcsx::ui {
|
||||
namespace detail {
|
||||
struct StructFieldInfo {
|
||||
std::size_t size = 0;
|
||||
std::size_t align = 0;
|
||||
std::size_t offset = 0;
|
||||
std::format_context::iterator (*format)(void *,
|
||||
std::format_context &ctx) = nullptr;
|
||||
std::string_view name;
|
||||
};
|
||||
|
||||
struct StructFieldQuery {
|
||||
StructFieldInfo info;
|
||||
|
||||
template <typename T> constexpr operator T() {
|
||||
info.size = sizeof(T);
|
||||
info.align = alignof(T);
|
||||
if constexpr (std::is_default_constructible_v<std::formatter<T>>) {
|
||||
info.format =
|
||||
[](void *object,
|
||||
std::format_context &ctx) -> std::format_context::iterator {
|
||||
std::formatter<T> formatter;
|
||||
return formatter.format(*static_cast<T *>(object), ctx);
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StructT, typename T>
|
||||
std::size_t getFieldOffset(T StructT::*ptr) {
|
||||
StructT queryStruct;
|
||||
return std::bit_cast<std::byte *>(&(queryStruct.*ptr)) -
|
||||
std::bit_cast<std::byte *>(&queryStruct);
|
||||
}
|
||||
|
||||
template <typename> struct StructRuntimeInfo {
|
||||
std::unordered_map<std::size_t, std::string_view> fieldInfo;
|
||||
|
||||
template <auto Field> void registerField() {
|
||||
fieldInfo[getFieldOffset(Field)] = getNameOf<Field>();
|
||||
}
|
||||
|
||||
std::string_view getFieldName(std::size_t offset) {
|
||||
if (auto it = fieldInfo.find(offset); it != fieldInfo.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
struct VariableRuntimeInfo {
|
||||
std::unordered_map<void *, std::string_view> infos;
|
||||
|
||||
std::string_view getVariableName(void *pointer) {
|
||||
if (auto it = infos.find(pointer); it != infos.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename> struct UnwrapFieldInfo;
|
||||
|
||||
template <typename T, typename StructT> struct UnwrapFieldInfo<T StructT::*> {
|
||||
using struct_type = StructT;
|
||||
using field_type = T;
|
||||
};
|
||||
|
||||
template <typename StructT> auto &getStructStorage() {
|
||||
static StructRuntimeInfo<StructT> structStorage;
|
||||
return structStorage;
|
||||
}
|
||||
|
||||
inline auto &getVariableStorage() {
|
||||
static VariableRuntimeInfo storage;
|
||||
return storage;
|
||||
}
|
||||
|
||||
template <typename StructT, std::size_t N = fieldCount<StructT>>
|
||||
constexpr auto getConstStructInfo() {
|
||||
auto genInfo =
|
||||
[]<std::size_t... I>(
|
||||
std::index_sequence<I...>) -> std::array<StructFieldInfo, N> {
|
||||
std::array<StructFieldQuery, N> queries;
|
||||
static_cast<void>(StructT{queries[I]...});
|
||||
|
||||
auto result = std::array<StructFieldInfo, N>{queries[I].info...};
|
||||
|
||||
std::size_t nextOffset = 0;
|
||||
for (auto &elem : result) {
|
||||
elem.offset = (nextOffset + (elem.align - 1)) & ~(elem.align - 1);
|
||||
nextOffset = elem.offset + elem.size;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return genInfo(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <typename StructT> constexpr auto getStructInfo() {
|
||||
auto structInfo = getConstStructInfo<StructT>();
|
||||
auto &runtimeInfo = getStructStorage<StructT>();
|
||||
for (auto &field : structInfo) {
|
||||
field.name = runtimeInfo.getFieldName(field.offset);
|
||||
}
|
||||
return structInfo;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <auto Field> void registerField() {
|
||||
using Info = detail::UnwrapFieldInfo<decltype(Field)>;
|
||||
auto &storage = detail::getStructStorage<typename Info::struct_type>();
|
||||
storage.template registerField<Field>();
|
||||
}
|
||||
|
||||
template <auto &&Variable> void registerVariable() {
|
||||
auto &storage = detail::getVariableStorage();
|
||||
storage.infos[&Variable] = getNameOf<Variable>();
|
||||
}
|
||||
} // namespace rpcsx::ui
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_standard_layout_v<T> && std::is_class_v<T> &&
|
||||
rpcsx::ui::fieldCount<T> > 0) &&
|
||||
(!requires(T value) { std::begin(value) != std::end(value); })
|
||||
struct std::formatter<T> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T &s, std::format_context &ctx) const {
|
||||
std::format_to(ctx.out(), "{}", rpcsx::ui::getNameOf<T>());
|
||||
std::format_to(ctx.out(), "{{");
|
||||
|
||||
auto structInfo = rpcsx::ui::detail::getStructInfo<T>();
|
||||
auto bytes = reinterpret_cast<std::byte *>(&s);
|
||||
for (std::size_t i = 0; i < rpcsx::ui::fieldCount<T>; ++i) {
|
||||
if (i != 0) {
|
||||
std::format_to(ctx.out(), ", ");
|
||||
}
|
||||
|
||||
if (!structInfo[i].name.empty()) {
|
||||
std::format_to(ctx.out(), ".{} = ", structInfo[i].name);
|
||||
}
|
||||
|
||||
structInfo[i].format(bytes + structInfo[i].offset, ctx);
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "}}");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_enum_v<T> && rpcsx::ui::fieldCount<T> > 0)
|
||||
struct std::formatter<T> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T value,
|
||||
std::format_context &ctx) const {
|
||||
auto getFieldName =
|
||||
[]<std::size_t... I>(std::underlying_type_t<T> value,
|
||||
std::index_sequence<I...>) -> std::string {
|
||||
std::string_view result;
|
||||
((value == I ? ((result = rpcsx::ui::getNameOf<static_cast<T>(I)>()), 0)
|
||||
: 0),
|
||||
...);
|
||||
|
||||
if (!result.empty()) {
|
||||
return std::string(result);
|
||||
}
|
||||
|
||||
return std::format("{}", value);
|
||||
};
|
||||
|
||||
auto queryUnknownField =
|
||||
[]<std::int64_t Offset, std::int64_t... I>(
|
||||
std::underlying_type_t<T> value,
|
||||
std::integral_constant<std::int64_t, Offset>,
|
||||
std::integer_sequence<std::int64_t, I...>) -> std::string {
|
||||
std::string_view result;
|
||||
if (value < 0) {
|
||||
((-value == I + Offset
|
||||
? ((result =
|
||||
rpcsx::ui::getNameOf<static_cast<T>(-(I + Offset))>()),
|
||||
0)
|
||||
: 0),
|
||||
...);
|
||||
} else {
|
||||
((value == I + Offset
|
||||
? ((result = rpcsx::ui::getNameOf<static_cast<T>(I + Offset)>()),
|
||||
0)
|
||||
: 0),
|
||||
...);
|
||||
}
|
||||
|
||||
if (!result.empty()) {
|
||||
return std::string(result);
|
||||
}
|
||||
|
||||
return std::format("{}", value);
|
||||
};
|
||||
|
||||
std::string fieldName;
|
||||
|
||||
auto underlying = std::to_underlying(value);
|
||||
|
||||
if (underlying < 0) {
|
||||
fieldName = queryUnknownField(
|
||||
underlying, std::integral_constant<std::int64_t, 0>{},
|
||||
std::make_integer_sequence<std::int64_t, 128>{});
|
||||
} else if (underlying >= rpcsx::ui::fieldCount<T>) {
|
||||
fieldName = queryUnknownField(
|
||||
underlying,
|
||||
std::integral_constant<std::int64_t, rpcsx::ui::fieldCount<T>>{},
|
||||
std::make_integer_sequence<std::int64_t, 128>{});
|
||||
} else {
|
||||
fieldName = getFieldName(
|
||||
underlying, std::make_index_sequence<rpcsx::ui::fieldCount<T>>());
|
||||
}
|
||||
|
||||
if (fieldName[0] >= '0' && fieldName[0] <= '9') {
|
||||
std::format_to(ctx.out(), "({}){}", rpcsx::ui::getNameOf<T>(), fieldName);
|
||||
} else {
|
||||
std::format_to(ctx.out(), "{}::{}", rpcsx::ui::getNameOf<T>(), fieldName);
|
||||
}
|
||||
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires requires(T value) { std::begin(value) != std::end(value); }
|
||||
struct std::formatter<T> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T &s, std::format_context &ctx) const {
|
||||
std::format_to(ctx.out(), "[");
|
||||
|
||||
for (bool first = true; auto &elem : s) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
std::format_to(ctx.out(), ", ");
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{}", elem);
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "]");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires(!std::is_same_v<std::remove_cv_t<T>, char> &&
|
||||
!std::is_same_v<std::remove_cv_t<T>, wchar_t> &&
|
||||
!std::is_same_v<std::remove_cv_t<T>, char8_t> &&
|
||||
!std::is_same_v<std::remove_cv_t<T>, char16_t> &&
|
||||
!std::is_same_v<std::remove_cv_t<T>, char32_t> &&
|
||||
std::is_default_constructible_v<std::formatter<T>>)
|
||||
struct std::formatter<T *> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T *ptr, std::format_context &ctx) const {
|
||||
auto name = rpcsx::ui::detail::getVariableStorage().getVariableName(ptr);
|
||||
if (!name.empty()) {
|
||||
std::format_to(ctx.out(), "*{} = ", name);
|
||||
} else {
|
||||
std::format_to(ctx.out(), "*");
|
||||
}
|
||||
|
||||
if (ptr == nullptr) {
|
||||
std::format_to(ctx.out(), "nullptr");
|
||||
} else {
|
||||
std::format_to(ctx.out(), "{}:{}", static_cast<void *>(ptr), *ptr);
|
||||
}
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
#define RX_CONCAT(a, b) RX_CONCAT_IMPL(a, b)
|
||||
#define RX_CONCAT_IMPL(a, b) a##b
|
||||
|
||||
#define RX_REGISTER_VARIABLE(x) \
|
||||
static auto RX_CONCAT(_RX_REGISTER_VARIABLE_, __LINE__) = ([] { \
|
||||
::rpcsx::ui::registerVariable<x>(); \
|
||||
return true; \
|
||||
}())
|
||||
|
||||
#define RX_REGISTER_FIELD(x) \
|
||||
static auto RX_CONCAT(_RX_REGISTER_FIELD_, __LINE__) = ([] { \
|
||||
::rpcsx::ui::registerField<&x>(); \
|
||||
return true; \
|
||||
}())
|
||||
@@ -1,37 +1,75 @@
|
||||
#pragma once
|
||||
#include "Protocol.hpp"
|
||||
#include <format>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace rpcsx::ui {
|
||||
template <typename... Args>
|
||||
void log(LogLevel level, std::format_string<Args...> fmt, Args &&...args) {
|
||||
Protocol::getDefault()->sendLogMessage(
|
||||
level, std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
[[gnu::format(__printf__, 2, 3)]]
|
||||
inline void log(LogLevel level, const char *fmt, ...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
buffer[255] = 0;
|
||||
|
||||
Protocol::getDefault()->sendLogMessage(level, buffer);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void ilog(std::format_string<Args...> fmt, Args &&...args) {
|
||||
Protocol::getDefault()->sendLogMessage(
|
||||
LogLevel::Info, std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
[[gnu::format(__printf__, 1, 2)]]
|
||||
inline void ilog(const char *fmt, ...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
buffer[255] = 0;
|
||||
|
||||
Protocol::getDefault()->sendLogMessage(LogLevel::Info, buffer);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void elog(std::format_string<Args...> fmt, Args &&...args) {
|
||||
Protocol::getDefault()->sendLogMessage(
|
||||
LogLevel::Error, std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
[[gnu::format(__printf__, 1, 2)]]
|
||||
inline void elog(const char *fmt, ...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
buffer[255] = 0;
|
||||
|
||||
Protocol::getDefault()->sendLogMessage(LogLevel::Error, buffer);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void wlog(std::format_string<Args...> fmt, Args &&...args) {
|
||||
Protocol::getDefault()->sendLogMessage(
|
||||
LogLevel::Warning,
|
||||
std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
[[gnu::format(__printf__, 1, 2)]] inline void wlog(const char *fmt, ...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
buffer[255] = 0;
|
||||
|
||||
Protocol::getDefault()->sendLogMessage(LogLevel::Warning, buffer);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
[[noreturn]] void fatal(std::format_string<Args...> fmt, Args &&...args) {
|
||||
Protocol::getDefault()->sendLogMessage(
|
||||
LogLevel::Fatal, std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
[[gnu::format(__printf__, 1, 2), noreturn]] inline void fatal(const char *fmt,
|
||||
...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
buffer[255] = 0;
|
||||
|
||||
Protocol::getDefault()->sendLogMessage(LogLevel::Fatal, buffer);
|
||||
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define RX_PRETTY_FUNCTION __FUNCSIG__
|
||||
#elif defined(__GNUC__)
|
||||
#define RX_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define RX_PRETTY_FUNCTION ""
|
||||
#endif
|
||||
|
||||
namespace rpcsx::ui {
|
||||
namespace detail {
|
||||
struct AnyStructFieldQuery {
|
||||
template <typename T> constexpr operator T &&();
|
||||
};
|
||||
|
||||
template <typename StructT, std::size_t N = 1, std::size_t LastValidCount = 0>
|
||||
requires std::is_class_v<StructT>
|
||||
constexpr auto calcFieldCount() {
|
||||
|
||||
auto isValidFieldCount = []<std::size_t... I>(std::index_sequence<I...>) {
|
||||
return requires { StructT(((I, AnyStructFieldQuery{}))...); };
|
||||
};
|
||||
|
||||
if constexpr (isValidFieldCount(std::make_index_sequence<N>())) {
|
||||
return calcFieldCount<StructT, N + 1, N>();
|
||||
} else if constexpr (sizeof(StructT) <= N || LastValidCount > 0) {
|
||||
return LastValidCount;
|
||||
} else {
|
||||
return calcFieldCount<StructT, N + 1, LastValidCount>();
|
||||
}
|
||||
}
|
||||
|
||||
consteval std::string_view unwrapName(std::string_view prefix,
|
||||
std::string_view pretty,
|
||||
bool dropNamespace) {
|
||||
#ifdef _MSC_VER
|
||||
if (auto pos = pretty.find(prefix); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + prefix.size());
|
||||
} else {
|
||||
pretty = {};
|
||||
}
|
||||
|
||||
if (auto pos = pretty.rfind('>'); pos != std::string_view::npos) {
|
||||
pretty.remove_suffix(pretty.size() - pos);
|
||||
} else {
|
||||
pretty = {};
|
||||
}
|
||||
|
||||
if (auto pos = pretty.rfind(')'); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + 1);
|
||||
}
|
||||
|
||||
if (auto pos = pretty.find(' '); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + 1);
|
||||
}
|
||||
#else
|
||||
if (auto pos = pretty.rfind('['); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + 1);
|
||||
} else {
|
||||
pretty = {};
|
||||
}
|
||||
|
||||
if (auto pos = pretty.rfind(prefix); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + prefix.size());
|
||||
} else {
|
||||
pretty = {};
|
||||
}
|
||||
if (auto pos = pretty.rfind(')'); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + 1);
|
||||
}
|
||||
if (pretty.ends_with(']')) {
|
||||
pretty.remove_suffix(1);
|
||||
} else {
|
||||
pretty = {};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dropNamespace) {
|
||||
if (auto pos = pretty.rfind(':'); pos != std::string_view::npos) {
|
||||
pretty.remove_prefix(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
template <typename> constexpr bool isField = false;
|
||||
|
||||
template <typename BaseT, typename TypeT>
|
||||
constexpr bool isField<TypeT(BaseT::*)> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <auto &&V> consteval auto getNameOf() {
|
||||
std::string_view prefix;
|
||||
#ifdef _MSC_VER
|
||||
prefix = "getNameOf<";
|
||||
#else
|
||||
prefix = "V = ";
|
||||
#endif
|
||||
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
|
||||
}
|
||||
|
||||
template <auto V>
|
||||
requires(detail::isField<decltype(V)> ||
|
||||
std::is_enum_v<std::remove_cvref_t<decltype(V)>> ||
|
||||
std::is_pointer_v<std::remove_cvref_t<decltype(V)>>)
|
||||
consteval auto getNameOf() {
|
||||
std::string_view prefix;
|
||||
#ifdef _MSC_VER
|
||||
prefix = "getNameOf<";
|
||||
#else
|
||||
prefix = "V = ";
|
||||
#endif
|
||||
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
|
||||
}
|
||||
|
||||
template <typename T> consteval auto getNameOf() {
|
||||
std::string_view prefix;
|
||||
#ifdef _MSC_VER
|
||||
prefix = "getNameOf<";
|
||||
#else
|
||||
prefix = "T = ";
|
||||
#endif
|
||||
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, false);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename EnumT, std::size_t N = 0>
|
||||
requires std::is_enum_v<EnumT>
|
||||
constexpr auto calcFieldCount() {
|
||||
if constexpr (requires { EnumT::Count; }) {
|
||||
return static_cast<std::size_t>(EnumT::Count);
|
||||
} else if constexpr (requires { EnumT::_count; }) {
|
||||
return static_cast<std::size_t>(EnumT::_count);
|
||||
} else if constexpr (requires { EnumT::count; }) {
|
||||
return static_cast<std::size_t>(EnumT::count);
|
||||
} else if constexpr (!requires { getNameOf<EnumT(N)>()[0]; }) {
|
||||
return N;
|
||||
} else {
|
||||
constexpr auto c = getNameOf<EnumT(N)>()[0];
|
||||
if constexpr (!requires { getNameOf<EnumT(N)>()[0]; }) {
|
||||
return N;
|
||||
} else if constexpr (c >= '0' && c <= '9') {
|
||||
return N;
|
||||
} else {
|
||||
return calcFieldCount<EnumT, N + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename StructT>
|
||||
inline constexpr std::size_t fieldCount = detail::calcFieldCount<StructT>();
|
||||
} // namespace rpcsx::ui
|
||||
Reference in New Issue
Block a user