常规更新

This commit is contained in:
2026-06-26 17:56:28 +08:00
parent fd6097564c
commit 5313ac5ae8
2 changed files with 1000 additions and 1164 deletions
+609 -753
View File
File diff suppressed because it is too large Load Diff
+391 -411
View File
@@ -32,7 +32,7 @@
namespace Psc {
class json_assign_error final : public std::system_error {
public:
using std::system_error::system_error;
using std::system_error::system_error;
};
enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool };
template <typename T>
@@ -42,439 +42,423 @@ bool to_number_ec(const std::string& val, T_Number& out,
std::error_code& ec) noexcept;
template <typename T_Number>
T_Number to_number(const std::string& 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");
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");
}
template <typename T_Number>
expected<T_Number, std::error_code>
try_to_number(const std::string& val) noexcept {
return detail::triple_api_expected<T_Number>(
[&val](T_Number& out, std::error_code& ec) {
return to_number_ec(val, out, ec);
});
expected<T_Number, std::error_code> try_to_number(const std::string& val) noexcept {
return detail::triple_api_expected<T_Number>(
[&val](T_Number& out, std::error_code& ec) {
return to_number_ec(val, out, ec);
});
}
template <typename T_Number>
bool to_number_ec(const std::string& 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>,
"to_number<T_Number>: T_Number must be an integral or "
"floating-point type");
try {
if constexpr (std::is_integral_v<T_Number>) {
if constexpr (std::is_unsigned_v<T_Number>) {
// stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range
unsigned long long x = std::stoull(val);
// 额外范围检查,避免静默截断
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;
}
out = static_cast<T_Number>(x);
return true;
}
else {
long long x = std::stoll(val);
// 额外范围检查,避免静默截断
if (x < static_cast<long long>(std::numeric_limits<T_Number>::min()) ||
x > static_cast<long long>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
}
else {
// floating point
long double x = std::stold(val);
// 可选:检查是否超出目标浮点类型范围
if (x < -static_cast<long double>(std::numeric_limits<T_Number>::max()) ||
x > static_cast<long double>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
}
catch (const std::invalid_argument&) {
ec = std::make_error_code(std::errc::invalid_argument);
return false; // 不能解析为数字
}
catch (const std::out_of_range&) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false; // 数值超范围
}
ec.clear();
// 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全)
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 {
if constexpr (std::is_integral_v<T_Number>) {
if constexpr (std::is_unsigned_v<T_Number>) {
// stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range
unsigned long long x = std::stoull(val);
// 额外范围检查,避免静默截断
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;
}
out = static_cast<T_Number>(x);
return true;
}
else {
long long x = std::stoll(val);
// 额外范围检查,避免静默截断
if (x < static_cast<long long>(std::numeric_limits<T_Number>::min()) ||
x > static_cast<long long>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
}
else {
// floating point
long double x = std::stold(val);
// 可选:检查是否超出目标浮点类型范围
if (x < -static_cast<long double>(std::numeric_limits<T_Number>::max()) ||
x > static_cast<long double>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
}
catch (const std::invalid_argument&) {
ec = std::make_error_code(std::errc::invalid_argument);
return false; // 不能解析为数字
}
catch (const std::out_of_range&) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false; // 数值超范围
}
}
class JSON {
public:
static std::function<void(const char*, const std::string&, const char*,
int)>
handle_error;
explicit operator std::string() const;
friend std::ostream& operator<<(std::ostream& os, const JSON& obj);
[[nodiscard]] bool has(const std::string& key) const;
[[nodiscard]] const JSON* get(const std::string& key) const;
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(const std::string& 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");
}
template <typename T_Number>
expected<T_Number, std::error_code>
try_get_number(const std::string& 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);
});
}
template <typename T_Number>
bool get_number_ec(const std::string& 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);
return false;
}
return that->number_val_ec(out, ec);
}
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");
}
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);
});
}
template <typename T_Number>
bool number_val_ec(T_Number& out, std::error_code& ec) const noexcept {
if (valueType != Number) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
return to_number_ec(val, out, ec);
}
JSON(std::string key, const JSON& body);
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(std::string k, T&& v) {
key = std::move(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>>>
JSON(T&& v) {
assign_json(valueType, val, std::forward<T>(v));
}
JSON();
JSON(const JSON& other);
JSON(JSON&& other) noexcept;
JSON& operator=(const JSON& other);
JSON& operator=(JSON&& other) noexcept;
JSON& operator+=(const JSON& child);
JSON& operator+=(JSON&& child);
void append_list(const std::vector<JSON>& arr);
void append(const JSON& json);
void prepend(const JSON& json);
static JSON array(std::string key, const std::vector<JSON>& arr);
static JSON object(std::string key, const std::vector<JSON>& children);
static JSON array(const std::vector<JSON>& arr = {});
static JSON object(const std::vector<JSON>& children = {});
JsonType valueType = Null;
std::string key, val;
std::vector<JSON> children;
[[nodiscard]] std::string
to_json_string(const std::string& object_split = "\n",
const std::string& array_split = "\n",
const std::string& indentStr = " ",
const int& indent = 0) const;
static std::function<void(const char *, const std::string&, const char *,
int)>
handle_error;
explicit operator std::string() const;
friend std::ostream& operator<<(std::ostream& os, const JSON& obj);
[[nodiscard]] bool has(const std::string& key) const;
[[nodiscard]] const JSON* get(const std::string& key) const;
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(const std::string& 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");
}
template <typename T_Number>
expected<T_Number, std::error_code> try_get_number(const std::string& 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);
});
}
template <typename T_Number>
bool get_number_ec(const std::string& 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);
return false;
}
return that->number_val_ec(out, ec);
}
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");
}
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);
});
}
template <typename T_Number>
bool number_val_ec(T_Number& out, std::error_code& ec) const noexcept {
if (valueType != Number) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
return to_number_ec(val, out, ec);
}
JSON(std::string key, const JSON& body);
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(std::string k, T&& v) {
key = std::move(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>>>
JSON(T&& v) {
assign_json(valueType, val, std::forward<T>(v));
}
JSON();
JSON(const JSON& other);
JSON(JSON&& other) noexcept;
JSON& operator=(const JSON& other);
JSON& operator=(JSON&& other) noexcept;
JSON& operator+=(const JSON& child);
JSON& operator+=(JSON&& child);
void append_list(const std::vector<JSON>& arr);
void append(const JSON& json);
void prepend(const JSON& json);
static JSON array(std::string key, const std::vector<JSON>& arr);
static JSON object(std::string key, const std::vector<JSON>& children);
static JSON array(const std::vector<JSON>& arr = {});
static JSON object(const std::vector<JSON>& children = {});
JsonType valueType = Null;
std::string key, val;
std::vector<JSON> children;
[[nodiscard]] std::string to_json_string(const std::string& object_split = "\n",
const std::string& array_split = "\n",
const std::string& indentStr = " ",
const int& indent = 0) const;
private:
static std::string get_indent(const int& indent,
const std::string& indentStr);
void append_value_string(std::string& ret, const int& indent, bool isEnd,
const std::string& object_split,
const std::string& array_split,
const std::string& indentStr,
JsonType fatherType) const;
static std::string get_indent(const int& indent,
const std::string& indentStr);
void append_value_string(std::string& ret, const int& indent, bool isEnd,
const std::string& object_split,
const std::string& array_split,
const std::string& 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);
template <typename T>
void assign_json(JsonType& rt, std::string& rv, T&& v) {
using C = std::decay_t<T>;
if constexpr (std::is_same_v<C, std::string>) {
rt = String;
rv = 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);
rt = String;
rv = ss.str();
}
// 处理 char* 类型
else if constexpr (std::is_same_v<C, char*>) {
rt = String;
rv = std::string(v);
}
else if constexpr (std::is_same_v<C, const char*>) {
rt = String;
rv = std::string(v); // 或 val = v;
}
// 处理 wchar_t* 类型
else if constexpr (std::is_same_v<C, wchar_t*>) {
std::wstring ws(v);
rt = String;
rv = std::string(ws.begin(), ws.end());
}
// 处理 std::wstring 类型
else if constexpr (std::is_same_v<C, std::wstring>) {
rt = String;
rv = std::string(v.begin(), v.end());
}
// 处理枚举类型
else if constexpr (std::is_enum_v<C>) {
rt = String;
rv = std::string(magic_enum::enum_name(v));
}
// 处理 bool 类型
else if constexpr (std::is_same_v<C, bool>) {
rt = Bool;
rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换
}
// 处理 std::nullptr_t 类型
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
rt = Null;
rv = "null";
}
else if constexpr (std::is_arithmetic_v<C>) {
rt = Number;
rv = std::to_string(v);
}
else if constexpr (is_atomic_v<C>) {
assign_json(rt, rv, v.load());
}
else if constexpr (is_optional_v<C>) {
if (v.has_value()) {
assign_json(rt, rv, v.value());
}
else {
rt = Null;
rv = "null";
}
}
else {
rt = String;
rv = v.to_string();
}
using C = std::decay_t<T>;
if constexpr (std::is_same_v<C, std::string>) {
rt = String;
rv = 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);
rt = String;
rv = ss.str();
}
// 处理 char* 类型
else if constexpr (std::is_same_v<C, char*>) {
rt = String;
rv = std::string(v);
}
else if constexpr (std::is_same_v<C, const char*>) {
rt = String;
rv = std::string(v); // 或 val = v;
}
// 处理 wchar_t* 类型
else if constexpr (std::is_same_v<C, wchar_t*>) {
std::wstring ws(v);
rt = String;
rv = std::string(ws.begin(), ws.end());
}
// 处理 std::wstring 类型
else if constexpr (std::is_same_v<C, std::wstring>) {
rt = String;
rv = std::string(v.begin(), v.end());
}
// 处理枚举类型
else if constexpr (std::is_enum_v<C>) {
rt = String;
rv = std::string(magic_enum::enum_name(v));
}
// 处理 bool 类型
else if constexpr (std::is_same_v<C, bool>) {
rt = Bool;
rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换
}
// 处理 std::nullptr_t 类型
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
rt = Null;
rv = "null";
}
else if constexpr (std::is_arithmetic_v<C>) {
rt = Number;
rv = std::to_string(v);
}
else if constexpr (is_atomic_v<C> || is_copyable_atomic_v<C>) {
assign_json(rt, rv, v.load());
}
else if constexpr (is_optional_v<C>) {
if (v.has_value()) {
assign_json(rt, rv, v.value());
}
else {
rt = Null;
rv = "null";
}
}
else {
rt = String;
rv = v.to_string();
}
}
void check_json_assign_field(bool ok, const std::error_code& ec,
const Psc::JSON* that_json, const char* name);
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;
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);
},
"assign_field failed");
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);
},
"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 {
return detail::triple_api_expected_void(
[&field, that_json, name](std::error_code& ec) {
return assign_field_ec(field, that_json, name, ec);
});
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);
});
}
template <typename T>
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name,
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);
return false;
}
auto j = that_json->get(name);
if (j == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
if constexpr (std::is_same_v<C, bool>) {
return j->bool_val_ec(field, ec);
}
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
return that_json->get_number_ec(name, field, ec);
}
else if constexpr (std::is_same_v<C, std::string>) {
return that_json->get_string_ec(name, field, ec);
}
else if constexpr (std::is_enum_v<C>) {
std::string value;
if (!that_json->get_string_ec(name, value, ec))
return false;
field = Psc::to_enum<C>(value);
}
else if constexpr (is_atomic_v<T>) {
using V = atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
}
field = value;
}
else if constexpr (is_copyable_atomic_v<T>) {
using V = copyable_atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec)) {
return false;
}
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec)) {
return false;
}
}
field = value;
}
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
}
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
}
else if constexpr (std::is_same_v<V, std::string>) {
if (!that_json->get_string_ec(name, value, ec))
return false;
}
else if constexpr (std::is_enum_v<V>) {
std::string text;
if (!that_json->get_string_ec(name, text, ec))
return false;
value = Psc::to_enum<V>(text);
}
else {
static_assert(!sizeof(T),
"assign_field does not support this optional type");
}
field = std::move(value);
}
else {
static_assert(!sizeof(T), "assign_field does not support this type");
}
return true;
using C = clean_t<T>;
if (that_json == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
auto j = that_json->get(name);
if (j == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
if constexpr (std::is_same_v<C, bool>) {
return j->bool_val_ec(field, ec);
}
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
return that_json->get_number_ec(name, field, ec);
}
else if constexpr (std::is_same_v<C, std::string>) {
return that_json->get_string_ec(name, field, ec);
}
else if constexpr (std::is_enum_v<C>) {
std::string value;
if (!that_json->get_string_ec(name, value, ec)) return false;
field = Psc::to_enum<C>(value);
}
else if constexpr (is_atomic_v<T>) {
using V = atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec)) return false;
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec)) return false;
}
field = value;
}
else if constexpr (is_copyable_atomic_v<T>) {
using V = copyable_atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec)) {
return false;
}
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec)) {
return false;
}
}
field = value;
}
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec)) return false;
}
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
if (!that_json->get_number_ec(name, value, ec)) return false;
}
else if constexpr (std::is_same_v<V, std::string>) {
if (!that_json->get_string_ec(name, value, ec)) return false;
}
else if constexpr (std::is_enum_v<V>) {
std::string text;
if (!that_json->get_string_ec(name, text, ec)) return false;
value = Psc::to_enum<V>(text);
}
else {
static_assert(!sizeof(T),
"assign_field does not support this optional type");
}
field = std::move(value);
}
else {
static_assert(!sizeof(T), "assign_field does not support this type");
}
return true;
}
template <typename T>
void output_field(const T& field, Psc::JSON& ret, const char* name) {
using C = clean_t<T>;
// bool
if constexpr (std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// 数字(排除 bool
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// string
else if constexpr (std::is_same_v<C, std::string>) {
ret.append(Psc::JSON(name, field));
}
// enum
else if constexpr (std::is_enum_v<C>) {
ret.append(Psc::JSON(name, Psc::to_string(field)));
}
// atomic<T>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.load()));
}
else if constexpr (is_copyable_atomic_v<T>) {
ret.append(Psc::JSON(name, field.load()));
}
// optional<T>
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
if (field.has_value()) {
// --- optional<bool>
if constexpr (std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<number>
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<string>
else if constexpr (std::is_same_v<V, std::string>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<enum>
else if constexpr (std::is_enum_v<V>) {
ret.append(Psc::JSON(name, to_string(field.value())));
}
// --- optional<atomic>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.value().load()));
}
// --- optional<未知类型>(调试输出)
else {
ret.append(Psc::JSON(name, field.value().to_string()));
}
}
else {
// optional 没值 → JSON null
ret.append(Psc::JSON(name, nullptr));
}
}
else if constexpr (is_shared_ptr_v<C>) {
if (field) {
ret.append(Psc::JSON(name, field->to_string()));
}
else {
ret.append(Psc::JSON(name, nullptr));
}
}
// 最终兜底
else {
ret.append(Psc::JSON(name, field.to_string()));
}
void output_field(const T& field, Psc::JSON& ret, const char *name) {
using C = clean_t<T>;
// bool
if constexpr (std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// 数字(排除 bool
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// string
else if constexpr (std::is_same_v<C, std::string>) {
ret.append(Psc::JSON(name, field));
}
// enum
else if constexpr (std::is_enum_v<C>) {
ret.append(Psc::JSON(name, Psc::to_string(field)));
}
// atomic<T>
else if constexpr (is_atomic_v<T> || is_copyable_atomic_v<C>) {
ret.append(Psc::JSON(name, field.load()));
}
// optional<T>
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
if (field.has_value()) {
// --- optional<bool>
if constexpr (std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<number>
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<string>
else if constexpr (std::is_same_v<V, std::string>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<enum>
else if constexpr (std::is_enum_v<V>) {
ret.append(Psc::JSON(name, to_string(field.value())));
}
// --- optional<atomic>
else if constexpr (is_atomic_v<T> || is_copyable_atomic_v<T>) {
ret.append(Psc::JSON(name, field.value().load()));
}
// --- optional<未知类型>(调试输出)
else {
ret.append(Psc::JSON(name, field.value().to_string()));
}
}
else {
// optional 没值 → JSON null
ret.append(Psc::JSON(name, nullptr));
}
}
else if constexpr (is_shared_ptr_v<C>) {
if (field) {
ret.append(Psc::JSON(name, field->to_string()));
}
else {
ret.append(Psc::JSON(name, nullptr));
}
}
// 最终兜底
else {
ret.append(Psc::JSON(name, field.to_string()));
}
}
} // namespace Psc
#undef Json_GET
#define Get_J_ex(NAME, FIELD) \
@@ -523,11 +507,9 @@ void output_field(const T& field, Psc::JSON& ret, const char* name) {
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) \
Psc::JSON::object({JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)})
#include "boost/pfr/core.hpp"
#include <boost/pfr/core_name.hpp>
#include <string_view>
#define PSC_TO_JSON \
[[nodiscard]] Psc::JSON to_base_json() const { \
Psc::JSON ret = Psc::JSON::object(); \
@@ -537,7 +519,6 @@ void output_field(const T& field, Psc::JSON& ret, const char* name) {
}); \
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)>>; \
@@ -548,7 +529,6 @@ void from_base_json(const Psc::JSON *that_json) { \
Psc::check_json_assign_field(t, ec, that_json, name); \
}); \
}
#define PSC_USE_JSON \
PSC_TO_JSON \
PSC_FROM_JSON
PSC_FROM_JSON