#pragma once #include #include #include #include #include "base/define.h" #include "base/exception.h" namespace ylib { /** * @brief JSON 封装(基于 nlohmann/json) * 保留历史常用 API:from / to_string / to / keys / exist / is_* / type 赋值 * private 继承:隐藏基类隐式 operator ValueType(),保证 if (j["key"]) 走 truthy() * 无额外数据成员;需要底层 API 时用 raw() */ class json : private nlohmann::json { public: using base = nlohmann::json; // 常用底层能力(不导出 begin/end,避免被当成 range 构造成 nlohmann 数组) using base::dump; using base::contains; using base::find; using base::at; using base::get; using base::get_ref; using base::get_ptr; enum type { null, obj, empty, array, boolean, number, string }; json() : base(nullptr) {} json(const json& other) = default; json(json&& other) noexcept = default; json(const base& other) : base(other) {} json(base&& other) noexcept : base(std::move(other)) {} json(std::nullptr_t) : base(nullptr) {} /// 按 type 枚举构造(避免 json x = type::array 退化成整数) json(type t) : base(nullptr) { *this = t; } json(const std::string& value) : base(value) {} json(const char* value) : base(value ? value : "") {} json(bool value) : base(value) {} json(int32 value) : base(value) {} json(uint32 value) : base(value) {} json(int64 value) : base(value) {} json(uint64 value) : base(value) {} json(double value) : base(value) {} json(float value) : base(value) {} json& operator=(const json& other) = default; json& operator=(json&& other) noexcept = default; json& operator=(const base& other) { base::operator=(other); return *this; } json& operator=(base&& other) noexcept { base::operator=(std::move(other)); return *this; } json& operator=(std::nullptr_t) { base::operator=(nullptr); return *this; } json& operator=(const std::string& value) { base::operator=(value); return *this; } json& operator=(const char* value) { if (value == nullptr) base::operator=(nullptr); else base::operator=(value); return *this; } json& operator=(bool value) { base::operator=(value); return *this; } json& operator=(int32 value) { base::operator=(value); return *this; } json& operator=(uint32 value) { base::operator=(value); return *this; } json& operator=(int64 value) { base::operator=(value); return *this; } json& operator=(uint64 value) { base::operator=(value); return *this; } json& operator=(double value) { base::operator=(value); return *this; } json& operator=(float value) { base::operator=(value); return *this; } json& operator=(type t) { switch (t) { case type::null: case type::empty: base::operator=(nullptr); break; case type::obj: base::operator=(base::object()); break; case type::array: base::operator=(base::array()); break; case type::boolean: base::operator=(false); break; case type::number: base::operator=(0); break; case type::string: base::operator=(""); break; } return *this; } /// 显式拿到底层 nlohmann::json(private 继承后不可隐式转换) base& raw() noexcept { return *this; } const base& raw() const noexcept { return *this; } static json from(const std::string& value) { if (value.empty()) return json(); try { // cb=nullptr, allow_exceptions=true, ignore_comments=true(支持 // 与 /* */) return json(base::parse(value, nullptr, true, true)); } catch (...) { return json(); } } bool parse(const std::string& value) { try { // cb=nullptr, allow_exceptions=true, ignore_comments=true(支持 // 与 /* */) *this = base::parse(value, nullptr, true, true); return true; } catch (...) { base::operator=(nullptr); return false; } } // 兼容旧签名;path / safe 已废弃为空操作 void path(const std::string&) {} void safe(bool) {} bool safe() { return false; } std::string to_string(bool format = false) const { return dump(format ? 2 : -1); } uint32 size() const { return static_cast(base::size()); } void resize(uint32 n) { if (!base::is_array()) *this = base::array(); base::get_ref().resize(n); } // null / 空对象 / 空数组 / 空字符串 视为 empty(比旧实现语义更清晰) bool is_empty() const { return base::empty(); } bool is_null() const { return base::is_null(); } bool is_obj() const { return base::is_object(); } bool is_array() const { return base::is_array(); } bool is_bool() const { return base::is_boolean(); } bool is_number() const { return base::is_number(); } bool is_string() const { return base::is_string(); } /** * @brief 真值:null / "" / 空数组 / 空对象 → false;其余(含 0、false)为 true */ bool truthy() const { if (is_null()) return false; if (is_string()) return !get_ref().empty(); if (is_array() || is_object()) return !base::empty(); return true; } /** * @brief 支持 if (j["key"]);private 继承后不会再落到基类 get() */ explicit operator bool() const { return truthy(); } bool exist(const std::string& name) const { return contains(name); } void erase(const std::string& key) { base::erase(key); } void erase(uint32 index) { if (is_array() && index < base::size()) base::erase(begin() + static_cast(index)); } void clear() { base::clear(); } std::vector keys() const { std::vector result; if (!is_object()) return result; result.reserve(base::size()); for (auto it = cbegin(); it != cend(); ++it) result.push_back(it.key()); return result; } json& operator[](const std::string& name) { return static_cast(base::operator[](name)); } const json& operator[](const std::string& name) const { auto it = find(name); if (it == cend()) { static const json null_json; return null_json; } return static_cast(*it); } // const char* 重载:配合 operator bool,避免 body["key"] 与内建下标歧义 json& operator[](const char* name) { return (*this)[std::string(name ? name : "")]; } const json& operator[](const char* name) const { return (*this)[std::string(name ? name : "")]; } json& operator[](size_t idx) { return static_cast(base::operator[](idx)); } const json& operator[](size_t idx) const { return static_cast(base::at(idx)); } json& operator[](int idx) { return static_cast(base::operator[](idx)); } const json& operator[](int idx) const { return static_cast(base::at(idx)); } json& operator[](unsigned int idx) { return static_cast(base::operator[](idx)); } const json& operator[](unsigned int idx) const { return static_cast(base::at(idx)); } using base::push_back; void push_back(const json& value) { base::push_back(static_cast(value)); } // 字面量重载:避免与基类 push_back(basic_json) 因隐式转换产生歧义 void push_back(bool value) { base::push_back(value); } void push_back(int32 value) { base::push_back(value); } void push_back(uint32 value) { base::push_back(value); } void push_back(int64 value) { base::push_back(value); } void push_back(uint64 value) { base::push_back(value); } void push_back(double value) { base::push_back(value); } void push_back(float value) { base::push_back(value); } void push_back(const char* value) { base::push_back(value ? value : ""); } void push_back(const std::string& value) { base::push_back(value); } bool operator==(const json& rhs) const { return static_cast(*this) == static_cast(rhs); } bool operator!=(const json& rhs) const { return !(*this == rhs); } template T_TO to(bool /*check*/ = false) const { using T = T_TO; if constexpr (std::is_same_v) { if (is_string()) return get(); if (is_null()) return std::string(); if (is_boolean()) return get() ? "true" : "false"; if (is_number_unsigned()) return std::to_string(get()); if (is_number_integer()) return std::to_string(get()); if (is_number_float()) return std::to_string(get()); return dump(); } else if constexpr (std::is_same_v) { if (is_boolean()) return get(); if (is_number()) return get() != 0.0; if (is_string()) { const auto& s = get_ref(); return s == "1" || s == "true" || s == "TRUE" || s == "True"; } return false; } else if constexpr (std::is_arithmetic_v) { if (is_number()) return get(); if (is_boolean()) return static_cast(get() ? 1 : 0); if (is_string()) { try { const auto& s = get_ref(); if constexpr (std::is_floating_point_v) return static_cast(std::stod(s)); else if constexpr (std::is_signed_v) return static_cast(std::stoll(s)); else return static_cast(std::stoull(s)); } catch (...) { return T{}; } } return T{}; } else if constexpr (std::is_same_v>) { std::vector result; if (!is_array()) return result; for (const auto& el : *this) result.push_back(static_cast(el).template to()); return result; } else if constexpr (std::is_same_v>) { std::vector result; if (!is_array()) return result; for (const auto& el : *this) result.push_back(static_cast(el)); return result; } else { throw ylib::exception("json::to unsupported type"); } } }; }