C++实现简易JSON解析与转储

devtools/2024/10/21 22:43:32/

FCJson.h

#pragma once
#include <stdint.h>
#include <string>
#include <vector>
#include <map>// VS 将执行字符集指定为 UTF-8
// 项目属性页 -> 配置属性 -> C/C++ -> 命令行 -> 其他选项(D) 
// 加入 /execution-charset:utf-8 或/utf-8
//// 此编译器指令在 Visual Studio 2015 Update 2 及更高版本中已过时
// #pragma execution_character_set("utf-8")// JSON规范: https://www.json.org/json-zh.html#ifdef _UNICODE#define __T(x)      L ## x
using _tstring = std::wstring;
using _tchar = wchar_t;
using _utchar = _tchar;#else#define __T(x)      x
using _tstring = std::string;
using _tchar = char;
using _utchar = unsigned char;#endif#define _T(x)       __T(x)
#define _TEXT(x)    __T(x)#define FC_JSON_RETURN  "\n"// JSON 解析
// FlameCyclone
namespace FCJson
{class JsonValue;using JsonNull = nullptr_t;using JsonBool = bool;using JsonInt = int64_t;using JsonUInt = uint64_t;using JsonFloat = double;using JsonString = _tstring;using JsonObject = std::map<_tstring, JsonValue>;using JsonArray = std::vector<JsonValue>;// 异常class JsonException{public:JsonException(const _tstring& msg) :m_Message(msg){}_tstring GetMessage() const{return m_Message;}_tstring GetTextPos() const{return m_Message;}private:_tstring    m_Message;      // 提示};// JSON 数据类型enum JsonType{eNull,              // 空值       nulleString,            // 字符串     "FlameCyclone"eInt,               // 有符号整数 正数: 0 - 9223372036854775807 负数: -1 - (9223372036854775807 - 1)eUInt,              // 无符号整数 0 - 18446744073709551615eFloat,             // 浮点数     3.141592653589793eBool,              // 布尔       true 或 falseeObject,            // 对象       [128,256,512,1204,"string",{"name":"FlameCyclone"}]eArray,             // 数组       {"name":"FlameCyclone"}};// JSON 编码enum JsonEncoding{eAuto,              // 自动eUtf8,              // Utf8eUtf16,             // Utf16编码};// JSON 值类class JsonValue{public:// 构造JsonValue();JsonValue(JsonType type);JsonValue(nullptr_t val);JsonValue(JsonBool val);JsonValue(int32_t val);JsonValue(uint32_t val);JsonValue(int64_t val);JsonValue(uint64_t val);JsonValue(JsonFloat val);JsonValue(const _tchar* val);JsonValue(const JsonString& val);JsonValue(const JsonObject& val);JsonValue(const JsonArray& val);JsonValue(const JsonValue& r);JsonValue(JsonValue&& r) noexcept;JsonValue(JsonString&& val);JsonValue(JsonObject&& val);JsonValue(JsonArray&& val);// 运算符重载JsonValue& operator = (JsonType type);JsonValue& operator = (JsonBool val);JsonValue& operator = (int32_t val);JsonValue& operator = (uint32_t val);JsonValue& operator = (int64_t val);JsonValue& operator = (uint64_t val);JsonValue& operator = (JsonFloat val);JsonValue& operator = (const _tchar* val);JsonValue& operator = (const JsonString& val);JsonValue& operator = (const JsonObject& val);JsonValue& operator = (const JsonArray& val);JsonValue& operator = (const JsonValue& r);JsonValue& operator = (JsonString&& val);JsonValue& operator = (JsonObject&& val);JsonValue& operator = (JsonArray&& val);JsonValue& operator = (JsonValue&& r) noexcept;JsonValue& operator [] (const _tstring& name);JsonValue& operator [] (const size_t index);// 清空void Clear();~JsonValue();// 检查与类型判断JsonType GetType() const;_tstring GetTypeName() const;// 类型判断bool IsObjectOrArray() const;bool IsNull() const;bool IsBool() const;bool IsInt() const;bool IsFloat() const;bool IsString() const;bool IsObject() const;bool IsArray() const;// 获取数据JsonBool AsBool() const;JsonInt AsInt() const;JsonUInt AsUInt() const;JsonFloat AsFloat() const;JsonString AsString() const;JsonObject AsObject() const;JsonArray AsArray() const;// // @brief: 获取本身或子项计数// @param: name             子项(空字符串: 本身对象或数组的计数 非空: 对象子项的计数)// @ret: size_t             计数, 非数组或对象时返回1, 不存在返回0size_t Count(const _tstring& name = _T("")) const;// // @brief: 从文本解析(仅支持 UTF8 或 UTF16编码的文本)// @param: strText          文本内容// @ret: JsonValue          JSON值JsonValue Parse(const _tstring& strText);// // @brief: 从文件解析(仅支持 UTF8 或 UTF16编码的文件)// @param: strPath          文件路径// @ret: JsonValue          JSON值JsonValue ParseFile(const _tstring& strPath);// // @brief: 转储为文本// @param: indent           缩进空格数量// @param: fEscapeCh        是否转义非Ascii字符// @ret: std::wstring       转储文本_tstring Dump(int indent = 0, bool fEscapeCh = false) const;// // @brief: 转储到文件// @param: strPath          文件路径// @param: indent           缩进空格数量// @param: enc              Unicode编码类型(UTF8或UTF16)// @param: fEscapeCh        是否转义非Ascii字符// @ret: std::wstring       转储文本bool DumpFile(const _tstring& strPath, int indent = 0, bool fEscapeCh = false, JsonEncoding enc = JsonEncoding::eAuto);private:// 解析JsonValue _Parse(const _tchar* pData, const _tchar** pEnd);bool _ParseNumber(const _tchar* pData, JsonValue& val, const _tchar** pEnd);bool _ParseUnicodeString(const _tchar* pData, _tstring& val, const _tchar** pEnd);bool _ParseString(const _tchar* pData, _tstring& val, const _tchar** pEnd);bool _ParseObject(const _tchar* pData, JsonValue& val, const _tchar** pEnd);bool _ParseArray(const _tchar* pData, JsonValue& val, const _tchar** pEnd);bool _ParseValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd);// 转储_tstring _Dump(int depth, int indent, bool fEscapeCh) const;_tstring _DumpNull() const;_tstring _DumpBool(bool val) const;_tstring _DumpInt(int64_t val) const;_tstring _DumpUInt(uint64_t val) const;_tstring _DumpDouble(double fNumber) const;_tstring _DumpString(const _tstring& strText, bool fEscapeCh) const;_tstring _DumpObject(int depth, int indent, bool fEscapeCh) const;_tstring _DumpArray(int depth, int indent, bool fEscapeCh) const;private:// JSON 数据union JsonData{JsonBool    Bool;       // 布尔类型          boolJsonInt     Int;        // 有符号整数        int64_tJsonUInt    UInt;       // 无符号整数        uint64_tJsonFloat   Float;      // 浮点数            doubleJsonString* String;     // 字符串指针        std::stringJsonObject* Object;     // 对象类型指针      std::mapJsonArray*  Array;      // 数组类型指针      std::vector}m_Data;                    // 数据JsonType    m_Type;         // 类型(表示当前数据所属类型)};
}

