#ifndef JSONREADWITHVERIFY_H #define JSONREADWITHVERIFY_H #include "_nlohmann_json_wrapper.h" #include "ParaHelper.h" #include "alog.h" /** @addtogroup ksjson * @{ * @addtogroup readWithVerify * @brief 从json转换到数值前判断key是否存在,确认数值是否在一定[min, max]范围内,或在一个数组列表范围之内。 * @{ */ /// \brief 尝试从obj读取键值为key的数据,没找到不赋值返回false,找到就给指针赋值并返回true。 /// \details 通常用于已经初始化为默认值的变量或结构体,找到就读,没找到就保持默认值。 /// 注意保存的格式要跟写入的格式一致,别写个string当int读,肯定会出问题的。这里就没法检验格式是否正确了。 /// /// \param obj nlohmann::json对象 /// \param key 键值,类型KeyT支持类型const char *, std::string /// \param dst 目标变量,类型ValueT可以是所有支持的数据类型,包括nlohmann::json标准的数据类型和定义了to_json和from_json的类型。 /// \return 没找到返回0,找到返回1。 template ::Type, typename ValueT> int tryRead(const jsonobj& obj, KeyT key, ValueT& dst) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) return 0; //没找到 it->template get_to(dst); return 1; } /// 尝试从obj读取键值为key的数据,没找到设置为缺省值并返回false,找到就读取数值给指针赋值并返回true。 /// 类型ValueT可以是所有支持的数据类型,包括nlohmann::json标准的数据类型和定义了to_json和from_json的类型。 /// \param obj nlohmann::json对象 /// \param dst 目标变量。 /// \param key 键值,类型KeyT支持类型const char *, std::string /// \param def 找不到键值使用的缺省值。def的数据类型ValueT2必须与dst的数据类型ValueT可以直接隐式转换或复制构造的 /// \return 没找到返回false,找到返回true。 template ::Type, typename ValueT, typename ValueT2> int readWithDefault(const jsonobj& obj, KeyT key, ValueT& dst, ValueT2 def) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = def; return 0; } it->template get_to(dst); return 1; } /// \brief 在\ref readWithDefault 基础上增加了校验读到的值是否在[min, max]范围之内。 /// \details 类型ValueT通常是数值类型。其它支持的数据类型如果它支持用大于号/小于号比较的类型也行,估计很少会用到。 /// \param obj nlohmann::json对象 /// \param key 键值,类型KeyT支持类型const char *, std::string /// \param dst 目标变量。 /// \param def 找不到键值使用的缺省值。def的数据类型必须与dst的数据类型可以直接转换的 /// \param min 取值范围的下限,min << value << max /// \param max 取值范围的上限,min << value << max /// \return 返回读取状态。 /// 没找到返回0,找到但数值超界返回-1,找到并在有效范围内返回1。 template ::Type, typename ValueT, typename ValueT2, typename ValueT3> int readInRange(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT2& def, const ValueT3& min, const ValueT3& max) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = ValueT(def); return 0; } ValueT tmp = it->template get(); if (tmp < ValueT(min)) { dst = ValueT(min); return -1; } else if (tmp > ValueT(max)) {//超界 dst = ValueT(max); return -1; } // 返回读取值 dst = tmp; return 1; } /// \brief 重载\ref readInRange 用sParaRange做取值范围的校验。 /// \details 用sParaRange的成员变量Def, Min, Max替代\ref readInRange的def, min, max参数 template ::Type, typename ValueT> inline int readInRange(const jsonobj& obj, KeyT key, ValueT& dst, const sParaRange& range) { return readInRange(obj, key, dst, range.Def, range.Min, range.Max); } /// \brief json --> ValueT,并校验数值是否在数组list[num]范围类 /// \details /// - 没找到:返回值为0,dst设置为def
/// - 找到但数值布置在列表范围内:返回值-1,dst设置为def
/// - 找到并在列表范围内:返回1,dst设置为解析值。
template ::Type, typename ValueT, typename NumT, typename = ArraySizeT::Type> int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, const ValueT* list, NumT num) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = def; return 0; } ValueT tmp = it->template get(); for (int i = 0; i < num; i++) { //不在列表中 if (tmp == list[i]) { dst = tmp; return 1; } } dst = def; return -1; } /// \brief json --> ValueT,并校验数值是否在QVector列表范围类 /// \details /// - 没找到:返回值为0,dst设置为def
/// - 找到但数值布置在列表范围内:返回值-1,dst设置为def
/// - 找到并在列表范围内:返回1,dst设置为解析值。
template ::Type, typename ValueT> int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::vector list) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = def; return 0; } ValueT tmp = it->template get(); if (list.contains(tmp)) { dst = tmp; return 1; } dst = def; return -1; } /// \brief json --> ValueT,并校验数值是否在QList列表范围类 /// \details /// - 没找到:返回值为0,dst设置为def
/// - 找到但数值布置在列表范围内:返回值-1,dst设置为def
/// - 找到并在列表范围内:返回1,dst设置为解析值。
template ::Type, typename ValueT> int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::list list) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = def; return 0; } ValueT tmp = it->template get(); if (list.contains(tmp)) { dst = tmp; return 1; } dst = def; return -1; } /// \brief 从json读入string, 与strlist里的字符串比较,确定枚举值。 /// \details /// \param strlist 字符串列表 /// \param num 字符串个数 /// \param vallist 枚举值列表。
/// vallist可以为null,代表枚举值如果是从0开始顺序递增的,dst设置为strlist数组的下标。
/// \return
/// - 没找到:返回值为0,dst设置为def
/// - 找到但字符串不在列表范围内:返回值-1,dst设置为def
/// - 找到并在列表范围内:返回1。如果vallist为null,dst设置strlist数组的下表;如果vallist非空,dst设置为对于的数组。
template ::Type, typename ValueT> int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, int def, const char* const* strlist, int num, const int* vallist = nullptr) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 alog->warn("readEnum 没找到{},返回缺省值", key); dst = ValueT(def); return 0; } if (it->is_string()) { std::string str = it->template get(); for (int i = 0; i < num; i++) { if (str.compare(strlist[i]) == 0) { if (vallist) dst = ValueT(vallist[i]); else dst = ValueT(i); return 1; } } alog->warn("readEnum {}没有匹配到字符串{},返回缺省值", key); dst = ValueT(def); } else if (it->is_number_integer()) { int val = it->template get(); if (vallist) { for (int i = 0; i < num; i++) { if (val == vallist[i]) { dst = ValueT(val); return 1; } } alog->warn("readEnum {}数值不在列表中,返回缺省值", key); dst = ValueT(def); } else { if (val >= 0 && val < num) { dst = ValueT(val); return 1; } else { alog->warn("readEnum {}数值超界,返回缺省值", key); dst = ValueT(def); } } } else { alog->error("{}的json类型错误,应该是字符串或整形,未修改结果", key); } return -1; } // 与上一版本的区别是没有缺省值 template ::Type, typename ValueT> int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, const char* const * strlist, int num, const int* vallist = nullptr) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 alog->warn("readEnum 没找到{},返回缺省值", key); return 0; } if (it->is_string()) { std::string str = it->template get(); for (int i = 0; i < num; i++) { if (str.compare(strlist[i]) == 0) { if (vallist) dst = ValueT(vallist[i]); else dst = ValueT(i); return 1; } } alog->warn("readEnum {}没有匹配到字符串{},未赋值", key); } else if (it->is_number_integer()) { int val = it->template get(); if (vallist) { for (int i = 0; i < num; i++) { if (val == vallist[i]) { dst = ValueT(val); return 1; } } alog->warn("readEnum {}数值不在列表中,未赋值", key); } else { if (val >= 0 && val < num) { dst = ValueT(val); return 1; } else { alog->warn("readEnum {}数值超界,未赋值", key); } } } else { alog->error("{}的json类型错误,应该是字符串或整形,未修改结果", key); } return -1; } /// \brief 从json读入string, 与strlist里的字符串比较,确定枚举值。 /// \details /// \param strlist 字符串列表 /// \param vallist 枚举值列表。
/// \return
/// - 没找到:返回值为0,dst设置为def
/// - 找到但字符串不在列表范围内:返回值-1,dst设置为def
/// - 找到并在列表范围内:返回1。如果vallist为null,dst设置strlist数组的下表;如果vallist非空,dst设置为对于的数组。
template ::Type, typename ValueT, typename ValutT2> int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, ValutT2 def, const char** strlist, const std::vector& vallist) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到 dst = ValueT(def); return 0; } std::string str = it->template get(); for (int i = 0; i < vallist.size(); i++) { if (str.compare(strlist[i]) == 0) { dst = vallist[i]; return 1; } } dst = ValueT(def); return -1; } /// 将C++枚举数组转换为字符串数组写入json template ::Type, typename ValueT> void writeEnumArray(jsonobj& obj, KeyT key, const char* const* strlist, int strnum, const std::vector &valuelist) { auto arr=jsonobj::array(); for(auto &val : valuelist) { if (val < 0 || val >= strnum) { alog->error("writeEnum {}数值超界", key); return; } arr.push_back(strlist[val]); } obj[key] = arr; } template ::Type, typename ValueT> int readEnumArray(const jsonobj& obj, KeyT key, std::vector& dst, const char* const* strlist, int num) { auto it = obj.find(key); if (it == obj.end()) {//没找到 alog->warn("readEnumArray 没找到{}", key); return 0; } if (!it->is_array()) { alog->error("readEnumArray {} 不是数组", key); return 0; } if (it->size() == 0) { alog->error("readEnumArray {} 是空数组", key); return 0; } dst.clear(); for (auto& x : *it) { if (x.is_string()) { std::string str=x.get(); int i = 0; for (; i < num; i++) { if (str.compare(strlist[i]) == 0) { dst.push_back(ValueT(i)); break; } } if(i==num )alog->warn("readEnumArray {}没有匹配到字符串{},未赋值", key, str); } else { alog->error("{}的json类型错误,应该是字符串,未修改结果", key); } } return int(dst.size()); } template ::Type> int readStr(const jsonobj& obj, const KeyT& key, char* dst, int dstsize) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到,或空 memset(dst, 0, dstsize); return 0; } if (!it->is_string()) { //不是字符串 return -1; } std::string str = it->template get(); auto len = str.length(); if (len >= dstsize) { return -2; } else if (len == 0) { *dst = 0; return 1; } else { memcpy(dst, str.c_str(), len); *(dst + len) = 0; return 1; } } /// /// 读入char型数值,如果长度刚好填满,不用0结束 /// /// /// /// /// /// /// template ::Type> int readCharArray(const jsonobj& obj, const KeyT& key, char* dst, int dstsize, char fill) { auto it = obj.find(key); if (it == obj.end() || it->is_null()) {//没找到,或空 memset(dst, 0, dstsize); return 0; } if (!it->is_string()) { //不是字符串 return -1; } std::string str = it->template get(); auto len = str.length(); if (len > dstsize) { return -2; } else { memcpy(dst, str.c_str(), len); if (len < dstsize) { memset(dst + len, fill, dstsize - len); } return 1; } } /** @} readWithCheck*/ /** @} json*/ #endif // JSONREADWITHVERIFY_H