| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #pragma once
- #include <nlohmann/json.hpp>
- #include <string>
- #include <vector>
- #include <type_traits>
- #include "base/define.h"
- #include "base/exception.h"
- namespace ylib
- {
- /**
- * @brief JSON 封装(基于 nlohmann/json)
- * 保留历史常用 API:from / to_string / to<T> / 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<uint32>(base::size()); }
- void resize(uint32 n)
- {
- if (!base::is_array())
- *this = base::array();
- base::get_ref<base::array_t&>().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<const base::string_t&>().empty();
- if (is_array() || is_object())
- return !base::empty();
- return true;
- }
- /**
- * @brief 支持 if (j["key"]);private 继承后不会再落到基类 get<bool>()
- */
- 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<difference_type>(index));
- }
- void clear() { base::clear(); }
- std::vector<std::string> keys() const
- {
- std::vector<std::string> 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<json&>(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<const json&>(*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<json&>(base::operator[](idx));
- }
- const json& operator[](size_t idx) const
- {
- return static_cast<const json&>(base::at(idx));
- }
- json& operator[](int idx)
- {
- return static_cast<json&>(base::operator[](idx));
- }
- const json& operator[](int idx) const
- {
- return static_cast<const json&>(base::at(idx));
- }
- json& operator[](unsigned int idx)
- {
- return static_cast<json&>(base::operator[](idx));
- }
- const json& operator[](unsigned int idx) const
- {
- return static_cast<const json&>(base::at(idx));
- }
- using base::push_back;
- void push_back(const json& value)
- {
- base::push_back(static_cast<const base&>(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<const base&>(*this) == static_cast<const base&>(rhs);
- }
- bool operator!=(const json& rhs) const { return !(*this == rhs); }
- template<typename T_TO>
- T_TO to(bool /*check*/ = false) const
- {
- using T = T_TO;
- if constexpr (std::is_same_v<T, std::string>)
- {
- if (is_string())
- return get<std::string>();
- if (is_null())
- return std::string();
- if (is_boolean())
- return get<bool>() ? "true" : "false";
- if (is_number_unsigned())
- return std::to_string(get<uint64_t>());
- if (is_number_integer())
- return std::to_string(get<int64_t>());
- if (is_number_float())
- return std::to_string(get<double>());
- return dump();
- }
- else if constexpr (std::is_same_v<T, bool>)
- {
- if (is_boolean())
- return get<bool>();
- if (is_number())
- return get<double>() != 0.0;
- if (is_string())
- {
- const auto& s = get_ref<const base::string_t&>();
- return s == "1" || s == "true" || s == "TRUE" || s == "True";
- }
- return false;
- }
- else if constexpr (std::is_arithmetic_v<T>)
- {
- if (is_number())
- return get<T>();
- if (is_boolean())
- return static_cast<T>(get<bool>() ? 1 : 0);
- if (is_string())
- {
- try
- {
- const auto& s = get_ref<const base::string_t&>();
- if constexpr (std::is_floating_point_v<T>)
- return static_cast<T>(std::stod(s));
- else if constexpr (std::is_signed_v<T>)
- return static_cast<T>(std::stoll(s));
- else
- return static_cast<T>(std::stoull(s));
- }
- catch (...)
- {
- return T{};
- }
- }
- return T{};
- }
- else if constexpr (std::is_same_v<T, std::vector<std::string>>)
- {
- std::vector<std::string> result;
- if (!is_array())
- return result;
- for (const auto& el : *this)
- result.push_back(static_cast<const json&>(el).template to<std::string>());
- return result;
- }
- else if constexpr (std::is_same_v<T, std::vector<json>>)
- {
- std::vector<json> result;
- if (!is_array())
- return result;
- for (const auto& el : *this)
- result.push_back(static_cast<const json&>(el));
- return result;
- }
- else
- {
- throw ylib::exception("json::to unsupported type");
- }
- }
- };
- }
|