更新
This commit is contained in:
+284
-302
@@ -1,319 +1,301 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include "magic_enum/include/magic_enum/magic_enum.hpp"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "remove_const.hpp"
|
||||
#include <sstream>
|
||||
#include "Core/Base/global_include.h"
|
||||
|
||||
|
||||
#include "magic_enum/include/magic_enum/magic_enum.hpp"
|
||||
#include "remove_const.hpp"
|
||||
namespace Psc {
|
||||
template<class T>
|
||||
class Copyable_Atomic {
|
||||
public:
|
||||
using value_type = T;
|
||||
Copyable_Atomic() = default;
|
||||
Copyable_Atomic(T value) : value_(value) {}
|
||||
Copyable_Atomic(const Copyable_Atomic& other) : value_(other.load()) {}
|
||||
Copyable_Atomic& operator=(const Copyable_Atomic& other) {
|
||||
store(other.load());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Copyable_Atomic& operator=(T value) {
|
||||
store(value);
|
||||
return *this;
|
||||
}
|
||||
T load(std::memory_order order = std::memory_order_seq_cst) const {
|
||||
return value_.load(order);
|
||||
}
|
||||
void store(T value, std::memory_order order = std::memory_order_seq_cst) {
|
||||
value_.store(value, order);
|
||||
}
|
||||
operator T() const {
|
||||
return load();
|
||||
}
|
||||
private:
|
||||
std::atomic<T> value_{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
namespace PV {
|
||||
template<typename T> struct is_copyable_atomic_helper : std::false_type {};
|
||||
template<typename U> struct is_copyable_atomic_helper<Copyable_Atomic<U>> : std::true_type {};
|
||||
template<typename T> struct is_copyable_atomic : is_copyable_atomic_helper<clean_t<T>> {};
|
||||
template<typename T> struct copyable_atomic_value;
|
||||
template<typename U> struct copyable_atomic_value<Copyable_Atomic<U>> {
|
||||
using type = U;
|
||||
};
|
||||
template <class T>
|
||||
class Copyable_Atomic {
|
||||
public:
|
||||
using value_type = T;
|
||||
Copyable_Atomic() = default;
|
||||
Copyable_Atomic(T value) : value_(value) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_copyable_atomic_v = PV::is_copyable_atomic<T>::value;
|
||||
|
||||
template<typename T>
|
||||
using copyable_atomic_value_t = typename PV::copyable_atomic_value<clean_t<T>>::type;
|
||||
|
||||
template<typename T> struct always_false : std::false_type {};
|
||||
template<typename T> using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
namespace PV {
|
||||
template<typename T> struct is_optional_helper : std::false_type {};
|
||||
template<typename U> struct is_optional_helper<std::optional<U>> : std::true_type {};
|
||||
template<typename T> struct is_optional : is_optional_helper<clean_t<T>> {};
|
||||
template<typename T> struct optional_value;
|
||||
template<typename U> struct optional_value<std::optional<U>> {
|
||||
using type = U;
|
||||
};
|
||||
Copyable_Atomic(const Copyable_Atomic& other) : value_(other.load()) {
|
||||
}
|
||||
template<typename T> constexpr bool is_optional_v = PV::is_optional<T>::value;
|
||||
template<typename T> using optional_value_t = typename PV::optional_value<clean_t<T>>::type;
|
||||
|
||||
namespace PV {
|
||||
template<typename T> struct is_atomic_helper : std::false_type {};
|
||||
template<typename U> struct is_atomic_helper<std::atomic<U>> : std::true_type {};
|
||||
template<typename T> struct is_atomic : is_atomic_helper<clean_t<T>> {};
|
||||
template<typename T> struct atomic_value;
|
||||
template<typename U> struct atomic_value<std::atomic<U>> {
|
||||
using type = U;
|
||||
};
|
||||
Copyable_Atomic& operator=(const Copyable_Atomic& other) {
|
||||
store(other.load());
|
||||
return *this;
|
||||
}
|
||||
template<typename T> constexpr bool is_atomic_v = PV::is_atomic<T>::value;
|
||||
template<typename T> using atomic_value_t = typename PV::atomic_value<clean_t<T>>::type;
|
||||
|
||||
|
||||
namespace PV {
|
||||
template<typename T> struct is_shared_ptr_helper : std::false_type {};
|
||||
template<typename U> struct is_shared_ptr_helper<std::shared_ptr<U>> : std::true_type {};
|
||||
template<typename T> struct is_shared_ptr : is_shared_ptr_helper<clean_t<T>> {};
|
||||
|
||||
template<typename T> struct shared_ptr_value;
|
||||
template<typename U> struct shared_ptr_value<std::shared_ptr<U>> { using type = U; };
|
||||
Copyable_Atomic& operator=(T value) {
|
||||
store(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> constexpr bool is_shared_ptr_v = PV::is_shared_ptr<T>::value;
|
||||
template<typename T> using shared_ptr_value_t = typename PV::shared_ptr_value<clean_t<T>>::type;
|
||||
|
||||
|
||||
// 泛型函数:将枚举类型和所有值转换为字符串,并返回
|
||||
template <typename EnumType>
|
||||
std::string get_enum_def_str() {
|
||||
std::string result;
|
||||
result += "enum " + std::string(magic_enum::enum_type_name<EnumType>());
|
||||
result += "{\n";
|
||||
for (auto e : magic_enum::enum_values<EnumType>()) {
|
||||
result += "\t";
|
||||
result += magic_enum::enum_name(e); // 获取枚举值的名字
|
||||
result += "\n";
|
||||
T load(std::memory_order order = std::memory_order_seq_cst) const {
|
||||
return value_.load(order);
|
||||
}
|
||||
void store(T value, std::memory_order order = std::memory_order_seq_cst) {
|
||||
value_.store(value, order);
|
||||
}
|
||||
operator T() const {
|
||||
return load();
|
||||
}
|
||||
private:
|
||||
std::atomic<T> value_{};
|
||||
};
|
||||
template <typename T>
|
||||
using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
namespace PV {
|
||||
template <typename T>
|
||||
struct is_copyable_atomic_helper : std::false_type {};
|
||||
template <typename U>
|
||||
struct is_copyable_atomic_helper<Copyable_Atomic<U>> : std::true_type {};
|
||||
template <typename T>
|
||||
struct is_copyable_atomic : is_copyable_atomic_helper<clean_t<T>> {};
|
||||
template <typename T>
|
||||
struct copyable_atomic_value;
|
||||
template <typename U>
|
||||
struct copyable_atomic_value<Copyable_Atomic<U>> {
|
||||
using type = U;
|
||||
};
|
||||
} // namespace PV
|
||||
template <typename T>
|
||||
constexpr bool is_copyable_atomic_v = PV::is_copyable_atomic<T>::value;
|
||||
template <typename T>
|
||||
using copyable_atomic_value_t = typename PV::copyable_atomic_value<clean_t<T>>::type;
|
||||
template <typename T>
|
||||
struct always_false : std::false_type {};
|
||||
template <typename T>
|
||||
using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
namespace PV {
|
||||
template <typename T>
|
||||
struct is_optional_helper : std::false_type {};
|
||||
template <typename U>
|
||||
struct is_optional_helper<std::optional<U>> : std::true_type {};
|
||||
template <typename T>
|
||||
struct is_optional : is_optional_helper<clean_t<T>> {};
|
||||
template <typename T>
|
||||
struct optional_value;
|
||||
template <typename U>
|
||||
struct optional_value<std::optional<U>> {
|
||||
using type = U;
|
||||
};
|
||||
} // namespace PV
|
||||
template <typename T>
|
||||
constexpr bool is_optional_v = PV::is_optional<T>::value;
|
||||
template <typename T>
|
||||
using optional_value_t = typename PV::optional_value<clean_t<T>>::type;
|
||||
namespace PV {
|
||||
template <typename T>
|
||||
struct is_atomic_helper : std::false_type {};
|
||||
template <typename U>
|
||||
struct is_atomic_helper<std::atomic<U>> : std::true_type {};
|
||||
template <typename T>
|
||||
struct is_atomic : is_atomic_helper<clean_t<T>> {};
|
||||
template <typename T>
|
||||
struct atomic_value;
|
||||
template <typename U>
|
||||
struct atomic_value<std::atomic<U>> {
|
||||
using type = U;
|
||||
};
|
||||
} // namespace PV
|
||||
template <typename T>
|
||||
constexpr bool is_atomic_v = PV::is_atomic<T>::value;
|
||||
template <typename T>
|
||||
using atomic_value_t = typename PV::atomic_value<clean_t<T>>::type;
|
||||
namespace PV {
|
||||
template <typename T>
|
||||
struct is_shared_ptr_helper : std::false_type {};
|
||||
template <typename U>
|
||||
struct is_shared_ptr_helper<std::shared_ptr<U>> : std::true_type {};
|
||||
template <typename T>
|
||||
struct is_shared_ptr : is_shared_ptr_helper<clean_t<T>> {};
|
||||
template <typename T>
|
||||
struct shared_ptr_value;
|
||||
template <typename U>
|
||||
struct shared_ptr_value<std::shared_ptr<U>> {
|
||||
using type = U;
|
||||
};
|
||||
} // namespace PV
|
||||
template <typename T>
|
||||
constexpr bool is_shared_ptr_v = PV::is_shared_ptr<T>::value;
|
||||
template <typename T>
|
||||
using shared_ptr_value_t = typename PV::shared_ptr_value<clean_t<T>>::type;
|
||||
// 泛型函数:将枚举类型和所有值转换为字符串,并返回
|
||||
template <typename EnumType>
|
||||
std::string get_enum_def_str() {
|
||||
std::string result;
|
||||
result += "enum " + std::string(magic_enum::enum_type_name<EnumType>());
|
||||
result += "{\n";
|
||||
for (auto e : magic_enum::enum_values<EnumType>()) {
|
||||
result += "\t";
|
||||
result += magic_enum::enum_name(e); // 获取枚举值的名字
|
||||
result += "\n";
|
||||
}
|
||||
result += "}\n";
|
||||
return result;
|
||||
}
|
||||
template <typename EnumType>
|
||||
EnumType to_enum(const std::string& str) {
|
||||
auto opt = magic_enum::enum_cast<EnumType>(str);
|
||||
if (opt.has_value()) {
|
||||
return opt.value(); // 返回枚举值
|
||||
}
|
||||
std::cerr << std::string(magic_enum::enum_type_name<EnumType>()) + " 字符串转换枚举值错误!str:[" + str + "]\n" +
|
||||
get_enum_def_str<EnumType>() + "\n";
|
||||
Psc::fail_fast("");
|
||||
return EnumType();
|
||||
}
|
||||
template <typename EnumType>
|
||||
std::optional<EnumType> to_enum2(const std::string& str) {
|
||||
auto opt = magic_enum::enum_cast<EnumType>(str);
|
||||
if (opt.has_value()) {
|
||||
return opt.value(); // 返回枚举值
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
// 其余未考虑到的类型直接实现 other_to_string(T) 就可以了。
|
||||
template <typename, typename = void>
|
||||
struct has_free_to_string : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_free_to_string<T, std::void_t<decltype(other_to_string(std::declval<T>()))>> : std::true_type {};
|
||||
template <typename, typename = void>
|
||||
struct has_member_to_string : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_member_to_string<T, std::void_t<decltype(std::declval<T>().to_string())>> : std::true_type {};
|
||||
template <typename T, typename decay = std::decay_t<T>,
|
||||
typename C = remove_recursive_top_const_t<remove_recursive_low_const_t<decay>>>
|
||||
std::string to_string(T&& v) {
|
||||
// 处理 std::string
|
||||
if constexpr (std::is_same_v<C, std::string>) {
|
||||
return std::forward<T>(v);
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, void*>) {
|
||||
std::stringstream ss;
|
||||
ss << "0x" << std::setw(sizeof(void*) * 2) << std::setfill('0') << std::hex
|
||||
<< reinterpret_cast<std::uintptr_t>(v);
|
||||
return ss.str();
|
||||
}
|
||||
// 处理 char* 类型
|
||||
else if constexpr (std::is_same_v<C, char*>) {
|
||||
return std::string(v);
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, const char*>) {
|
||||
return std::string(v);
|
||||
}
|
||||
// 处理 wchar_t* 类型
|
||||
else if constexpr (std::is_same_v<C, wchar_t*>) {
|
||||
std::wstring ws(v);
|
||||
return std::string(ws.begin(), ws.end()); // 简单转换为 std::string
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, const wchar_t*>) {
|
||||
std::wstring ws(v);
|
||||
return std::string(ws.begin(), ws.end()); // 简单转换为 std::string
|
||||
}
|
||||
// 处理 std::wstring 类型
|
||||
else if constexpr (std::is_same_v<C, std::wstring>) {
|
||||
return std::string(v.begin(), v.end()); // 将 std::wstring 转为 std::string
|
||||
}
|
||||
// 处理枚举类型
|
||||
else if constexpr (std::is_enum_v<C>) {
|
||||
return std::string(magic_enum::enum_name(v)); // 使用 magic_enum 转换枚举
|
||||
}
|
||||
// 处理 bool 类型
|
||||
else if constexpr (std::is_same_v<C, bool>) {
|
||||
return v ? std::string("true") : std::string("false"); // 对 bool 类型进行自定义转换
|
||||
}
|
||||
// 处理 std::nullptr_t 类型
|
||||
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
|
||||
return std::string("null"); // 对 nullptr 做特殊处理
|
||||
}
|
||||
// 处理算术类型(整数或浮点数)
|
||||
else if constexpr (std::is_arithmetic_v<C>) {
|
||||
return std::to_string(v); // 使用 std::to_string 转换数值类型
|
||||
}
|
||||
else if constexpr (is_atomic_v<C>) {
|
||||
return to_string(v.load());
|
||||
}
|
||||
else if constexpr (is_copyable_atomic_v<C>) {
|
||||
return to_string(v.load());
|
||||
}
|
||||
else if constexpr (is_optional_v<C>) {
|
||||
return v.has_value() ? to_string(v.value()) : "nullopt";
|
||||
}
|
||||
else if constexpr (is_shared_ptr_v<C>) {
|
||||
if (v) {
|
||||
return v->to_string();
|
||||
}
|
||||
result += "}\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename EnumType>
|
||||
EnumType to_enum(const std::string& str) {
|
||||
auto opt = magic_enum::enum_cast<EnumType>(str);
|
||||
if (opt.has_value()) {
|
||||
return opt.value(); // 返回枚举值
|
||||
else {
|
||||
return std::string("null");
|
||||
}
|
||||
std::cerr << std::string(magic_enum::enum_type_name<EnumType>()) +
|
||||
" 字符串转换枚举值错误!str:" + str + "\n" +
|
||||
get_enum_def_str<EnumType>()
|
||||
+ "\n";
|
||||
Psc::fail_fast("");
|
||||
|
||||
return EnumType();
|
||||
}
|
||||
|
||||
template <typename EnumType>
|
||||
std::optional<EnumType> to_enum2(const std::string& str) {
|
||||
auto opt = magic_enum::enum_cast<EnumType>(str);
|
||||
if (opt.has_value()) {
|
||||
return opt.value(); // 返回枚举值
|
||||
else {
|
||||
// 没有匹配上 最后走这条路径
|
||||
if constexpr (has_free_to_string<C>::value) {
|
||||
return other_to_string(v);
|
||||
}
|
||||
else if constexpr (has_member_to_string<C>::value) {
|
||||
return v.to_string();
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof(C) == 0, "Psc to_string not available for this type");
|
||||
}
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
template <typename EnumType>
|
||||
std::optional<EnumType> int_to_enum(int enum_value) {
|
||||
// 静态断言,确保 EnumType 是枚举类型
|
||||
static_assert(std::is_enum_v<EnumType>, "EnumType must be an enum type");
|
||||
// 使用 magic_enum 获取所有的枚举值
|
||||
auto enum_values = magic_enum::enum_values<EnumType>();
|
||||
// 检查是否存在匹配的枚举值
|
||||
for (auto value : enum_values) {
|
||||
if (static_cast<int>(value) == enum_value) {
|
||||
return value; // 返回匹配的枚举值
|
||||
}
|
||||
}
|
||||
// 如果没有匹配的枚举值,返回 std::nullopt
|
||||
return std::nullopt;
|
||||
}
|
||||
template <typename EnumType>
|
||||
std::optional<std::string> enum_int_to_string(int enum_value) {
|
||||
auto tmp = int_to_enum<EnumType>(enum_value);
|
||||
if (!tmp.has_value())
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 其余未考虑到的类型直接实现 other_to_string(T) 就可以了。
|
||||
template<typename, typename = void>
|
||||
struct has_free_to_string : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct has_free_to_string<T,
|
||||
std::void_t<decltype(other_to_string(std::declval<T>()))>
|
||||
> : std::true_type {};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_member_to_string : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct has_member_to_string<T,
|
||||
std::void_t<decltype(std::declval<T>().to_string())>
|
||||
> : std::true_type {};
|
||||
|
||||
|
||||
template <typename T,
|
||||
typename decay = std::decay_t<T>,
|
||||
typename C = remove_recursive_top_const_t<remove_recursive_low_const_t<decay>>
|
||||
>
|
||||
std::string to_string(T&& v) {
|
||||
// 处理 std::string
|
||||
if constexpr (std::is_same_v<C, std::string>) {
|
||||
return std::forward<T>(v);
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, void*>) {
|
||||
std::stringstream ss;
|
||||
ss << "0x" << std::setw(sizeof(void*) * 2) << std::setfill('0') << std::hex << reinterpret_cast<std::uintptr_t>(v);
|
||||
return ss.str();
|
||||
}
|
||||
// 处理 char* 类型
|
||||
else if constexpr (std::is_same_v<C, char*>) {
|
||||
return std::string(v);
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, const char*>) {
|
||||
return std::string(v);
|
||||
}
|
||||
// 处理 wchar_t* 类型
|
||||
else if constexpr (std::is_same_v<C, wchar_t*>) {
|
||||
std::wstring ws(v);
|
||||
return std::string(ws.begin(), ws.end()); // 简单转换为 std::string
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, const wchar_t*>) {
|
||||
std::wstring ws(v);
|
||||
return std::string(ws.begin(), ws.end()); // 简单转换为 std::string
|
||||
}
|
||||
// 处理 std::wstring 类型
|
||||
else if constexpr (std::is_same_v<C, std::wstring>) {
|
||||
return std::string(v.begin(), v.end()); // 将 std::wstring 转为 std::string
|
||||
}
|
||||
// 处理枚举类型
|
||||
else if constexpr (std::is_enum_v<C>) {
|
||||
return std::string(magic_enum::enum_name(v)); // 使用 magic_enum 转换枚举
|
||||
}
|
||||
// 处理 bool 类型
|
||||
else if constexpr (std::is_same_v<C, bool>) {
|
||||
return v ? std::string("true") : std::string("false"); // 对 bool 类型进行自定义转换
|
||||
}
|
||||
// 处理 std::nullptr_t 类型
|
||||
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
|
||||
return std::string("null"); // 对 nullptr 做特殊处理
|
||||
}
|
||||
// 处理算术类型(整数或浮点数)
|
||||
else if constexpr (std::is_arithmetic_v<C>) {
|
||||
return std::to_string(v); // 使用 std::to_string 转换数值类型
|
||||
}
|
||||
else if constexpr (is_atomic_v<C>) {
|
||||
return to_string(v.load());
|
||||
}
|
||||
else if constexpr (is_copyable_atomic_v<C>) {
|
||||
return to_string(v.load());
|
||||
}
|
||||
else if constexpr (is_optional_v<C>) {
|
||||
return v.has_value() ? to_string(v.value()) : "nullopt";
|
||||
}
|
||||
else if constexpr (is_shared_ptr_v<C>) {
|
||||
if (v) {
|
||||
return v->to_string();
|
||||
} else {
|
||||
return std::string("null");
|
||||
}
|
||||
} else {
|
||||
// 没有匹配上 最后走这条路径
|
||||
if constexpr (has_free_to_string<C>::value) {
|
||||
return other_to_string(v);
|
||||
}
|
||||
else if constexpr (has_member_to_string<C>::value) {
|
||||
return v.to_string();
|
||||
} else {
|
||||
static_assert(sizeof(C) == 0, "Psc to_string not available for this type");
|
||||
}
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename EnumType>
|
||||
std::optional<EnumType> int_to_enum(int enum_value) {
|
||||
// 静态断言,确保 EnumType 是枚举类型
|
||||
static_assert(std::is_enum_v<EnumType>, "EnumType must be an enum type");
|
||||
// 使用 magic_enum 获取所有的枚举值
|
||||
auto enum_values = magic_enum::enum_values<EnumType>();
|
||||
// 检查是否存在匹配的枚举值
|
||||
for (auto value : enum_values) {
|
||||
if (static_cast<int>(value) == enum_value) {
|
||||
return value; // 返回匹配的枚举值
|
||||
}
|
||||
}
|
||||
// 如果没有匹配的枚举值,返回 std::nullopt
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename EnumType>
|
||||
std::optional<std::string> enum_int_to_string(int enum_value) {
|
||||
auto tmp = int_to_enum<EnumType>(enum_value);
|
||||
if (!tmp.has_value()) return std::nullopt;
|
||||
return to_string(tmp.value());
|
||||
}
|
||||
|
||||
template <typename Enum>
|
||||
std::vector<Enum> split_flags(Enum flags)
|
||||
{
|
||||
static_assert(std::is_enum_v<Enum>, "Template parameter must be an enum type");
|
||||
std::vector<Enum> setFlags;
|
||||
for (auto flag : magic_enum::enum_values<Enum>())
|
||||
{
|
||||
if ((flags & flag) == flag)
|
||||
{
|
||||
setFlags.push_back(flag);
|
||||
}
|
||||
}
|
||||
return setFlags;
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
class enum_error_category : public std::error_category {
|
||||
static_assert(std::is_enum_v<E>, "E must be an enum");
|
||||
|
||||
public:
|
||||
const char* name() const noexcept override {
|
||||
// enum_type_name 返回 string_view,静态存储即可
|
||||
static constexpr auto name_sv = magic_enum::enum_type_name<E>();
|
||||
return name_sv.data();
|
||||
}
|
||||
|
||||
std::string message(int ev) const override {
|
||||
auto opt = magic_enum::enum_name(static_cast<E>(ev));
|
||||
if (!opt.empty())
|
||||
return std::string(opt);
|
||||
Psc::fail_fast_core_dump();
|
||||
return "unknown enum error";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
std::error_code make_ec(E e) {
|
||||
static_assert(std::is_enum_v<E>, "E must be an enum");
|
||||
static enum_error_category<E> cat;
|
||||
return {static_cast<int>(e), cat};
|
||||
}
|
||||
inline std::error_code get_sys_ec() {
|
||||
return std::error_code(get_error_code(), std::system_category());
|
||||
}
|
||||
|
||||
inline unexpected<std::error_code> get_sys_ex() {
|
||||
return unexpected<std::error_code>(get_sys_ec());
|
||||
return to_string(tmp.value());
|
||||
}
|
||||
template <typename Enum>
|
||||
std::vector<Enum> split_flags(Enum flags) {
|
||||
static_assert(std::is_enum_v<Enum>, "Template parameter must be an enum type");
|
||||
std::vector<Enum> setFlags;
|
||||
for (auto flag : magic_enum::enum_values<Enum>()) {
|
||||
if ((flags & flag) == flag) {
|
||||
setFlags.push_back(flag);
|
||||
}
|
||||
}
|
||||
return setFlags;
|
||||
}
|
||||
template <typename E>
|
||||
class enum_error_category : public std::error_category {
|
||||
static_assert(std::is_enum_v<E>, "E must be an enum");
|
||||
public:
|
||||
const char* name() const noexcept override {
|
||||
// enum_type_name 返回 string_view,静态存储即可
|
||||
static constexpr auto name_sv = magic_enum::enum_type_name<E>();
|
||||
return name_sv.data();
|
||||
}
|
||||
std::string message(int ev) const override {
|
||||
auto opt = magic_enum::enum_name(static_cast<E>(ev));
|
||||
if (!opt.empty())
|
||||
return std::string(opt);
|
||||
Psc::fail_fast_core_dump();
|
||||
return "unknown enum error";
|
||||
}
|
||||
};
|
||||
template <typename E>
|
||||
std::error_code make_ec(E e) {
|
||||
static_assert(std::is_enum_v<E>, "E must be an enum");
|
||||
static enum_error_category<E> cat;
|
||||
return {static_cast<int>(e), cat};
|
||||
}
|
||||
inline std::error_code get_sys_ec() {
|
||||
return std::error_code(get_error_code(), std::system_category());
|
||||
}
|
||||
inline unexpected<std::error_code> get_sys_ex() {
|
||||
return unexpected<std::error_code>(get_sys_ec());
|
||||
}
|
||||
} // namespace Psc
|
||||
|
||||
+94
-133
@@ -14,15 +14,15 @@
|
||||
#define PSC_JSON_FILE_PARAMS(M, SEP) M(std::string_view, file_name)
|
||||
#undef max
|
||||
#undef min
|
||||
#define Json_GET(type, name) \
|
||||
[[nodiscard]] type get_##name(std::string_view _key) const { \
|
||||
const Psc::JSON* that = get(_key); \
|
||||
if (!that) { \
|
||||
std::cout << "get" #type " error json not found! key:" << _key \
|
||||
<< " json: " << to_json_string() << std::endl; \
|
||||
return false; \
|
||||
} \
|
||||
return that->name##_val(); \
|
||||
#define Json_GET(type, name) \
|
||||
[[nodiscard]] type get_##name(std::string_view _key) const { \
|
||||
const Psc::JSON* that = get(_key); \
|
||||
if (!that) { \
|
||||
std::cout << "get" #type " error json not found! key:" << _key << " json: " << to_json_string() \
|
||||
<< std::endl; \
|
||||
return false; \
|
||||
} \
|
||||
return that->name##_val(); \
|
||||
}
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
@@ -35,39 +35,26 @@ class json_assign_error final : public std::system_error {
|
||||
public:
|
||||
using std::system_error::system_error;
|
||||
};
|
||||
enum JsonType : uint8_t { String,
|
||||
Object,
|
||||
Array,
|
||||
Null,
|
||||
Number,
|
||||
Bool };
|
||||
enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool };
|
||||
template <typename T>
|
||||
void assign_json(JsonType& rt, std::string& rv, T&& val);
|
||||
template <typename T_Number>
|
||||
bool to_number_ec(std::string_view val, T_Number& out,
|
||||
std::error_code& ec) noexcept;
|
||||
bool to_number_ec(std::string_view val, T_Number& out, std::error_code& ec) noexcept;
|
||||
template <typename T_Number>
|
||||
T_Number to_number(std::string_view val) {
|
||||
return detail::triple_api_throwing<T_Number>(
|
||||
[&val](T_Number& out, std::error_code& ec) {
|
||||
return to_number_ec(val, out, ec);
|
||||
},
|
||||
"to_number failed");
|
||||
[&val](T_Number& out, std::error_code& ec) { return to_number_ec(val, out, ec); }, "to_number failed");
|
||||
}
|
||||
template <typename T_Number>
|
||||
expected<T_Number, std::error_code> try_to_number(std::string_view val) noexcept {
|
||||
return detail::triple_api_expected<T_Number>(
|
||||
[&val](T_Number& out, std::error_code& ec) {
|
||||
return to_number_ec(val, out, ec);
|
||||
});
|
||||
[&val](T_Number& out, std::error_code& ec) { return to_number_ec(val, out, ec); });
|
||||
}
|
||||
template <typename T_Number>
|
||||
bool to_number_ec(std::string_view val, T_Number& out,
|
||||
std::error_code& ec) noexcept {
|
||||
bool to_number_ec(std::string_view val, T_Number& out, std::error_code& ec) noexcept {
|
||||
ec.clear();
|
||||
// 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全)
|
||||
static_assert(std::is_integral_v<T_Number> ||
|
||||
std::is_floating_point_v<T_Number>,
|
||||
static_assert(std::is_integral_v<T_Number> || std::is_floating_point_v<T_Number>,
|
||||
"to_number<T_Number>: T_Number must be an integral or "
|
||||
"floating-point type");
|
||||
try {
|
||||
@@ -77,8 +64,7 @@ bool to_number_ec(std::string_view val, T_Number& out,
|
||||
auto text = std::string(val);
|
||||
unsigned long long x = std::stoull(text);
|
||||
// 额外范围检查,避免静默截断
|
||||
if (x > static_cast<unsigned long long>(
|
||||
std::numeric_limits<T_Number>::max())) {
|
||||
if (x > static_cast<unsigned long long>(std::numeric_limits<T_Number>::max())) {
|
||||
ec = std::make_error_code(std::errc::result_out_of_range);
|
||||
return false;
|
||||
}
|
||||
@@ -123,35 +109,26 @@ bool to_number_ec(std::string_view val, T_Number& out,
|
||||
}
|
||||
class JSON {
|
||||
public:
|
||||
static std::function<void(const char*, std::string_view, const char*,
|
||||
int)>
|
||||
handle_error;
|
||||
static std::function<void(const char*, std::string_view, const char*, int)> handle_error;
|
||||
explicit operator std::string() const;
|
||||
friend std::ostream& operator<<(std::ostream& os, const JSON& obj);
|
||||
[[nodiscard]] bool has(std::string_view key) const;
|
||||
[[nodiscard]] const JSON* get(std::string_view key) const;
|
||||
PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string,
|
||||
PSC_JSON_KEY_PARAMS);
|
||||
PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string, PSC_JSON_KEY_PARAMS);
|
||||
PSC_DECLARE_TRIPLE_API_CONST_METHOD_0(bool, bool_val);
|
||||
PSC_DECLARE_TRIPLE_API_CONST_METHOD(bool, get_bool, PSC_JSON_KEY_PARAMS);
|
||||
template <typename T_Number>
|
||||
T_Number get_number(std::string_view key) const {
|
||||
return detail::triple_api_throwing<T_Number>(
|
||||
[this, &key](T_Number& out, std::error_code& ec) {
|
||||
return get_number_ec(key, out, ec);
|
||||
},
|
||||
"get_number failed");
|
||||
[this, &key](T_Number& out, std::error_code& ec) { return get_number_ec(key, out, ec); }, "get_number failed");
|
||||
}
|
||||
template <typename T_Number>
|
||||
expected<T_Number, std::error_code> try_get_number(std::string_view key) const noexcept {
|
||||
return detail::triple_api_expected<T_Number>(
|
||||
[this, &key](T_Number& out, std::error_code& ec) {
|
||||
return get_number_ec(key, out, ec);
|
||||
});
|
||||
[this, &key](T_Number& out, std::error_code& ec) { return get_number_ec(key, out, ec); });
|
||||
}
|
||||
template <typename T_Number>
|
||||
bool get_number_ec(std::string_view key, T_Number& out,
|
||||
std::error_code& ec) const noexcept {
|
||||
bool get_number_ec(std::string_view key, T_Number& out, std::error_code& ec) const noexcept {
|
||||
const JSON* that = get(key);
|
||||
if (!that) {
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
@@ -162,17 +139,12 @@ public:
|
||||
template <typename T_Number>
|
||||
T_Number number_val() const {
|
||||
return detail::triple_api_throwing<T_Number>(
|
||||
[this](T_Number& out, std::error_code& ec) {
|
||||
return number_val_ec(out, ec);
|
||||
},
|
||||
"number_val failed");
|
||||
[this](T_Number& out, std::error_code& ec) { return number_val_ec(out, ec); }, "number_val failed");
|
||||
}
|
||||
template <typename T_Number>
|
||||
expected<T_Number, std::error_code> try_number_val() const noexcept {
|
||||
return detail::triple_api_expected<T_Number>(
|
||||
[this](T_Number& out, std::error_code& ec) {
|
||||
return number_val_ec(out, ec);
|
||||
});
|
||||
[this](T_Number& out, std::error_code& ec) { return number_val_ec(out, ec); });
|
||||
}
|
||||
template <typename T_Number>
|
||||
bool number_val_ec(T_Number& out, std::error_code& ec) const noexcept {
|
||||
@@ -183,14 +155,12 @@ public:
|
||||
return to_number_ec(val, out, ec);
|
||||
}
|
||||
JSON(std::string_view key, const JSON& body);
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
|
||||
template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
|
||||
JSON(std::string_view k, T&& v) {
|
||||
key = std::string(k);
|
||||
assign_json(valueType, val, std::forward<T>(v));
|
||||
}
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
|
||||
template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
|
||||
JSON(T&& v) {
|
||||
assign_json(valueType, val, std::forward<T>(v));
|
||||
}
|
||||
@@ -211,18 +181,12 @@ public:
|
||||
JsonType valueType = Null;
|
||||
std::string key, val;
|
||||
std::vector<JSON> children;
|
||||
[[nodiscard]] std::string to_json_string(std::string_view object_split = "\n",
|
||||
std::string_view array_split = "\n",
|
||||
std::string_view indentStr = " ",
|
||||
const int& indent = 0) const;
|
||||
[[nodiscard]] std::string to_json_string(std::string_view object_split = "\n", std::string_view array_split = "\n",
|
||||
std::string_view indentStr = " ", const int& indent = 0) const;
|
||||
private:
|
||||
static std::string get_indent(const int& indent,
|
||||
std::string_view indentStr);
|
||||
void append_value_string(std::string& ret, const int& indent, bool isEnd,
|
||||
std::string_view object_split,
|
||||
std::string_view array_split,
|
||||
std::string_view indentStr,
|
||||
JsonType fatherType) const;
|
||||
static std::string get_indent(const int& indent, std::string_view indentStr);
|
||||
void append_value_string(std::string& ret, const int& indent, bool isEnd, std::string_view object_split,
|
||||
std::string_view array_split, std::string_view indentStr, JsonType fatherType) const;
|
||||
};
|
||||
PSC_DECLARE_TRIPLE_API(JSON, parse_json, PSC_JSON_PARSE_PARAMS);
|
||||
PSC_DECLARE_TRIPLE_API(JSON, parse_json_file, PSC_JSON_FILE_PARAMS);
|
||||
@@ -300,30 +264,22 @@ void assign_json(JsonType& rt, std::string& rv, T&& v) {
|
||||
rv = v.to_string();
|
||||
}
|
||||
}
|
||||
void check_json_assign_field(bool ok, const std::error_code& ec,
|
||||
const Psc::JSON* that_json, const char* name);
|
||||
void check_json_assign_field(bool ok, const std::error_code& ec, const Psc::JSON* that_json, const char* name);
|
||||
template <typename T>
|
||||
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name, std::error_code& ec) noexcept;
|
||||
template <typename T>
|
||||
void assign_field(T& field, const Psc::JSON* that_json, const char* name) {
|
||||
detail::triple_api_throwing_void(
|
||||
[&field, that_json, name](std::error_code& ec) {
|
||||
return assign_field_ec(field, that_json, name, ec);
|
||||
},
|
||||
[&field, that_json, name](std::error_code& ec) { return assign_field_ec(field, that_json, name, ec); },
|
||||
"assign_field failed");
|
||||
}
|
||||
template <typename T>
|
||||
expected<void, std::error_code> try_assign_field(T& field,
|
||||
const Psc::JSON* that_json,
|
||||
const char* name) noexcept {
|
||||
expected<void, std::error_code> try_assign_field(T& field, const Psc::JSON* that_json, const char* name) noexcept {
|
||||
return detail::triple_api_expected_void(
|
||||
[&field, that_json, name](std::error_code& ec) {
|
||||
return assign_field_ec(field, that_json, name, ec);
|
||||
});
|
||||
[&field, that_json, name](std::error_code& ec) { return assign_field_ec(field, that_json, name, ec); });
|
||||
}
|
||||
template <typename T>
|
||||
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name,
|
||||
std::error_code& ec) noexcept {
|
||||
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name, std::error_code& ec) noexcept {
|
||||
using C = clean_t<T>;
|
||||
if (that_json == nullptr) {
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
@@ -347,7 +303,13 @@ bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name,
|
||||
std::string value;
|
||||
if (!that_json->get_string_ec(name, value, ec))
|
||||
return false;
|
||||
field = Psc::to_enum<C>(value);
|
||||
std::optional<C> opt = magic_enum::enum_cast<C>(value);
|
||||
if (opt.has_value()) {
|
||||
field = opt.value();
|
||||
}
|
||||
else {
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
}
|
||||
else if constexpr (is_atomic_v<T>) {
|
||||
using V = atomic_value_t<T>;
|
||||
@@ -396,11 +358,17 @@ bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name,
|
||||
std::string text;
|
||||
if (!that_json->get_string_ec(name, text, ec))
|
||||
return false;
|
||||
value = Psc::to_enum<V>(text);
|
||||
// value = Psc::to_enum<V>(text);
|
||||
std::optional<V> opt = magic_enum::enum_cast<V>(text);
|
||||
if (opt.has_value()) {
|
||||
value = opt.value();
|
||||
}
|
||||
else {
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T),
|
||||
"assign_field does not support this optional type");
|
||||
static_assert(!sizeof(T), "assign_field does not support this optional type");
|
||||
}
|
||||
field = std::move(value);
|
||||
}
|
||||
@@ -481,16 +449,15 @@ void output_field(const T& field, Psc::JSON& ret, const char* name) {
|
||||
}
|
||||
} // namespace Psc
|
||||
#undef Json_GET
|
||||
#define Get_J_ex(NAME, FIELD) \
|
||||
{ \
|
||||
std::error_code ec_##FIELD; \
|
||||
const bool ok_##FIELD = \
|
||||
Psc::assign_field_ec(FIELD, that_json, NAME, ec_##FIELD); \
|
||||
Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, NAME); \
|
||||
#define Get_J_ex(NAME, FIELD) \
|
||||
{ \
|
||||
std::error_code ec_##FIELD; \
|
||||
const bool ok_##FIELD = Psc::assign_field_ec(FIELD, that_json, NAME, ec_##FIELD); \
|
||||
Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, NAME); \
|
||||
}
|
||||
#define Ret_J_ex(NAME, FIELD) \
|
||||
{ \
|
||||
Psc::output_field(FIELD, ret, NAME); \
|
||||
#define Ret_J_ex(NAME, FIELD) \
|
||||
{ \
|
||||
Psc::output_field(FIELD, ret, NAME); \
|
||||
}
|
||||
#define Get_J(FIELD) Get_J_ex(#FIELD, FIELD)
|
||||
#define Ret_J(FIELD) Ret_J_ex(#FIELD, FIELD)
|
||||
@@ -500,55 +467,49 @@ void output_field(const T& field, Psc::JSON& ret, const char* name) {
|
||||
#define JSON_KV_3(P1, P2, P3) JSON_KV_2(P1, P2), JSON_KV(P3)
|
||||
#define JSON_KV_4(P1, P2, P3, P4) JSON_KV_3(P1, P2, P3), JSON_KV(P4)
|
||||
#define JSON_KV_5(P1, P2, P3, P4, P5) JSON_KV_4(P1, P2, P3, P4), JSON_KV(P5)
|
||||
#define JSON_KV_6(P1, P2, P3, P4, P5, P6) \
|
||||
JSON_KV_5(P1, P2, P3, P4, P5), JSON_KV(P6)
|
||||
#define JSON_KV_7(P1, P2, P3, P4, P5, P6, P7) \
|
||||
JSON_KV_6(P1, P2, P3, P4, P5, P6), JSON_KV(P7)
|
||||
#define JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8) \
|
||||
JSON_KV_7(P1, P2, P3, P4, P5, P6, P7), JSON_KV(P8)
|
||||
#define JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \
|
||||
JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8), JSON_KV(P9)
|
||||
#define JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
|
||||
JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), JSON_KV(P10)
|
||||
#define JSON_KV_6(P1, P2, P3, P4, P5, P6) JSON_KV_5(P1, P2, P3, P4, P5), JSON_KV(P6)
|
||||
#define JSON_KV_7(P1, P2, P3, P4, P5, P6, P7) JSON_KV_6(P1, P2, P3, P4, P5, P6), JSON_KV(P7)
|
||||
#define JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8) JSON_KV_7(P1, P2, P3, P4, P5, P6, P7), JSON_KV(P8)
|
||||
#define JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8), JSON_KV(P9)
|
||||
#define JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), JSON_KV(P10)
|
||||
#define VAR_JSON_1(P1) Psc::JSON::object({JSON_KV_1(P1)})
|
||||
#define VAR_JSON_2(P1, P2) Psc::JSON::object({JSON_KV_2(P1, P2)})
|
||||
#define VAR_JSON_3(P1, P2, P3) Psc::JSON::object({JSON_KV_3(P1, P2, P3)})
|
||||
#define VAR_JSON_4(P1, P2, P3, P4) \
|
||||
Psc::JSON::object({JSON_KV_4(P1, P2, P3, P4)})
|
||||
#define VAR_JSON_5(P1, P2, P3, P4, P5) \
|
||||
Psc::JSON::object({JSON_KV_5(P1, P2, P3, P4, P5)})
|
||||
#define VAR_JSON_6(P1, P2, P3, P4, P5, P6) \
|
||||
Psc::JSON::object({JSON_KV_6(P1, P2, P3, P4, P5, P6)})
|
||||
#define VAR_JSON_7(P1, P2, P3, P4, P5, P6, P7) \
|
||||
Psc::JSON::object({JSON_KV_7(P1, P2, P3, P4, P5, P6, P7)})
|
||||
#define VAR_JSON_8(P1, P2, P3, P4, P5, P6, P7, P8) \
|
||||
Psc::JSON::object({JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8)})
|
||||
#define VAR_JSON_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \
|
||||
#define VAR_JSON_4(P1, P2, P3, P4) Psc::JSON::object({JSON_KV_4(P1, P2, P3, P4)})
|
||||
#define VAR_JSON_5(P1, P2, P3, P4, P5) Psc::JSON::object({JSON_KV_5(P1, P2, P3, P4, P5)})
|
||||
#define VAR_JSON_6(P1, P2, P3, P4, P5, P6) Psc::JSON::object({JSON_KV_6(P1, P2, P3, P4, P5, P6)})
|
||||
#define VAR_JSON_7(P1, P2, P3, P4, P5, P6, P7) Psc::JSON::object({JSON_KV_7(P1, P2, P3, P4, P5, P6, P7)})
|
||||
#define VAR_JSON_8(P1, P2, P3, P4, P5, P6, P7, P8) Psc::JSON::object({JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8)})
|
||||
#define VAR_JSON_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \
|
||||
Psc::JSON::object({JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9)})
|
||||
#define VAR_JSON_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
|
||||
#define VAR_JSON_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
|
||||
Psc::JSON::object({JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)})
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <string_view>
|
||||
#include "boost/pfr/core.hpp"
|
||||
#define PSC_TO_JSON \
|
||||
[[nodiscard]] Psc::JSON to_base_json() const { \
|
||||
Psc::JSON ret = Psc::JSON::object(); \
|
||||
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
|
||||
boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](const auto& field) mutable { \
|
||||
Psc::output_field(field, ret, names[i++].data()); \
|
||||
}); \
|
||||
return ret; \
|
||||
#define PSC_TO_JSON \
|
||||
[[nodiscard]] Psc::JSON to_base_json() const { \
|
||||
Psc::JSON ret = Psc::JSON::object(); \
|
||||
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
|
||||
boost::pfr::for_each_field( \
|
||||
*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](const auto& field) mutable { \
|
||||
Psc::output_field(field, ret, names[i++].data()); \
|
||||
}); \
|
||||
return ret; \
|
||||
}
|
||||
#define PSC_FROM_JSON \
|
||||
void from_base_json(const Psc::JSON* that_json) { \
|
||||
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
|
||||
boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](auto& field) mutable { \
|
||||
auto name = names[i++].data(); \
|
||||
std::error_code ec; \
|
||||
auto t = Psc::assign_field_ec(field, that_json, name, ec); \
|
||||
Psc::check_json_assign_field(t, ec, that_json, name); \
|
||||
}); \
|
||||
#define PSC_FROM_JSON \
|
||||
void from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) { \
|
||||
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
|
||||
boost::pfr::for_each_field( \
|
||||
*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](auto& field) mutable { \
|
||||
auto name = names[i++].data(); \
|
||||
std::error_code ec; \
|
||||
auto t = Psc::assign_field_ec(field, that_json, name, ec); \
|
||||
if (!not_exist_use_default_value) { \
|
||||
Psc::check_json_assign_field(t, ec, that_json, name); \
|
||||
} \
|
||||
}); \
|
||||
}
|
||||
#define PSC_USE_JSON \
|
||||
PSC_TO_JSON \
|
||||
#define PSC_USE_JSON \
|
||||
PSC_TO_JSON \
|
||||
PSC_FROM_JSON
|
||||
|
||||
Reference in New Issue
Block a user