#pragma once #include #include #include #include #include #include #include #include #include #include namespace aigc { /****************************************************** * Register class or struct members * eg: * struct Test * { * string A; * string B; * AIGC_JSON_HELPER(A, B) * }; ******************************************************/ #define AIGC_JSON_HELPER(...) \ std::map __aigcDefaultValues; \ bool AIGCJsonToObject(aigc::JsonHelperPrivate &handle, \ rapidjson::Value &jsonValue, \ std::vector &names) { \ std::vector standardNames = handle.GetMembersNames(#__VA_ARGS__); \ if (names.size() <= standardNames.size()) { \ for (int i = static_cast(names.size()); i < static_cast(standardNames.size()); i++) \ names.push_back(standardNames[i]); \ } \ return handle.SetMembers(names, 0, jsonValue, __aigcDefaultValues, __VA_ARGS__); \ } \ bool AIGCObjectToJson(aigc::JsonHelperPrivate &handle, \ rapidjson::Value &jsonValue, \ rapidjson::Document::AllocatorType &allocator, \ std::vector &names) { \ std::vector standardNames = handle.GetMembersNames(#__VA_ARGS__); \ if (names.size() <= standardNames.size()) { \ for (int i = static_cast(names.size()); i < static_cast(standardNames.size()); i++) \ names.push_back(standardNames[i]); \ } \ return handle.GetMembers(names, 0, jsonValue, allocator, __VA_ARGS__); \ } /****************************************************** * Rename members * eg: * struct Test * { * string A; * string B; * AIGC_JSON_HELPER(A, B) * AIGC_JSON_HELPER_RENAME("a", "b") * }; ******************************************************/ #define AIGC_JSON_HELPER_RENAME(...) \ std::vector AIGCRenameMembers(aigc::JsonHelperPrivate &handle) { \ return handle.GetMembersNames(#__VA_ARGS__); \ } /****************************************************** * Register base-class * eg: * struct Base * { * string name; * AIGC_JSON_HELPER(name) * }; * struct Test : Base * { * string A; * string B; * AIGC_JSON_HELPER(A, B) * AIGC_JSON_HELPER_BASE((Base*)this) * }; ******************************************************/ #define AIGC_JSON_HELPER_BASE(...) \ bool AIGCBaseJsonToObject(aigc::JsonHelperPrivate &handle, rapidjson::Value &jsonValue) { \ return handle.SetBase(jsonValue, __VA_ARGS__); \ } \ bool AIGCBaseObjectToJson(aigc::JsonHelperPrivate &handle, \ rapidjson::Value &jsonValue, \ rapidjson::Document::AllocatorType &allocator) { \ return handle.GetBase(jsonValue, allocator, __VA_ARGS__); \ } /****************************************************** * Set default value * eg: * struct Base * { * string name; * int age; * AIGC_JSON_HELPER(name, age) * AIGC_JSON_HELPER_DEFAULT(age=18) * }; ******************************************************/ #define AIGC_JSON_HELPER_DEFAULT(...) \ void AIGCDefaultValues(aigc::JsonHelperPrivate &handle) { \ __aigcDefaultValues = handle.GetMembersValueMap(#__VA_ARGS__); \ } class JsonHelperPrivate { public: /****************************************************** * * enable_if * ******************************************************/ template struct enable_if {}; template struct enable_if { typedef TYPE type; }; public: /****************************************************** * * Check Interface * If class or struct add AIGC_JSON_HELPER\AIGC_JSON_HELPER_RENAME\AIGC_JSON_HELPER_BASE, * it will go to the correct conver function. * ******************************************************/ template struct HasConverFunction { template static char func(decltype(&TT::AIGCJsonToObject)); template static int func(...); const static bool has = (sizeof(func(NULL)) == sizeof(char)); }; template struct HasRenameFunction { template static char func(decltype(&TT::AIGCRenameMembers)); template static int func(...); const static bool has = (sizeof(func(NULL)) == sizeof(char)); }; template struct HasBaseConverFunction { template static char func(decltype(&TT::AIGCBaseJsonToObject)); template static int func(...); const static bool has = (sizeof(func(NULL)) == sizeof(char)); }; template struct HasDefaultValueFunction { template static char func(decltype(&TT::AIGCDefaultValues)); template static int func(...); const static bool has = (sizeof(func(NULL)) == sizeof(char)); }; public: /****************************************************** * * Interface of JsonToObject\ObjectToJson * ******************************************************/ template::has, int>::type = 0> bool JsonToObject(T &obj, rapidjson::Value &jsonValue) { if (!BaseConverJsonToObject(obj, jsonValue)) { return false; } LoadDefaultValuesMap(obj); std::vector names = LoadRenameArray(obj); return obj.AIGCJsonToObject(*this, jsonValue, names); } template::has, int>::type = 0> bool JsonToObject(T &obj, rapidjson::Value &jsonValue) { if (std::is_enum::value) { int ivalue; if (!JsonToObject(ivalue, jsonValue)) { return false; } obj = static_cast(ivalue); return true; } m_message = "unsupported this type."; return false; } template::has, int>::type = 0> bool ObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { if (jsonValue.IsNull()) { jsonValue.SetObject(); } if (!BaseConverObjectToJson(obj, jsonValue, allocator)) { return false; } std::vector names = LoadRenameArray(obj); return obj.AIGCObjectToJson(*this, jsonValue, allocator, names); } template::has, int>::type = 0> bool ObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { if (std::is_enum::value) { int ivalue = static_cast(obj); return ObjectToJson(ivalue, jsonValue, allocator); } m_message = "unsupported this type."; return false; } /****************************************************** * * Interface of LoadRenameArray * ******************************************************/ template::has, int>::type = 0> std::vector LoadRenameArray(T &obj) { return obj.AIGCRenameMembers(*this); } template::has, int>::type = 0> std::vector LoadRenameArray(T &obj) { return std::vector(); } /****************************************************** * * Interface of BaseConverJsonToObject\BaseConverObjectToJson * ******************************************************/ template::has, int>::type = 0> bool BaseConverJsonToObject(T &obj, rapidjson::Value &jsonValue) { return obj.AIGCBaseJsonToObject(*this, jsonValue); } template::has, int>::type = 0> bool BaseConverJsonToObject(T &obj, rapidjson::Value &jsonValue) { return true; } template::has, int>::type = 0> bool BaseConverObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { return obj.AIGCBaseObjectToJson(*this, jsonValue, allocator); } template::has, int>::type = 0> bool BaseConverObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { return true; } /****************************************************** * * Interface of Default value * ******************************************************/ template::has, int>::type = 0> void LoadDefaultValuesMap(T &obj) { obj.AIGCDefaultValues(*this); } template::has, int>::type = 0> void LoadDefaultValuesMap(T &obj) { (void)obj; } public: /****************************************************** * * Tool function * ******************************************************/ static std::vector StringSplit(const std::string &str, char sep = ',') { std::vector array; std::string::size_type pos1, pos2; pos1 = 0; pos2 = str.find(sep); while (std::string::npos != pos2) { array.push_back(str.substr(pos1, pos2 - pos1)); pos1 = pos2 + 1; pos2 = str.find(sep, pos1); } if (pos1 != str.length()) { array.push_back(str.substr(pos1)); } return array; } static std::string StringTrim(std::string key) { std::string newStr = key; if (!newStr.empty()) { newStr.erase(0, newStr.find_first_not_of(" ")); newStr.erase(newStr.find_last_not_of(" ") + 1); } if (!newStr.empty()) { newStr.erase(0, newStr.find_first_not_of("\"")); newStr.erase(newStr.find_last_not_of("\"") + 1); } return newStr; } static void StringTrim(std::vector &array) { for (int i = 0; i < (int)array.size(); i++) { array[i] = StringTrim(array[i]); } } /** * Get json value type */ static std::string GetJsonValueTypeName(rapidjson::Value &jsonValue) { switch (jsonValue.GetType()) { case rapidjson::Type::kArrayType: return "array"; case rapidjson::Type::kFalseType: case rapidjson::Type::kTrueType: return "bool"; case rapidjson::Type::kObjectType: return "object"; case rapidjson::Type::kStringType: return "string"; case rapidjson::Type::kNumberType: return "number"; default: return "string"; } } static std::string GetStringFromJsonValue(rapidjson::Value &jsonValue, bool isPrettyWriter = false) { rapidjson::StringBuffer buffer; if (isPrettyWriter) { rapidjson::PrettyWriter writer(buffer); jsonValue.Accept(writer); } else { rapidjson::Writer writer(buffer); jsonValue.Accept(writer); } std::string ret = std::string(buffer.GetString()); return ret; } static std::string FindStringFromMap(std::string name, std::map &stringMap) { std::map::iterator iter = stringMap.find(name); if (iter == stringMap.end()) { return ""; } return iter->second; } public: /****************************************************** * * Set class/struct members value * ******************************************************/ std::vector GetMembersNames(const std::string membersStr) { std::vector array = StringSplit(membersStr); StringTrim(array); return array; } std::map GetMembersValueMap(const std::string valueStr) { std::vector array = StringSplit(valueStr); std::map ret; for (int i = 0; i < array.size(); i++) { std::vector keyValue = StringSplit(array[i], '='); if (keyValue.size() != 2) { continue; } std::string key = StringTrim(keyValue[0]); std::string value = StringTrim(keyValue[1]); if (ret.find(key) != ret.end()) { continue; } ret.insert(std::pair(key, value)); } return ret; } template bool SetMembers(const std::vector &names, int index, rapidjson::Value &jsonValue, std::map defaultValues, TYPE &arg, TYPES &...args) { if (!SetMembers(names, index, jsonValue, defaultValues, arg)) { return false; } return SetMembers(names, ++index, jsonValue, defaultValues, args...); } template bool SetMembers(const std::vector &names, int index, rapidjson::Value &jsonValue, std::map defaultValues, TYPE &arg) { if (jsonValue.IsNull()) { return true; } const char *key = names[index].c_str(); if (!jsonValue.IsObject()) { return false; } if (!jsonValue.HasMember(key)) { std::string defaultV = FindStringFromMap(names[index], defaultValues); if (!defaultV.empty()) { StringToObject(arg, defaultV); } return true; } if (!JsonToObject(arg, jsonValue[key])) { m_message = "[" + names[index] + "] " + m_message; return false; } return true; } /****************************************************** * * Get class/struct members value * ******************************************************/ template bool GetMembers(const std::vector &names, int index, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE &arg, TYPES &...args) { if (!GetMembers(names, index, jsonValue, allocator, arg)) { return false; } return GetMembers(names, ++index, jsonValue, allocator, args...); } template bool GetMembers(const std::vector &names, int index, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE &arg) { rapidjson::Value item; bool check = ObjectToJson(arg, item, allocator); if (!check) { m_message = "[" + names[index] + "] " + m_message; return false; } if (jsonValue.HasMember(names[index].c_str())) { jsonValue.RemoveMember(names[index].c_str()); } rapidjson::Value key; key.SetString(names[index].c_str(), static_cast(names[index].length()), allocator); jsonValue.AddMember(key, item, allocator); return true; } public: /****************************************************** * * Set base class value * ******************************************************/ template bool SetBase(rapidjson::Value &jsonValue, TYPE *arg, TYPES *...args) { if (!SetBase(jsonValue, arg)) { return false; } return SetBase(jsonValue, args...); } template bool SetBase(rapidjson::Value &jsonValue, TYPE *arg) { return JsonToObject(*arg, jsonValue); } /****************************************************** * * Get base class value * ******************************************************/ template bool GetBase(rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE *arg, TYPES *...args) { if (!GetBase(jsonValue, allocator, arg)) { return false; } return GetBase(jsonValue, allocator, args...); } template bool GetBase(rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE *arg) { return ObjectToJson(*arg, jsonValue, allocator); } public: /****************************************************** * Conver base-type : string to base-type * Contain: int\uint、int64_t\uint64_t、bool、float * double、string * ******************************************************/ template void StringToObject(TYPE &obj, std::string &value) { return; } void StringToObject(std::string &obj, std::string &value) { obj = value; } void StringToObject(int &obj, std::string &value) { obj = atoi(value.c_str()); } void StringToObject(unsigned int &obj, std::string &value) { char *end; obj = strtoul(value.c_str(), &end, 10); } void StringToObject(int64_t &obj, std::string &value) { char *end; obj = strtoll(value.c_str(), &end, 10); } void StringToObject(uint64_t &obj, std::string &value) { char *end; obj = strtoull(value.c_str(), &end, 10); } void StringToObject(bool &obj, std::string &value) { obj = (value == "true"); } void StringToObject(float &obj, std::string &value) { obj = strtof(value.c_str(), nullptr); } void StringToObject(double &obj, std::string &value) { obj = strtod(value.c_str(), nullptr); } public: /****************************************************** * Conver base-type : Json string to base-type * Contain: int\uint、int64_t\uint64_t、bool、float * double、string、vector、list、map * ******************************************************/ bool JsonToObject(int &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsInt()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is int."; return false; } obj = jsonValue.GetInt(); return true; } bool JsonToObject(unsigned int &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsUint()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is unsigned int."; return false; } obj = jsonValue.GetUint(); return true; } bool JsonToObject(short &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsInt()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is short."; return false; } obj = jsonValue.GetInt(); return true; } bool JsonToObject(unsigned short &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsUint()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is unsigned short."; return false; } obj = jsonValue.GetUint(); return true; } bool JsonToObject(int64_t &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsInt64()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is int64_t."; return false; } obj = jsonValue.GetInt64(); return true; } bool JsonToObject(uint64_t &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsUint64()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is uint64_t."; return false; } obj = jsonValue.GetUint64(); return true; } bool JsonToObject(bool &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsBool()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is bool."; return false; } obj = jsonValue.GetBool(); return true; } bool JsonToObject(float &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsNumber()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is float."; return false; } obj = jsonValue.GetFloat(); return true; } bool JsonToObject(double &obj, rapidjson::Value &jsonValue) { if (!jsonValue.IsNumber()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is double."; return false; } obj = jsonValue.GetDouble(); return true; } bool JsonToObject(std::string &obj, rapidjson::Value &jsonValue) { obj = ""; if (jsonValue.IsNull()) { return true; } //object or number conver to string else if (jsonValue.IsObject() || jsonValue.IsNumber()) { obj = GetStringFromJsonValue(jsonValue); } else if (!jsonValue.IsString()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is string."; return false; } else { obj = jsonValue.GetString(); } return true; } template bool JsonToObject(std::vector &obj, rapidjson::Value &jsonValue) { obj.clear(); if (!jsonValue.IsArray()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::vector."; return false; } auto array = jsonValue.GetArray(); for (int i = 0; i < array.Size(); i++) { TYPE item; if (!JsonToObject(item, array[i])) { return false; } obj.push_back(item); } return true; } template bool JsonToObject(std::list &obj, rapidjson::Value &jsonValue) { obj.clear(); if (!jsonValue.IsArray()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::list."; return false; } auto array = jsonValue.GetArray(); for (int i = 0; i < static_cast(array.Size()); i++) { TYPE item; if (!JsonToObject(item, array[i])) { return false; } obj.push_back(item); } return true; } template bool JsonToObject(std::map &obj, rapidjson::Value &jsonValue) { obj.clear(); if (!jsonValue.IsObject()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::map."; return false; } for (auto iter = jsonValue.MemberBegin(); iter != jsonValue.MemberEnd(); ++iter) { auto key = (iter->name).GetString(); auto &value = jsonValue[key]; TYPE item; if (!JsonToObject(item, value)) { return false; } obj.insert(std::pair(key, item)); } return true; } template bool JsonToObject(std::unordered_map &obj, rapidjson::Value &jsonValue) { obj.clear(); if (!jsonValue.IsObject()) { m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::unordered_map."; return false; } for (auto iter = jsonValue.MemberBegin(); iter != jsonValue.MemberEnd(); ++iter) { auto key = (iter->name).GetString(); auto &value = jsonValue[key]; TYPE item; if (!JsonToObject(item, value)) { return false; } obj.insert(std::pair(key, item)); } return true; } public: /****************************************************** * Conver base-type : base-type to json string * Contain: int\uint、int64_t\uint64_t、bool、float * double、string、vector、list、map * ******************************************************/ bool ObjectToJson(int &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetInt(obj); return true; } bool ObjectToJson(unsigned int &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetUint(obj); return true; } bool ObjectToJson(short &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetInt((int)obj); return true; } bool ObjectToJson(unsigned short &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetUint((unsigned int)obj); return true; } bool ObjectToJson(int64_t &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetInt64(obj); return true; } bool ObjectToJson(uint64_t &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetUint64(obj); return true; } bool ObjectToJson(bool &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetBool(obj); return true; } bool ObjectToJson(float &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetFloat(obj); return true; } bool ObjectToJson(double &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetDouble(obj); return true; } bool ObjectToJson(std::string &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetString(obj.c_str(), static_cast(obj.length()), allocator); return true; } template bool ObjectToJson(std::vector &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { rapidjson::Value array(rapidjson::Type::kArrayType); for (int i = 0; i < obj.size(); i++) { rapidjson::Value item; if (!ObjectToJson(obj[i], item, allocator)) { return false; } array.PushBack(item, allocator); } jsonValue = array; return true; } template bool ObjectToJson(std::list &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { rapidjson::Value array(rapidjson::Type::kArrayType); for (auto i = obj.begin(); i != obj.end(); i++) { rapidjson::Value item; if (!ObjectToJson(*i, item, allocator)) { return false; } array.PushBack(item, allocator); } jsonValue = array; return true; } template bool ObjectToJson(std::map &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetObject(); for (auto iter = obj.begin(); iter != obj.end(); ++iter) { auto key = iter->first; TYPE value = iter->second; rapidjson::Value jsonitem; if (!ObjectToJson(value, jsonitem, allocator)) { return false; } rapidjson::Value jsonkey; jsonkey.SetString(key.c_str(), key.length(), allocator); jsonValue.AddMember(jsonkey, jsonitem, allocator); } return true; } template bool ObjectToJson(std::unordered_map &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator) { jsonValue.SetObject(); for (auto iter = obj.begin(); iter != obj.end(); ++iter) { auto key = iter->first; TYPE value = iter->second; rapidjson::Value jsonitem; if (!ObjectToJson(value, jsonitem, allocator)) { return false; } rapidjson::Value jsonkey; jsonkey.SetString(key.c_str(), key.length(), allocator); jsonValue.AddMember(jsonkey, jsonitem, allocator); } return true; } public: std::string m_message; }; class JsonHelper { public: /** * @brief conver json string to class | struct * @param obj : class or struct * @param jsonStr : json string * @param keys : the path of the object * @param message : printf err message when conver failed */ template static bool JsonToObject(T &obj, const std::string &jsonStr, const std::vector keys = {}, std::string *message = NULL) { //Parse json string rapidjson::Document root; root.Parse(jsonStr.c_str()); if (root.IsNull()) { if (message) { *message = "Json string can't parse."; } return false; } //Go to the key-path std::string path; rapidjson::Value &value = root; for (int i = 0; i < (int)keys.size(); i++) { const char *find = keys[i].c_str(); if (!path.empty()) { path += "->"; } path += keys[i]; if (!value.IsObject() || !value.HasMember(find)) { if (message) { *message = "Can't parse the path [" + path + "]."; } return false; } value = value[find]; } //Conver JsonHelperPrivate handle; if (!handle.JsonToObject(obj, value)) { if (message) { *message = handle.m_message; } return false; } return true; } /** * @brief conver json string to class | struct * @param jsonStr : json string * @param defaultT : default value * @param keys : the path of the object * @param message : printf err message when conver failed */ template static T Get(const std::string &jsonStr, T defaultT, const std::vector keys = {}, std::string *message = NULL) { T obj; if (JsonToObject(obj, jsonStr, keys, message)) { return obj; } return defaultT; } /** * @brief conver class | struct to json string * @param errMessage : printf err message when conver failed * @param isPretty Output pretty format json string * @param obj : class or struct * @param jsonStr : json string */ template static bool ObjectToJson(T &obj, std::string &jsonStr, bool isPretty, std::string *message) { rapidjson::Document root; root.SetObject(); rapidjson::Document::AllocatorType &allocator = root.GetAllocator(); //Conver JsonHelperPrivate handle; if (!handle.ObjectToJson(obj, root, allocator)) { if (message) { *message = handle.m_message; } return false; } jsonStr = handle.GetStringFromJsonValue(root, isPretty); return true; } /** * @brief conver class | struct to json string * @param errMessage : printf err message when conver failed * @param obj : class or struct * @param isPretty Output pretty format json string * @param jsonStr : json string */ template static bool ObjectToJson(T &obj, std::string &jsonStr, bool isPretty = false) { rapidjson::Document root; root.SetObject(); rapidjson::Document::AllocatorType &allocator = root.GetAllocator(); //Conver JsonHelperPrivate handle; if (!handle.ObjectToJson(obj, root, allocator)) { return false; } jsonStr = handle.GetStringFromJsonValue(root, isPretty); return true; } }; } // namespace aigc