FCJson.cpp

#include "FCJson.h"
#include <cwctype>
#include <fstream>// UTF-8 编码标准
// 
// 1字节 U+0000000 - U+0000007F 0xxxxxxx
// 2字节 U+0000080 - U+000007FF 110xxxxx 10xxxxxx
// 3字节 U+0000800 - U+0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
// 4字节 U+0010000 - U+001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
// 5字节 U+0200000 - U+03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
// 6字节 U+4000000 - U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx// UTF16 编码标准
// 
// 基本多语言平面(U+0000 - U+FFFF)
// 
// 辅助平面(U+10000 - U+10FFFF)
// 1.码位减去 0x10000,得到20位的代理值(0x00 - 0xFFFFF)
// 2.高10位(范围0 - 0x3FF)加 0xD800 得到高位代理(0xD800 - 0xDBFF)
// 3.低10位(范围0 - 0x3FF)加 0xDC00 得到低位代理(0xDC00 - 0xDFFF)namespace FCJson
{
#ifdef _UNICODE#define _istxdigit          std::iswxdigit
#define _istdigit           std::iswdigit
#define _tcsnicmp           _wcsnicmp
#define _tcsncmp            wcsncmp
#define _tcsstr             wcsstr
#define _tcstod             std::wcstod
#define _tcstol             std::wcstol
#define _tcstoll            std::wcstoll
#define _tcstoull            std::wcstoull
#define _stcprintf_s        _scwprintf
#define _stprintf_s         swprintf_s
#define _tisgraph           iswgraph
#else#define _istxdigit          std::iswxdigit
#define _istdigit           std::iswdigit
#define _tcsnicmp           _strnicmp
#define _tcsncmp            strncmp
#define _tcsstr             strstr
#define _tcstod             std::strtod
#define _tcstol             std::strtol
#define _tcstoll            std::strtoll
#define _tcstoull            std::strtoull
#define _stcprintf_s        _scprintf
#define _stprintf_s         sprintf_s
#define _tisgraph           isgraph#endifstatic std::string _CodePointToUtf8(uint32_t cp32);static bool _GetUnicodeCodePoint(const _tchar* pData, uint32_t* pCp, const _tchar** pEnd);static bool _GetUnicodeString(const _tchar* pData, _tstring& val, const _tchar** pEnd);static int32_t _Utf8ToUtf16(const void* pData, size_t size = -1, std::string* pUtf8 = nullptr, std::wstring* pUtf16 = nullptr);static int32_t _Utf16ToUtf8(const void* pData, size_t size = -1, std::string* pUtf8 = nullptr, std::wstring* pUtf16 = nullptr);inline const _tchar* _SkipWhitespace(const _tchar* pData);inline const _tchar* _SkipBom(const _tchar* pData);static bool _SkipDigit(const _tchar* pData, const _tchar** pEnd);JsonValue::JsonValue():m_Data{ 0 },m_Type(JsonType::eNull){}JsonValue::JsonValue(JsonType type) : JsonValue(){m_Type = type;}JsonValue::JsonValue(nullptr_t) : JsonValue(){}JsonValue::JsonValue(JsonBool val){m_Type = JsonType::eBool;m_Data.Bool = val;}JsonValue::JsonValue(int32_t val){m_Type = JsonType::eInt;m_Data.Int = val;}JsonValue::JsonValue(uint32_t val){m_Type = JsonType::eInt;m_Data.UInt = val;}JsonValue::JsonValue(int64_t val){m_Type = JsonType::eInt;m_Data.Int = val;}JsonValue::JsonValue(uint64_t val){m_Type = JsonType::eUInt;m_Data.UInt = val;}JsonValue::JsonValue(JsonFloat val){m_Type = JsonType::eFloat;m_Data.Float = val;}JsonValue::JsonValue(const _tchar* val) : JsonValue(){if (val){m_Type = JsonType::eString;m_Data.String = new (std::nothrow) JsonString(val);}}JsonValue::JsonValue(const JsonString& val){m_Type = JsonType::eString;m_Data.String = new (std::nothrow) JsonString(val);}JsonValue::JsonValue(const JsonObject& val){m_Type = JsonType::eObject;m_Data.Object = new (std::nothrow) JsonObject(val);}JsonValue::JsonValue(const JsonArray& val){m_Type = JsonType::eArray;m_Data.Array = new (std::nothrow) JsonArray(val);}JsonValue::JsonValue(const JsonValue& r){m_Type = r.m_Type;if (JsonType::eString == m_Type && r.m_Data.String){m_Data.String = new (std::nothrow) JsonString(*r.m_Data.String);}else if (JsonType::eObject == m_Type && r.m_Data.Object){m_Data.Object = new (std::nothrow) JsonObject(*r.m_Data.Object);}else if (JsonType::eArray == m_Type && r.m_Data.Array){m_Data.Array = new (std::nothrow) JsonArray(*r.m_Data.Array);}else{m_Data = r.m_Data;}}JsonValue::JsonValue(JsonString&& val){m_Type = JsonType::eString;m_Data.String = new (std::nothrow) JsonString(std::move(val));}JsonValue::JsonValue(JsonObject&& val){m_Type = JsonType::eObject;m_Data.Object = new (std::nothrow) JsonObject(std::move(val));}JsonValue::JsonValue(JsonArray&& val){m_Type = JsonType::eArray;m_Data.Array = new (std::nothrow) JsonArray(std::move(val));}JsonValue::JsonValue(JsonValue&& r) noexcept{m_Type = r.m_Type;m_Data = r.m_Data;r.m_Data = { 0 };r.m_Type = JsonType::eNull;}JsonValue& JsonValue::operator = (JsonType type){if (type != m_Type){Clear();m_Type = type;}return *this;}JsonValue& JsonValue::operator = (JsonBool val){if (JsonType::eBool != m_Type){Clear();m_Type = JsonType::eBool;}m_Data.Bool = val;return *this;}JsonValue& JsonValue::operator = (int32_t val){if (JsonType::eInt != m_Type){Clear();m_Type = JsonType::eInt;}m_Data.Int = val;return *this;}JsonValue& JsonValue::operator = (uint32_t val){if (JsonType::eInt != m_Type){Clear();m_Type = JsonType::eInt;}m_Data.UInt = val;return *this;}JsonValue& JsonValue::operator = (int64_t val){if (JsonType::eInt != m_Type){Clear();m_Type = JsonType::eInt;}m_Data.Int = val;return *this;}JsonValue& JsonValue::operator = (uint64_t val){if (JsonType::eInt != m_Type){Clear();m_Type = JsonType::eUInt;}m_Data.UInt = val;return *this;}JsonValue& JsonValue::operator = (JsonFloat val){if (JsonType::eFloat != m_Type){Clear();m_Type = JsonType::eFloat;}m_Data.Float = val;return *this;}JsonValue& JsonValue::operator = (const _tchar* val){if (JsonType::eString != m_Type){Clear();m_Type = JsonType::eString;}if (nullptr == m_Data.String){m_Data.String = new (std::nothrow) JsonString(val);}return *this;}JsonValue& JsonValue::operator = (const JsonString& val){if (JsonType::eString != m_Type){Clear();m_Type = JsonType::eString;}if (nullptr == m_Data.String){m_Data.String = new (std::nothrow) JsonString(val);}return *this;}JsonValue& JsonValue::operator = (const JsonObject& val){if (JsonType::eObject != m_Type){Clear();m_Type = JsonType::eObject;}if (nullptr == m_Data.Object){m_Data.Object = new (std::nothrow) JsonObject(val);}return *this;}JsonValue& JsonValue::operator = (const JsonArray& val){if (JsonType::eArray != m_Type){Clear();m_Type = JsonType::eArray;}if (nullptr == m_Data.Array){m_Data.Array = new (std::nothrow) JsonArray(val);}return *this;}JsonValue& JsonValue::operator = (const JsonValue& r){if (&r != this){Clear();m_Type = r.m_Type;if (JsonType::eString == m_Type && r.m_Data.String){m_Data.String = new (std::nothrow) JsonString(*r.m_Data.String);}else if (JsonType::eObject == m_Type && r.m_Data.Object){m_Data.Object = new (std::nothrow) JsonObject(*r.m_Data.Object);}else if (JsonType::eArray == m_Type && r.m_Data.Array){m_Data.Array = new (std::nothrow) JsonArray(*r.m_Data.Array);}else{m_Data = r.m_Data;}}return *this;}JsonValue& JsonValue::operator = (JsonString&& val){if (JsonType::eString != m_Type){Clear();m_Type = JsonType::eString;}if (nullptr == m_Data.String){m_Data.String = new (std::nothrow) JsonString(std::move(val));}return *this;}JsonValue& JsonValue::operator = (JsonObject&& val){if (JsonType::eObject != m_Type){Clear();m_Type = JsonType::eObject;}if (nullptr == m_Data.Object){m_Data.Object = new (std::nothrow) JsonObject(std::move(val));}return *this;}JsonValue& JsonValue::operator = (JsonArray&& val){if (JsonType::eArray != m_Type){Clear();m_Type = JsonType::eArray;}if (nullptr == m_Data.Array){m_Data.Array = new (std::nothrow) JsonArray(std::move(val));}return *this;}JsonValue& JsonValue::operator = (JsonValue&& r) noexcept{if (&r != this){Clear();m_Type = r.m_Type;m_Data = r.m_Data;r.m_Data = { 0 };r.m_Type = JsonType::eNull;}return *this;}JsonValue& JsonValue::operator[](const _tstring& name){if (!IsObject()){throw JsonException(_T("operator[] JsonType::eObject == m_Type"));}if (nullptr == m_Data.Object){m_Data.Object = new (std::nothrow) JsonObject;if (nullptr == m_Data.Object){throw JsonException(_T("operator[] nullptr == m_Data.Object"));}}auto itFind = m_Data.Object->find(name);if (m_Data.Object->end() != itFind){return itFind->second;}auto insertResult = m_Data.Object->insert(std::make_pair(name, JsonValue()));return insertResult.first->second;}JsonValue& JsonValue::operator[](const size_t index){if (JsonType::eArray != m_Type){throw JsonException(_T("operator[] JsonType::eArray == m_Type"));}if (nullptr == m_Data.Array){m_Data.Array = new (std::nothrow) JsonArray;if (nullptr == m_Data.Array){throw JsonException(_T("operator[] nullptr == m_Data.Array"));}}if (m_Data.Array->size() <= index){m_Data.Array->resize(index + 1);}return (*m_Data.Array)[index];}JsonValue::~JsonValue(){Clear();}JsonType JsonValue::GetType() const{return m_Type;}_tstring JsonValue::GetTypeName() const{if (JsonType::eNull == m_Type) return _T("Null");if (JsonType::eBool == m_Type) return _T("Bool");if (JsonType::eInt == m_Type) return _T("Integer");if (JsonType::eUInt == m_Type) return _T("Unsigned Integer");if (JsonType::eFloat == m_Type) return _T("Float");if (JsonType::eString == m_Type) return _T("String");if (JsonType::eObject == m_Type) return _T("Object");if (JsonType::eArray == m_Type) return _T("Array");return _T("None");}bool JsonValue::IsObjectOrArray() const{return IsObject() || IsArray();}bool JsonValue::IsNull() const{return JsonType::eNull == m_Type;}bool JsonValue::IsBool() const{return JsonType::eBool == m_Type;}bool JsonValue::IsInt() const{return JsonType::eInt == m_Type || JsonType::eUInt == m_Type;}bool JsonValue::IsFloat() const{return JsonType::eFloat == m_Type;}bool JsonValue::IsString() const{return JsonType::eString == m_Type;}bool JsonValue::IsObject() const{return JsonType::eObject == m_Type;}bool JsonValue::IsArray() const{return JsonType::eArray == m_Type;}JsonBool JsonValue::AsBool() const{if (!JsonType::eBool == m_Type){throw JsonException(_T("AsBool(): JsonType::eBool == m_Type"));}return m_Data.Bool;}JsonInt JsonValue::AsInt() const{if (!(JsonType::eInt == m_Type || JsonType::eUInt == m_Type)){throw JsonException(_T("AsInt(): JsonType::eInteger == m_Type"));}return m_Data.Int;}JsonUInt JsonValue::AsUInt() const{if (!(JsonType::eInt == m_Type || JsonType::eUInt == m_Type)){throw JsonException(_T("AsInt(): JsonType::eInteger == m_Type"));}return m_Data.UInt;}JsonFloat JsonValue::AsFloat() const{if (!JsonType::eFloat == m_Type){throw JsonException(_T("AsFloat(): JsonType::eFloat == m_Type"));}return m_Data.Float;}JsonString JsonValue::AsString() const{if (!JsonType::eString == m_Type){throw JsonException(_T("AsString(): JsonType::eString == m_Type"));}return *m_Data.String;}JsonObject JsonValue::AsObject() const{if (!JsonType::eObject == m_Type){throw JsonException(_T("AsObject(): JsonType::eObject == m_Type"));}return *m_Data.Object;}JsonArray JsonValue::AsArray() const{if (!JsonType::eArray == m_Type){throw JsonException(_T("AsArray(): JsonType::eArray == m_Type"));}return *m_Data.Array;}void JsonValue::Clear(){if (JsonType::eNull == m_Type){return;}if (m_Data.String && JsonType::eString == m_Type){delete m_Data.String;}else if (m_Data.Object && JsonType::eObject == m_Type){delete m_Data.Object;}else if (m_Data.Array && JsonType::eArray == m_Type){delete m_Data.Array;}m_Data = { 0 };m_Type = JsonType::eNull;}size_t JsonValue::Count(const _tstring& name) const{if (name.empty()){if (JsonType::eObject == m_Type && m_Data.Object){return m_Data.Object->size();}if (JsonType::eArray == m_Type && m_Data.Array){return m_Data.Array->size();}return 1;}auto itFind = m_Data.Object->find(name);if (m_Data.Object->end() == itFind){return 0;}return itFind->second.Count();}bool JsonValue::_ParseNumber(const _tchar* pData, JsonValue& val, const _tchar** pEnd){// [-]?[0-9]+\.[0-9]+[eE]?[-+]?[0-9]+const _tchar* pStart = pData;bool fNegative = false;bool fDot = false;bool fExponent = false;bool fResult = false;do{// 符号if (_T('-') == *pData){fNegative = true;pData++;}// 数字部分if (!_SkipDigit(pData, &pData)){fResult = false;break;}//小数点if (_T('.') == *pData){fDot = true;pData++;}// 小数部分if (fDot){if (!_SkipDigit(pData, &pData)){break;}}// 指数部分if (_T('E') == *pData || _T('e') == *pData){fExponent = true;pData++;// 指数符号if (_T('-') == *pData || _T('+') == *pData){pData++;}if (!_SkipDigit(pData, &pData)){break;}}_tstring strNumber(pStart, pData - pStart);// 存在小数点或指数, 则使用浮点数if (fDot || fExponent){val = _tcstod(strNumber.c_str(), nullptr);}else{if (fNegative){val = _tcstoll(strNumber.c_str(), nullptr, 10);}else{val = _tcstoull(strNumber.c_str(), nullptr, 10);}// 超出范围则使用浮点数if (ERANGE == errno){val = _tcstod(strNumber.c_str(), nullptr);errno = 0;}}fResult = true;} while (false);if (pEnd){*pEnd = pData;}return fResult;}bool JsonValue::_ParseUnicodeString(const _tchar* pData, _tstring& val, const _tchar** pEnd){uint32_t cp32 = 0;bool fResult = false;do{if (!_GetUnicodeCodePoint(pData, &cp32, &pData)){break;}// 高位if (cp32 >= 0xD800 && cp32 <= 0xDBFF){cp32 -= 0xD800;if (0 != _tcsncmp(_T(R"(\u)"), pData, 2)){break;}pData += 2;uint32_t cpLo = 0;if (!_GetUnicodeCodePoint(pData, &cpLo, &pData)){break;}// 低位if (cpLo >= 0xDC00 && cpLo <= 0xDFFF){cpLo -= 0xDC00;cp32 = 0x10000 + ((cp32 << 10) | cpLo);
#ifdef _UNICODEuint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;val.push_back(cp32Hi);val.push_back(cp32Lo);
#elseval += _CodePointToUtf8(cp32);
#endif}else{break;}}else{
#ifdef _UNICODEval.push_back((_tchar)cp32);
#elseval += _CodePointToUtf8(cp32);
#endif}fResult = true;} while (false);if (pEnd){*pEnd = pData;}return fResult;}bool JsonValue::_ParseString(const _tchar* pData, _tstring& val, const _tchar** pEnd){const _tchar* pStart = pData;bool fAbort = false;pData = _SkipWhitespace(pData);if (_T('\"') != *pData){return false;}pData++;pStart = pData;while (_T('\0') != *pData){_tchar ch = *pData;if (_T('\"') == ch){break;}if (_T('\\') == ch){pData++;ch = *pData;switch (ch){case _T('\"'):{val.push_back(_T('\"'));}break;case _T('\\'):{val.push_back(_T('\\'));}break;case _T('/'):{val.push_back(_T('/'));}break;case _T('b'):{val.push_back(_T('\b'));}break;case _T('n'):{val.push_back(_T('\n'));}break;case _T('r'):{val.push_back(_T('\r'));}break;case _T('t'):{val.push_back(_T('\t'));}break;case _T('u'):{pData++;if (!_ParseUnicodeString(pData, val, &pData)){fAbort = true;break;}continue;}break;default:pData--;fAbort = true;break;}}else{val.push_back(ch);}if (fAbort){break;}pData++;}if (_T('\"') != *pData || fAbort){*pEnd = pData;return false;}pData++;if (pEnd){*pEnd = pData;}return true;}_tstring JsonValue::_DumpString(const _tstring& strText, bool fEscapeCh) const{const _tchar* pData = strText.c_str();_tstring strResult;strResult.reserve(strText.size());while (_T('\0') != *pData){_utchar ch = *pData;if (_T('\"') == ch){strResult += _T(R"(\")");}else if (_T('\\') == ch){strResult += _T(R"(\\)");}else if (_T('/') == ch){strResult += _T(R"(/)");}else if (_T('\b') == ch){strResult += _T(R"(\b)");}else if (_T('\f') == ch){strResult += _T(R"(\f)");}else if (_T('\n') == ch){strResult += _T(R"(\n)");}else if (_T('\r') == ch){strResult += _T(R"(\r)");}else if (_T('\t') == ch){strResult += _T(R"(\t)");}else{if (ch < 0x80 || !fEscapeCh){strResult.push_back(ch);}else{_GetUnicodeString(pData, strResult, &pData);continue;}}pData++;}return strResult;}_tstring JsonValue::_DumpObject(int depth, int indent, bool fEscapeCh) const{_tstring strResult(_T("{"));if (indent > 0){depth++;_tstring strIndent(depth * indent, _T(' '));JsonObject& jsonObject = *m_Data.Object;size_t size = jsonObject.size();strResult += _T(FC_JSON_RETURN);for (const auto& item : jsonObject){strResult += strIndent;strResult += _T("\"");strResult += std::move(_DumpString(item.first, fEscapeCh));strResult += _T("\": ");strResult += std::move(item.second._Dump(depth, indent, fEscapeCh));size--;if (0 != size){strResult += _T(",");}strResult += _T(FC_JSON_RETURN);}depth--;strResult += _tstring(depth * indent, _T(' '));strResult += _T("}");}else{JsonObject& jsonObject = *m_Data.Object;size_t size = jsonObject.size();depth++;for (const auto& item : jsonObject){strResult += _T("\"");strResult += std::move(_DumpString(item.first, fEscapeCh));strResult += _T("\":");strResult += std::move(item.second._Dump(depth, indent, fEscapeCh));size--;if (0 != size){strResult += _T(",");}}depth--;strResult += _T("}");}return strResult;}_tstring JsonValue::_DumpArray(int depth, int indent, bool fEscapeCh) const{_tstring strResult(_T("["));if (indent > 0){depth++;_tstring strIndent(depth * indent, _T(' '));JsonArray& jsonArray = *(JsonArray*)m_Data.Array;size_t size = jsonArray.size();strResult += _T(FC_JSON_RETURN);for (const auto& item : jsonArray){strResult += strIndent;strResult += std::move(item._Dump(depth, indent, fEscapeCh));size--;if (0 != size){strResult += _T(",");}strResult += _T(FC_JSON_RETURN);}depth--;strResult += _tstring(depth * indent, _T(' '));strResult += _T("]");}else{JsonArray& jsonArray = *(JsonArray*)m_Data.Array;size_t size = jsonArray.size();depth++;for (const auto& item : jsonArray){strResult += std::move(item._Dump(depth, indent, fEscapeCh));size--;if (0 != size){strResult += _T(",");}}depth--;strResult += _T("]");}return strResult;}_tstring JsonValue::_DumpNull() const{return _T("null");}_tstring JsonValue::_DumpBool(bool val) const{return val ? _T("true") : _T("false");}_tstring JsonValue::_DumpInt(int64_t val) const{const auto length = static_cast<size_t>(_scprintf("%lld", val));_tstring strResult(length, '\0');_stprintf_s(&strResult[0], length + 1, "%lld", val);return strResult;}_tstring JsonValue::_DumpUInt(uint64_t val) const{const auto length = static_cast<size_t>(_scprintf("%llu", val));_tstring strResult(length, '\0');_stprintf_s(&strResult[0], length + 1, "%llu", val);return strResult;}_tstring JsonValue::_DumpDouble(double fNumber) const{const auto length = static_cast<size_t>(_scprintf("%.16g", fNumber));_tstring strResult(length, '\0');_stprintf_s(&strResult[0], length + 1, "%.16g", fNumber);if (_tstring::npos == strResult.find(_T('e')) && _tstring::npos == strResult.find(_T('.'))){strResult += _T(".0");}return strResult;}_tstring JsonValue::_Dump(int depth, int indent, bool fEscapeCh) const{if (indent < 0){indent = 0;}_tstring strResult;if (IsArray()){if (nullptr == m_Data.Array){return _T("[]");}JsonArray& jsonArray = *m_Data.Array;if (jsonArray.empty()){return _T("[]");}}if (IsObject()){if (nullptr == m_Data.Object){return _T("{}");}JsonObject& jsonObject = *m_Data.Object;if (jsonObject.empty()){return _T("{}");}}if (IsNull()){strResult = std::move(_DumpNull());}else if (IsBool()){strResult = std::move(_DumpBool(m_Data.Bool));}else if (JsonType::eInt == m_Type){strResult = std::move(_DumpInt(m_Data.Int));}else if (JsonType::eUInt == m_Type){strResult = std::move(_DumpUInt(m_Data.UInt));}else if (IsFloat()){strResult = std::move(_DumpDouble(m_Data.Float));}else if (IsString()){strResult += _T("\"");strResult += std::move(_DumpString(*m_Data.String, fEscapeCh));strResult += _T("\"");}else if (IsObject()){strResult += std::move(_DumpObject(depth, indent, fEscapeCh));}else if (IsArray()){strResult += std::move(_DumpArray(depth, indent, fEscapeCh));}return strResult;}_tstring JsonValue::Dump(int indent/* = 0*/, bool fEscapeCh/* = false*/) const{return _Dump(0, indent, fEscapeCh);}bool JsonValue::DumpFile(const _tstring& strPath, int indent/* = 0*/, bool fEscapeCh/* = false*/, JsonEncoding encoding/* = JsonEncoding::eAuto*/){std::string strUnicode8;std::wstring strUnicode16;_tstring strResult;_tstring strText = std::move(_Dump(0, indent, fEscapeCh));if (!IsObjectOrArray()){return false;}//strUnicode8.push_back((uint8_t)0xEF);//strUnicode8.push_back((uint8_t)0xBB);//strUnicode8.push_back((uint8_t)0xBF);strUnicode16.push_back((uint16_t)0xFEFF);std::ofstream outputFile(strPath, std::ios::binary | std::ios::out);if (!outputFile.is_open()){return false;}#ifdef _UNICODEstrResult = strUnicode16;if (JsonEncoding::eUtf16 == encoding || JsonEncoding::eAuto == encoding){strResult += strText;outputFile.write((const char*)strResult.data(), strResult.size() * sizeof(_tchar));outputFile.close();}if (JsonEncoding::eUtf8 == encoding){int32_t nU8Length = _Utf16ToUtf8(strText.c_str(), (size_t)-1, &strUnicode8, nullptr);if (nU8Length >= 0){outputFile.write((const char*)strUnicode8.data(), strUnicode8.size() * sizeof(char));outputFile.close();}}#elsestrResult = strUnicode8;if (JsonEncoding::eUtf8 == encoding || JsonEncoding::eAuto == encoding){strResult += strText;outputFile.write((const char*)strResult.data(), strResult.size() * sizeof(_tchar));outputFile.close();}if (JsonEncoding::eUtf16 == encoding){int32_t nU8Length = _Utf8ToUtf16(strText.c_str(), (size_t)-1, nullptr, &strUnicode16);if (nU8Length >= 0){outputFile.write((const char*)strUnicode16.data(), strUnicode16.size() * sizeof(wchar_t));outputFile.close();}}#endifreturn true;}JsonValue JsonValue::Parse(const _tstring& strText){const _tchar* pEnd = nullptr;*this = std::move(_Parse(strText.c_str(), &pEnd));return *this;}JsonValue JsonValue::ParseFile(const _tstring& strPath){std::string strUnicode8;std::wstring strUnicode16;_tstring strText;*this = JsonType::eNull;do{std::ifstream inputFile(strPath, std::ios::binary | std::ios::in);if (!inputFile.is_open()){return *this;}inputFile.seekg(0, std::ios::end);std::streamoff nSize = inputFile.tellg();inputFile.seekg(0, std::ios::beg);std::string strBuffer(nSize, 0);inputFile.read((char*)&strBuffer[0], nSize);size_t nByteSize = (size_t)inputFile.gcount();inputFile.close();if (0 == nByteSize){break;}int32_t nU8Length = _Utf8ToUtf16(strBuffer.data(), strBuffer.size(), &strUnicode8, &strUnicode16);#ifdef _UNICODEif (nU8Length > 0){strText = strUnicode16;break;}
#elseif (nU8Length > 0){strText = strUnicode8;break;}
#endifint32_t nU16Length = _Utf16ToUtf8(strBuffer.data(), strBuffer.size(), &strUnicode8, &strUnicode16);#ifdef _UNICODEif (nU16Length > 0){strText = strUnicode16;break;}
#elseif (nU16Length > 0){strText = strUnicode8;break;}
#endif} while (false);const _tchar* pEnd = nullptr;*this = _Parse(strText.c_str(), &pEnd);return *this;}bool _SkipDigit(const _tchar* pData, const _tchar** pEnd){if (0 == _istdigit(*pData)){return false;}while (_istdigit(*pData)){pData++;}*pEnd = pData;return true;}bool JsonValue::_ParseObject(const _tchar* pData, JsonValue& val, const _tchar** pEnd){JsonValue valResult(JsonType::eObject);bool fResult = false;if (_T('{') == *pData){pData++;}while (_T('\0') != *pData){_tstring strName;JsonValue jsonValue;pData = _SkipWhitespace(pData);if (_T('}') == *pData){fResult = true;pData++;break;}if (!_ParseString(pData, strName, &pData)){break;}pData = _SkipWhitespace(pData);if (_T(':') != *pData){break;}pData++;if (!_ParseValue(pData, jsonValue, &pData)){break;}valResult[strName] = std::move(jsonValue);pData = _SkipWhitespace(pData);if (_T(',') == *pData){pData++;}else if (_T('}') == *pData){fResult = true;pData++;break;}else{break;}}if (fResult){val = std::move(valResult);}if (pEnd){*pEnd = pData;}return true;}bool JsonValue::_ParseArray(const _tchar* pData, JsonValue& val, const _tchar** pEnd){JsonValue valResult(JsonType::eArray);bool fResult = false;if (_T('[') == *pData){pData++;}size_t nIndex = 0;while (_T('\0') != *pData){JsonValue jsonValue;pData = _SkipWhitespace(pData);if (_T(']') == *pData){fResult = true;pData++;break;}if (!_ParseValue(pData, jsonValue, &pData)){break;}if (nullptr == valResult.m_Data.Array){valResult.m_Data.Array = new (std::nothrow) JsonArray;if (nullptr == valResult.m_Data.Array){continue;}}JsonArray& jsonArray = *valResult.m_Data.Array;if (jsonArray.size() <= nIndex){jsonArray.resize(nIndex + 1);}jsonArray[nIndex] = std::move(jsonValue);pData = _SkipWhitespace(pData);if (_T(',') == *pData){pData++;}else if (_T(']') == *pData){fResult = true;pData++;break;}else{break;}nIndex++;}if (fResult){val = std::move(valResult);}if (pEnd){*pEnd = pData;}return fResult;}bool JsonValue::_ParseValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd){pData = _SkipWhitespace(pData);bool fResult = false;_tchar ch = 0;do{ch = *pData;if (_T('{') == ch){if (!_ParseObject(pData, val, &pData)){break;}}else if (_T('[') == ch){if (!_ParseArray(pData, val, &pData)){break;}}else{pData = _SkipWhitespace(pData);ch = *pData;if (_T('\"') == ch){_tstring strValue;if (!_ParseString(pData, strValue, &pData)){break;}val = std::move(strValue);}else if (0 == _tcsncmp(_T("null"), pData, 4)){val = JsonValue(JsonType::eNull);pData += 4;}else if(0 == _tcsncmp(_T("true"), pData, 4)){val = true;pData += 4;}else if(0 == _tcsncmp(_T("false"), pData, 5)){val = false;pData += 5;}else if (_T('-') == ch || _istdigit(ch)){if (!_ParseNumber(pData, val, &pData)){break;}}else{break;}}fResult = true;} while (false);if (*pEnd){*pEnd = pData;}return fResult;}JsonValue JsonValue::_Parse(const _tchar* pData, const _tchar** pEnd){JsonValue valResult;pData = _SkipBom(pData);_ParseValue(pData, valResult, &pData);if (_T('\0') != *pData){valResult = JsonType::eNull;}if (pEnd){*pEnd = pData;}return valResult;}inline const _tchar* _SkipWhitespace(const _tchar* pData){while (_T('\0') != *pData){if (*pData > _T(' ')){break;}pData++;}return pData;}inline const _tchar* _SkipBom(const _tchar* pData){
#ifdef _UNICODEwhile (0xFEFF == *pData){pData++;}#elsewhile (nullptr != _tcsstr(pData, "\xEF\xBB\xBF")){pData += 3;}#endifreturn pData;}bool _GetUnicodeCodePoint(const _tchar* pData, uint32_t* pCp, const _tchar** pEnd){_tchar szBuf[16] = { 0 };_tchar* pChEnd = nullptr;bool fResult = false;do{int count = 0;for (count = 0; count < 4; count++){_tchar ch = *pData;if (0 == _istxdigit(ch)){break;}szBuf[count] = ch;pData++;}if (4 != count){break;}if (pCp){*pCp = _tcstol(szBuf, &pChEnd, 16);}fResult = true;} while (false);if (pEnd){*pEnd = pData;}return fResult;}bool _GetUnicodeString(const _tchar* pData, _tstring& val, const _tchar** pEnd){_utchar ch = *pData;#ifdef _UNICODE_tchar szBuf[32] = { 0 };_stprintf_s(szBuf, sizeof(szBuf) / sizeof(_tchar), _T(R"(\u%0.4x)"), ch);val += szBuf;pData++;#elseif (ch >= 0xC0){uint8_t u8CodeMask = 0xC0;     // 11000000uint8_t u8DataMask = 0x1F;      // 000xxxxxint nCount = 2;                 // 有效字节数量: 2-6// 检索字符使用的字节数量size_t nByteCount = 0;uint32_t cp32 = 0;while (u8CodeMask <= 0xFC){uint8_t u8MaskMax = u8CodeMask | u8DataMask;if (ch >= u8CodeMask && ch <= u8MaskMax){cp32 = ch & u8DataMask;nByteCount = nCount;break;}u8CodeMask = (u8CodeMask >> 1) | 0x80;u8DataMask = u8DataMask >> 1;nCount++;}if (0 == nByteCount){return false;}for (size_t i = 1; i < nByteCount; i++){cp32 = cp32 << 6;cp32 |= pData[i] & 0x3F;}char szBuf[32] = { 0 };if (cp32 < 0x10000){sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32);val += szBuf;}else{uint32_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32Hi);val += szBuf;sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32Lo);val += szBuf;}pData += nByteCount;}
#endifif (pEnd){*pEnd = pData;}return false;}std::string _CodePointToUtf8(uint32_t cp32){char szBuf[16] = { 0 };// 1字节 0xxxxxxxif (cp32 >= 0x00000000 && cp32 <= 0x0000007F){szBuf[0] = (uint8_t)cp32;szBuf[1] = 0;}// 2字节 110xxxxx 10xxxxxxif (cp32 >= 0x00000080 && cp32 <= 0x000007FF){szBuf[0] = ((cp32 >>  6) & 0x1F) | 0xC0;szBuf[1] = ((cp32 & 0x3F)) | 0x80;szBuf[2] = 0;}// 3字节 1110xxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00000800 && cp32 <= 0x0000FFFF){szBuf[0] = ((cp32 >> 12) & 0x0F) | 0xE0;szBuf[1] = ((cp32 >>  6) & 0x3F) | 0x80;szBuf[2] = ((cp32 & 0x3F)) | 0x80;szBuf[3] = 0;}// 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00010000 && cp32 <= 0x001FFFFF){szBuf[0] = ((cp32 >> 18) & 0x07) | 0xF0;szBuf[1] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[2] = ((cp32 >>  6) & 0x3F) | 0x80;szBuf[3] = ((cp32 & 0x3F)) | 0x80;szBuf[4] = 0;}// 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00200000 && cp32 <= 0x03FFFFFF){szBuf[0] = ((cp32 >> 24) & 0x03) | 0xF8;szBuf[1] = ((cp32 >> 18) & 0x3F) | 0x80;szBuf[2] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[3] = ((cp32 >>  6) & 0x3F) | 0x80;szBuf[4] = ((cp32 & 0x3F)) | 0x80;szBuf[5] = 0;}// 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x04000000 && cp32 <= 0x7FFFFFFF){szBuf[0] = ((cp32 >> 30) & 0x01) | 0xFC;szBuf[1] = ((cp32 >> 24) & 0x3F) | 0x80;szBuf[2] = ((cp32 >> 18) & 0x3F) | 0x80;szBuf[3] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[4] = ((cp32 >>  6) & 0x3F) | 0x80;szBuf[5] = ((cp32 & 0x3F)) | 0x80;szBuf[6] = 0;}return szBuf;}int32_t _Utf8ToUtf16(const void* pData, size_t size/* = -1*/, std::string* pUtf8/* = nullptr*/, std::wstring* pUtf16/* = nullptr*/){const uint8_t* pCpData = (const uint8_t*)pData;std::wstring strOut16;      // 输出UTF16std::string strOut8;        // 输出UTF8uint32_t cp32 = 0;          // UNICODE码点int32_t nByteCount = 0;     // 字节计数int32_t nChCount = 0;       // 字符计数bool fResult = true;        // 操作结果bool fBom = true;           // BOM(Byte Order Mark)if (pUtf8){strOut8 += *pUtf8;}if (pUtf16){strOut16 += *pUtf16;}while ((0 != *pCpData) && (0 != size)){uint8_t ch = *pCpData;// 普通 Ascii 也是 UTF-8 一部分if (ch < 0x7F){cp32 = ch;nChCount++;}else{// 检查 UTF-8 首字节if (0 == nByteCount){cp32 = 0;if (ch >= 0xC0){uint8_t u8CodeMask  = 0xC0;     // 11000000uint8_t u8DataMask = 0x1F;      // 000xxxxxint nCount = 2;                 // 有效字节数量: 2-6// 检索字符使用的字节数量while(u8CodeMask <= 0xFC){uint8_t u8MaskMax = u8CodeMask | u8DataMask;if (ch >= u8CodeMask && ch <= u8MaskMax){cp32 = ch & u8DataMask;nByteCount = nCount;break;}u8CodeMask = (u8CodeMask >> 1) | 0x80;u8DataMask = u8DataMask >> 1;nCount++;}if (0 == nByteCount){fResult = false;break;}if (0xEF == ch && 3 == nByteCount){fBom = true;}nByteCount--;}else{fResult = false;break;}}else{// 非首字节掩码: 10xxxxxxif (0x80 != (ch & 0xC0)){fResult = false;break;}// BOM处理if (fBom){if (0xBB != ch && 2 == nByteCount){fBom = false;}if (0xBF != ch && 1 == nByteCount){fBom = false;}}cp32 = cp32 << 6;cp32 |= ch & 0x3F;nByteCount--;if (0 == nByteCount){// 跳过BOMif (fBom){fBom = false;pCpData++;continue;}nChCount++;}}}if (0 == nByteCount){if (pUtf8){strOut8 += _CodePointToUtf8(cp32);}if (pUtf16){if (cp32 < 0x10000){strOut16.push_back((uint16_t)(cp32 & 0xFFFF));}else{uint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;strOut16.push_back(cp32Hi);strOut16.push_back(cp32Lo);}}}pCpData++;if (-1 != size){size--;}}if (!fResult){return -1;}if (pUtf8){*pUtf8 = std::move(strOut8);}if (pUtf16){*pUtf16 = std::move(strOut16);}return nChCount;}int32_t _Utf16ToUtf8(const void* pData, size_t size/* = -1*/, std::string* pUtf8/* = nullptr*/, std::wstring* pUtf16/* = nullptr*/){const uint16_t* pCpData = (const uint16_t*)pData;std::wstring strOut16;          // 输出UTF16std::string strOut8;            // 输出UTF8uint32_t cp32 = 0;              // 32位码点uint16_t cp32Hi = 0;            // 32位码点高10位uint16_t cp32Lo = 0;            // 32位码点低10位uint16_t cp16 = 0;              // 16位码点int32_t nByteCount = 0;         // 字节计数int32_t nChCount = 0;           // 字符计数bool fBigEndian = false;        // 是否大端字节序bool fLittleEndian = false;     // 是否小端字节序bool fResult = true;            // 操作结果if (pUtf8){strOut8 += *pUtf8;}if (pUtf16){strOut16 += *pUtf16;}if (-1 != size){if ((size < 2) || (0 != (size % 2))){return -1;}}while ((0 != *pCpData) && (0 != size)){cp16 = *pCpData;// BOM检查if (0xFFFE == cp16 || 0xFEFF == cp16){if (0 == nByteCount){if (0xFFFE == cp16) // 大端字节序 (Big Endian){fBigEndian = true;}if (0xFEFF == cp16) // 小端字节序 (Little Endian){fLittleEndian = true;}}else{fResult = false;break;}// 不可能同时存在两种字节序if (fBigEndian && fLittleEndian){fResult = false;break;}pCpData++;if (-1 != size){size -= 2;}continue;}if (fBigEndian){cp16 = ((cp16 >> 8) | (cp16 << 8));}//检查是否为基本多语言平面(U+0000 - U+FFFF)if (!(cp16 >= 0xD800 && cp16 <= 0xDFFF)){if (cp32Hi > 0) // 高位码点后必须跟着低位码点{fResult = false;break;}cp32 = cp16;nChCount++;}else{if (0 == nByteCount){//检查是否为辅助平面(U+10000 - U+10FFFF)if (cp16 >= 0xD800 && cp16 <= 0xDBFF)   //检查高位代理(0xD800 - 0xDBFF){cp32Hi = (cp16 - 0xD800);nByteCount = 1;}else{fResult = false;break;}}else{if (1 == nByteCount) // 高位码点后必须接着低位码点{if ((cp16 >= 0xDC00) && (cp16 <= 0xDFFF))   //检查低位代理(0xDC00 - 0xDFFF){cp32Lo = (cp16 - 0xDC00);cp32 = 0x10000 + ((uint32_t)cp32Hi << 10 | cp32Lo);cp32Lo = 0;cp32Hi = 0;}else{fResult = false;break;}}nByteCount--;if (0 == nByteCount){nChCount++;}}}// 转换为 UTF 编码if (0 == nByteCount){if (pUtf8){strOut8 += _CodePointToUtf8(cp32);}if (pUtf16){if (cp32 < 0x10000){strOut16.push_back((uint16_t)(cp32 & 0xFFFF));}else{uint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cpHi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cpLo = (uint16_t)(cp & 0x3FF) + 0xDC00;strOut16.push_back(cpHi);strOut16.push_back(cpLo);}}}pCpData++;if (-1 != size){size -= 2;}}if (!fResult){return -1;}if (pUtf8){*pUtf8 = std::move(strOut8);}if (pUtf16){*pUtf16 = std::move(strOut16);}return nChCount;}
}

main.cpp

#include <iostream>
#include <tchar.h>
#include <locale>
#include <string>
#include <fstream>
#include "FCJson.h"
#include "include/nlohmann/json.hpp"
#include "include/configor/json.hpp"#pragma execution_character_set("utf-8")#if  0
#define TEST_JSON_FILE  "data.json"
#else
#define TEST_JSON_FILE  "city_4.json"
#endif
int count = 1;
int dump_indent = 0;int main()
{std::string strUtf8 = "我是地球🌍";std::wstring strUtf16 = L"我是地球🌍";size_t nCount = count;clock_t timeBegin = clock();clock_t timeEnd = clock();{// 构造jsonnlohmann::json nlohmannJson = {{ "null", nullptr},{ "bool_false", false },{ "bool_true", true },{ "int_min", INT64_MIN },{ "int_max", INT64_MAX },{ "float", 3.1415926535 },{ "object", {{ "name", "FlameCyclone" },{ "age", 30 }},},{ "array", {nullptr,false, true, INT64_MIN, INT64_MAX, 3.1415926535}}};std::string strUtf8 = R"({"aaa":"\u6211\u662f\u5730\u7403\ud83c\udf0d"})";nlohmannJson = nlohmann::json::parse(strUtf8);// 序列化std::string nlohmannDump = nlohmannJson.dump(4);std::cout << nlohmannDump << std::endl;}{// 构造jsonFCJson::JsonValue fcJson = FCJson::JsonObject{{ "null", nullptr},{ "bool_false", false },{ "bool_true", true },{ "int_min", INT64_MIN },{ "int_max", INT64_MAX },{ "float", 3.1415926535 },{ "object", FCJson::JsonObject{{ "name", "我是地球🌍" },{ "age", 30 }},},{ "array", FCJson::JsonArray{nullptr,false, true, INT64_MIN, INT64_MAX, 3.1415926535}}};// 序列化std::string strJson = fcJson.Dump(4, true);std::cout << strJson << std::endl;}{// 构造jsonconfigor::json::value configorJson = configor::json::object{{ "null", nullptr},{ "bool_false", false },{ "bool_true", true },{ "int_min", INT64_MIN },{ "int_max", INT64_MAX },{ "float", 3.1415926535 },{ "object", configor::json::object{{ "name", "FlameCyclone" },{ "age", 30 }},},{ "array", configor::json::array{nullptr,false, true, INT64_MIN, INT64_MAX, 3.1415926535}}};// 序列化std::string configorDump = configor::json::dump(configorJson);std::cout << configorDump << std::endl;}setlocale(LC_ALL, "");std::ifstream inputFile(TEST_JSON_FILE, std::ios::binary | std::ios::in);if (!inputFile.is_open()){return -1;}inputFile.seekg(0, std::ios::end);std::streamoff nSize = inputFile.tellg();inputFile.seekg(0, std::ios::beg);std::string strBuffer(nSize, 0);inputFile.read((char*)&strBuffer[0], nSize);size_t nByteSize = (size_t)inputFile.gcount();inputFile.close();// 性能对比while (true){{nlohmann::json nlohmannJson;std::cout << "nlohmann" << std::endl;timeBegin = clock();for (int i = 0; i < nCount; i++){nlohmannJson = nlohmann::json::parse(strBuffer);}timeEnd = clock();std::cout << "nlohmann parse cost time: " << timeEnd - timeBegin << std::endl;timeBegin = clock();std::string nlohmannDump;if (dump_indent > 0){for (int i = 0; i < nCount; i++){nlohmannDump = nlohmannJson.dump(dump_indent);}}else{for (int i = 0; i < nCount; i++){nlohmannDump = nlohmannJson.dump();}}timeEnd = clock();std::cout << "nlohmann dump cost time: " << timeEnd - timeBegin << std::endl;std::cout << "nlohmann size: " << nlohmannDump.size() << std::endl;{std::ofstream outputFile("nlohmann.json", std::ios::binary | std::ios::out);if (outputFile.is_open()){outputFile.write(nlohmannDump.data(), nlohmannDump.size());}}std::cout << std::endl;}{FCJson::JsonValue fcJson;fcJson.ParseFile(_T("data.json"));std::string fcDump2 = fcJson.Dump(4);fcJson.DumpFile(_T("data_out_0.json"), 4, false);fcJson.DumpFile(_T("data_out_1.json"), 4, true);std::cout << "FCJson" << std::endl;timeBegin = clock();for (int i = 0; i < nCount; i++){fcJson.Parse(strBuffer);}timeEnd = clock();std::cout << "FCJson parse cost time: " << timeEnd - timeBegin << std::endl;timeBegin = clock();std::string fcDump;for (int i = 0; i < nCount; i++){fcDump = fcJson.Dump(dump_indent);}timeEnd = clock();std::cout << "FCJson dump cost time: " << timeEnd - timeBegin << std::endl;std::cout << "FCJson size: " << fcDump.size() << std::endl;{std::ofstream outputFile("FCJson.json", std::ios::binary | std::ios::out);if (outputFile.is_open()){outputFile.write(fcDump.data(), fcDump.size());}}std::cout << std::endl;}{configor::json::value configorJson;std::cout << "nomango" << std::endl;timeBegin = clock();for (int i = 0; i < nCount; i++){configorJson = configor::json::parse(strBuffer);}timeEnd = clock();std::cout << "nomango parse cost time: " << timeEnd - timeBegin << std::endl;timeBegin = clock();std::string configorDump; for (int i = 0; i < nCount; i++){configorDump = configor::json::dump(configorJson);}timeEnd = clock();std::cout << "nomango dump cost time: " << timeEnd - timeBegin << std::endl;std::cout << "nomango size: " << configorDump.size() << std::endl;{std::ofstream outputFile("nomango.json", std::ios::binary | std::ios::out);if (outputFile.is_open()){outputFile.write(configorDump.data(), configorDump.size());}}std::cout << std::endl;}system("pause");}return 0;
}

性能测试

CPU: AMD Ryzen 5 4500U with Radeon Graphics


http://www.ppmy.cn/devtools/127672.html

相关文章

五、Spring Boot集成Spring Security之认证流程2

一、Spring Boot集成Spring Security专栏 一、Spring Boot集成Spring Security之自动装配 二、Spring Boot集成Spring Security之实现原理 三、Spring Boot集成Spring Security之过滤器链详解 四、Spring Boot集成Spring Security之认证流程 五、Spring Boot集成Spring Se…

2020年计算机网络408真题解析

第一题&#xff1a; 解析&#xff1a;OSI参考模型网络协议的三要素 网络协议的三要素&#xff1a;语法 &#xff0c;语义&#xff0c;同步&#xff08;时序&#xff09; 语法&#xff1a;定义收发双方所交换信息的格式 语法&#xff1a;定义收发双方所要完成的操作 网页的加载 …

微信小程序用开发工具在本地真机调试可以正常访问摄像头,发布了授权后却无法访问摄像头,解决方案

今天开发上线了一个拍照的微信小程序&#xff0c;用uniapp的Vue3开发的&#xff0c;调用的camera组件&#xff0c;相关代码如下&#xff1a; <!-- 微信小程序相机组件 --><view v-if"showCamera" class"camera-container"><camera :device…

鸿蒙测试-常见问题记录

文章目录 queuesize:0, msg:error: failed to install bundle. code:9568322 error: signature verification failed due to not trusted app source. queuesize:0, msg:error: failed to install bundle. code:9568322 error: signature verification failed due to not trust…

RabbitMQ系列学习笔记(七)--RabbitMQ交换机

文章目录 一、Exchange概念二、交换机类型三、无名交换机四、绑定(bindings) 本文参考&#xff1a; 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、Exchange概念 RabbitMQ 消息传递模型的核心思想是: 生…

除GOF23种设计模式之简单工厂模式

文章目录 1. 简介2. 代码2.1 抽象类&#xff1a;Course.java2.2 产品A:JavaCourse.java2.3 产品B:PythonCourse.java2.4 工厂:CourseFactory.java2.5 测试&#xff1a;Test.java 3. 心得参考链接&#xff08;无&#xff09; 1. 简介 简单工厂模式(Simple Factory Patern):又称…

《柬埔寨语翻译通》App:技术驱动的语言翻译解决方案,高精度的高棉语OCR识别技术分享

2023年&#xff0c;一款全新的高棉语翻译应用《柬埔寨语翻译通》正式面向公众发布。这款应用不仅支持中文与高棉语的双向翻译&#xff0c;还集成了语音播放、翻译历史自动保存等高级功能&#xff0c;极大地提高了用户的语言学习效率和跨文化交流的便捷性。 核心功能与技术亮点…

物流管理系统设计与实现

摘 要 本物流管理系统是针对目前物流管理系统管理的实际需求&#xff0c;从实际工作出发&#xff0c;对过去的物流管理系统管理系统存在的问题进行分析&#xff0c;结合计算机系统的结构、概念、模型、原理、方法&#xff0c;在计算机各种优势的情况下&#xff0c;采用目前jsp…