Files
GdCpp12/include/json/jsonReadWithVerify.h

422 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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 <typename KeyT, typename = typename JsonKey<KeyT>::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<ValueT>(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 <typename KeyT, typename = typename JsonKey<KeyT>::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<ValueT>(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 <typename KeyT, typename = typename JsonKey<KeyT>::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<ValueT>();
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<ValueT>做取值范围的校验。
/// \details 用sParaRange的成员变量Def, Min, Max替代\ref readInRange的def, min, max参数
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
inline int readInRange(const jsonobj& obj, KeyT key, ValueT& dst, const sParaRange<ValueT>& range)
{
return readInRange(obj, key, dst, range.Def, range.Min, range.Max);
}
/// \brief json --> ValueT并校验数值是否在数组list[num]范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename NumT, typename = ArraySizeT<NumT>::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<ValueT>();
for (int i = 0; i < num; i++) { //不在列表中
if (tmp == list[i]) {
dst = tmp;
return 1;
}
}
dst = def;
return -1;
}
/// \brief json --> ValueT并校验数值是否在QVector<ValueT>列表范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::vector<ValueT> list)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
ValueT tmp = it->template get<ValueT>();
if (list.contains(tmp)) {
dst = tmp;
return 1;
}
dst = def;
return -1;
}
/// \brief json --> ValueT并校验数值是否在QList<ValueT>列表范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::list<ValueT> list)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
ValueT tmp = it->template get<ValueT>();
if (list.contains(tmp)) {
dst = tmp;
return 1;
}
dst = def;
return -1;
}
/// \brief 从json读入string, 与strlist里的字符串比较确定枚举值。
/// \details
/// \param strlist 字符串列表
/// \param num 字符串个数
/// \param vallist 枚举值列表。<br>
/// vallist可以为null代表枚举值如果是从0开始顺序递增的dst设置为strlist数组的下标。<br>
/// \return <br>
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但字符串不在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1。如果vallist为nulldst设置strlist数组的下表如果vallist非空dst设置为对于的数组。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::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<std::string>();
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<int>();
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 <typename KeyT, typename = typename JsonKey<KeyT>::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<std::string>();
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<int>();
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 枚举值列表。<br>
/// \return <br>
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但字符串不在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1。如果vallist为nulldst设置strlist数组的下表如果vallist非空dst设置为对于的数组。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename ValutT2>
int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, ValutT2 def, const char** strlist, const std::vector<ValueT>& vallist)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = ValueT(def);
return 0;
}
std::string str = it->template get<std::string>();
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 <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
void writeEnumArray(jsonobj& obj, KeyT key, const char* const* strlist, int strnum, const std::vector<ValueT> &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 <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readEnumArray(const jsonobj& obj, KeyT key, std::vector<ValueT>& 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<std::string >();
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 <typename KeyT, typename = typename JsonKey<KeyT>::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<std::string>();
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;
}
}
/// <summary>
/// 读入char型数值如果长度刚好填满不用0结束
/// </summary>
/// <typeparam name="KeyT"></typeparam>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <param name="dst"></param>
/// <param name="dstsize"></param>
/// <returns></returns>
template <typename KeyT, typename = typename JsonKey<KeyT>::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<std::string>();
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