mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-06 23:15:18 +00:00
temporary make std::print and std::format optional
This commit is contained in:
parent
d2b9b7c1f6
commit
5904079a87
26 changed files with 231 additions and 130 deletions
59
rx/include/rx/format-base.hpp
Normal file
59
rx/include/rx/format-base.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __has_include
|
||||
#define __has_include(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_include(<print>)
|
||||
#include <format>
|
||||
|
||||
namespace rx {
|
||||
using std::format;
|
||||
using std::format_args;
|
||||
using std::format_context;
|
||||
using std::format_parse_context;
|
||||
using std::format_string;
|
||||
using std::format_to;
|
||||
using std::format_to_n;
|
||||
using std::formatter;
|
||||
using std::make_format_args;
|
||||
using std::vformat;
|
||||
using std::vformat_to;
|
||||
} // namespace rx
|
||||
#else
|
||||
#include <fmt/format.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rx {
|
||||
using fmt::format;
|
||||
using fmt::format_args;
|
||||
using fmt::format_context;
|
||||
using fmt::format_parse_context;
|
||||
|
||||
namespace detail {
|
||||
template <typename... Args>
|
||||
struct format_string_impl : fmt::format_string<Args...> {
|
||||
using fmt::format_string<Args...>::format_string;
|
||||
|
||||
constexpr std::string_view get() const noexcept {
|
||||
return std::string_view(this->str);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using format_string = std::type_identity_t<detail::format_string_impl<Args...>>;
|
||||
|
||||
template <typename... Args>
|
||||
auto make_format_args(const Args &...args)
|
||||
-> decltype(fmt::make_format_args(const_cast<Args &>(args)...)) {
|
||||
return fmt::make_format_args(const_cast<Args &>(args)...);
|
||||
}
|
||||
|
||||
using fmt::format_to;
|
||||
using fmt::format_to_n;
|
||||
using fmt::formatter;
|
||||
using fmt::vformat;
|
||||
using fmt::vformat_to;
|
||||
} // namespace rx
|
||||
#endif
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include "format-base.hpp"
|
||||
#include "refl.hpp"
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <optional>
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
|
@ -14,8 +14,7 @@ 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;
|
||||
format_context::iterator (*format)(void *, format_context &ctx) = nullptr;
|
||||
std::string_view name;
|
||||
};
|
||||
|
||||
|
|
@ -25,11 +24,10 @@ struct StructFieldQuery {
|
|||
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;
|
||||
if constexpr (std::is_default_constructible_v<formatter<T>>) {
|
||||
info.format = [](void *object,
|
||||
format_context &ctx) -> format_context::iterator {
|
||||
formatter<T> formatter;
|
||||
return formatter.format(*static_cast<T *>(object), ctx);
|
||||
};
|
||||
}
|
||||
|
|
@ -132,51 +130,66 @@ template <auto &&Variable> void registerVariable() {
|
|||
auto &storage = detail::getVariableStorage();
|
||||
storage.infos[&Variable] = rx::getNameOf<Variable>();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename... Args>
|
||||
struct format_string_with_location_impl : format_string<Args...> {
|
||||
std::source_location location;
|
||||
|
||||
template <typename T>
|
||||
constexpr format_string_with_location_impl(
|
||||
T message,
|
||||
std::source_location location = std::source_location::current())
|
||||
: format_string<Args...>(message), location(location) {}
|
||||
};
|
||||
} // namespace detail
|
||||
template <typename... Args>
|
||||
using format_string_with_location =
|
||||
std::type_identity_t<detail::format_string_with_location_impl<Args...>>;
|
||||
} // namespace rx
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_standard_layout_v<T> && std::is_class_v<T> &&
|
||||
rx::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) {
|
||||
struct rx::formatter<T> {
|
||||
constexpr rx::format_parse_context::iterator
|
||||
parse(rx::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T &s, std::format_context &ctx) const {
|
||||
std::format_to(ctx.out(), "{}", rx::getNameOf<T>());
|
||||
std::format_to(ctx.out(), "{{");
|
||||
format_context::iterator format(T &s, rx::format_context &ctx) const {
|
||||
format_to(ctx.out(), "{}", rx::getNameOf<T>());
|
||||
format_to(ctx.out(), "{{");
|
||||
|
||||
auto structInfo = rx::detail::getStructInfo<T>();
|
||||
auto bytes = reinterpret_cast<std::byte *>(&s);
|
||||
for (std::size_t i = 0; i < rx::fieldCount<T>; ++i) {
|
||||
if (i != 0) {
|
||||
std::format_to(ctx.out(), ", ");
|
||||
format_to(ctx.out(), ", ");
|
||||
}
|
||||
|
||||
if (!structInfo[i].name.empty()) {
|
||||
std::format_to(ctx.out(), ".{} = ", structInfo[i].name);
|
||||
format_to(ctx.out(), ".{} = ", structInfo[i].name);
|
||||
}
|
||||
|
||||
structInfo[i].format(bytes + structInfo[i].offset, ctx);
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "}}");
|
||||
format_to(ctx.out(), "}}");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_enum_v<T> && rx::fieldCount<T> > 0)
|
||||
struct std::formatter<T> {
|
||||
constexpr std::format_parse_context::iterator
|
||||
parse(std::format_parse_context &ctx) {
|
||||
struct rx::formatter<T> {
|
||||
constexpr rx::format_parse_context::iterator
|
||||
parse(rx::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T value,
|
||||
std::format_context &ctx) const {
|
||||
rx::format_context::iterator format(T value, format_context &ctx) const {
|
||||
auto getFieldName =
|
||||
[]<std::size_t... I>(std::underlying_type_t<T> value,
|
||||
std::index_sequence<I...>) -> std::string {
|
||||
|
|
@ -188,7 +201,7 @@ struct std::formatter<T> {
|
|||
return std::string(result);
|
||||
}
|
||||
|
||||
return std::format("{}", value);
|
||||
return rx::format("{}", value);
|
||||
};
|
||||
|
||||
auto queryUnknownField =
|
||||
|
|
@ -208,16 +221,19 @@ struct std::formatter<T> {
|
|||
};
|
||||
|
||||
if (value < 0) {
|
||||
(queryIndex(std::integral_constant<std::int64_t, -(I + Offset)>{}, value), ...);
|
||||
(queryIndex(std::integral_constant<std::int64_t, -(I + Offset)>{},
|
||||
value),
|
||||
...);
|
||||
} else {
|
||||
(queryIndex(std::integral_constant<std::int64_t, I + Offset>{}, value), ...);
|
||||
(queryIndex(std::integral_constant<std::int64_t, I + Offset>{}, value),
|
||||
...);
|
||||
}
|
||||
|
||||
if (!result.empty()) {
|
||||
return std::string(result);
|
||||
}
|
||||
|
||||
return std::format("{}", value);
|
||||
return rx::format("{}", value);
|
||||
};
|
||||
|
||||
std::string fieldName;
|
||||
|
|
@ -240,9 +256,9 @@ struct std::formatter<T> {
|
|||
}
|
||||
|
||||
if (fieldName[0] >= '0' && fieldName[0] <= '9') {
|
||||
std::format_to(ctx.out(), "({}){}", rx::getNameOf<T>(), fieldName);
|
||||
rx::format_to(ctx.out(), "({}){}", rx::getNameOf<T>(), fieldName);
|
||||
} else {
|
||||
std::format_to(ctx.out(), "{}::{}", rx::getNameOf<T>(), fieldName);
|
||||
rx::format_to(ctx.out(), "{}::{}", rx::getNameOf<T>(), fieldName);
|
||||
}
|
||||
|
||||
return ctx.out();
|
||||
|
|
@ -251,26 +267,26 @@ struct std::formatter<T> {
|
|||
|
||||
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) {
|
||||
struct rx::formatter<T> {
|
||||
constexpr rx::format_parse_context::iterator
|
||||
parse(rx::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T &s, std::format_context &ctx) const {
|
||||
std::format_to(ctx.out(), "[");
|
||||
rx::format_context::iterator format(T &s, rx::format_context &ctx) const {
|
||||
rx::format_to(ctx.out(), "[");
|
||||
|
||||
for (bool first = true; auto &elem : s) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
std::format_to(ctx.out(), ", ");
|
||||
rx::format_to(ctx.out(), ", ");
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "{}", elem);
|
||||
rx::format_to(ctx.out(), "{}", elem);
|
||||
}
|
||||
|
||||
std::format_to(ctx.out(), "]");
|
||||
rx::format_to(ctx.out(), "]");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
|
@ -281,25 +297,25 @@ template <typename 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) {
|
||||
std::is_default_constructible_v<rx::formatter<T>>)
|
||||
struct rx::formatter<T *> {
|
||||
constexpr rx::format_parse_context::iterator
|
||||
parse(rx::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
std::format_context::iterator format(T *ptr, std::format_context &ctx) const {
|
||||
rx::format_context::iterator format(T *ptr, rx::format_context &ctx) const {
|
||||
auto name = rx::detail::getVariableStorage().getVariableName(ptr);
|
||||
if (!name.empty()) {
|
||||
std::format_to(ctx.out(), "*{} = ", name);
|
||||
rx::format_to(ctx.out(), "*{} = ", name);
|
||||
} else {
|
||||
std::format_to(ctx.out(), "*");
|
||||
rx::format_to(ctx.out(), "*");
|
||||
}
|
||||
|
||||
if (ptr == nullptr) {
|
||||
std::format_to(ctx.out(), "nullptr");
|
||||
rx::format_to(ctx.out(), "nullptr");
|
||||
} else {
|
||||
std::format_to(ctx.out(), "{}:{}", static_cast<void *>(ptr), *ptr);
|
||||
rx::format_to(ctx.out(), "{}:{}", static_cast<void *>(ptr), *ptr);
|
||||
}
|
||||
return ctx.out();
|
||||
}
|
||||
|
|
|
|||
32
rx/include/rx/print.hpp
Normal file
32
rx/include/rx/print.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __has_include
|
||||
#define __has_include(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_include(<print>)
|
||||
#include <print>
|
||||
namespace rx {
|
||||
using std::print;
|
||||
using std::println;
|
||||
using std::vprint_nonunicode;
|
||||
using std::vprint_unicode;
|
||||
} // namespace rx
|
||||
#else
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace rx {
|
||||
using fmt::print;
|
||||
using fmt::println;
|
||||
|
||||
inline void vprint_nonunicode(FILE *stream, std::string_view fmt,
|
||||
fmt::format_args args) {
|
||||
fmt::vprint(stream, fmt, args);
|
||||
}
|
||||
|
||||
inline void vprint_unicode(FILE *stream, std::string_view fmt,
|
||||
fmt::format_args args) {
|
||||
fmt::vprint(stream, fmt, args);
|
||||
}
|
||||
} // namespace rx
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue