请自行约束两种语言数据结构语法上的不同,避开如下问题:
1、json本身不约束key是否符合一个编程语言中的变量名,所以编写用于和编程语言数据结构交互的json代码时应该注意key是否正确。
2、lua没有数组,利用哈希表实现的逻辑上的数组,在中间可以存在不连续的情况时json将无法识别。
3、lua的字符串key可以和数字key共存,这对于json来说,是不允许的。
这些代码我已经用了很久了,所以暂时不多解释了,依赖c++11以上的版本,
代码挺多,有需求可以直接复制,这么多代码的目的也就是更高性能,单纯的在C++里面跑,比谷歌的实现稍微快一点点。
好了,废话不多说,上代码
#pragma once #include <string> #include <functional> #include <setjmp.h> #include <fstream> #include <vector> namespace aqx { #ifndef jsize_t typedef unsigned int jsize_t; #endif #ifndef jnumber_t typedef double jnumber_t; #endif static short constexpr jsvt_null{ 0 }; static short constexpr jsvt_string{ 1 }; static short constexpr jsvt_number{ 2 }; static short constexpr jsvt_boolean{ 3 }; static short constexpr jsvt_object{ 4 }; static short constexpr jsvt_group{ 5 }; namespace aqx_internal { #ifndef __AQX_UTF8_CHAR_LEN #define __AQX_UTF8_CHAR_LEN static unsigned char utf8_char_len[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 }; #endif static unsigned int json_char_state[] = { 0,0,0,0,0,0,0,0,0,32,96,0,0,96,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 32,0,640,0,0,0,0,0,0,0,0,1048576,65536,8192,131072,512, 3072,3072,3072,3072,3072,3072,3072,3072,3072,3072,16,0,0,0,0,0, 0,1024,1024,1024,1024,5120,1024,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,4,768,8,0,0, 0,17408,1024,1024,1024,21504,50176,0,0,0,0,0,278528,0,524800,0, 0,0,16896,16384,49664,279040,0,0,0,0,0,1,0,2,0,0 }; static int u16c2u8c(unsigned long u16c, unsigned char *u8c) { if (u16c <= 0x0000007F) { u8c[0] = u16c & 0x7F; return 1; } else if (u16c >= 0x00000080 && u16c <= 0x000007FF) { u8c[1] = (u16c & 0x3F) | 0x80; u8c[0] = ((u16c >> 6) & 0x1F) | 0xC0; return 2; } else if (u16c >= 0x00000800 && u16c <= 0x0000FFFF) { u8c[2] = (u16c & 0x3F) | 0x80; u8c[1] = ((u16c >> 6) & 0x3F) | 0x80; u8c[0] = ((u16c >> 12) & 0x0F) | 0xE0; return 3; } else if (u16c >= 0x00010000 && u16c <= 0x001FFFFF) { u8c[3] = (u16c & 0x3F) | 0x80; u8c[2] = ((u16c >> 6) & 0x3F) | 0x80; u8c[1] = ((u16c >> 12) & 0x3F) | 0x80; u8c[0] = ((u16c >> 18) & 0x07) | 0xF0; return 4; } else if (u16c >= 0x00200000 && u16c <= 0x03FFFFFF) { u8c[4] = (u16c & 0x3F) | 0x80; u8c[3] = ((u16c >> 6) & 0x3F) | 0x80; u8c[2] = ((u16c >> 12) & 0x3F) | 0x80; u8c[1] = ((u16c >> 18) & 0x3F) | 0x80; u8c[0] = ((u16c >> 24) & 0x03) | 0xF8; return 5; } else if (u16c >= 0x04000000 && u16c <= 0x7FFFFFFF) { u8c[5] = (u16c & 0x3F) | 0x80; u8c[4] = ((u16c >> 6) & 0x3F) | 0x80; u8c[3] = ((u16c >> 12) & 0x3F) | 0x80; u8c[2] = ((u16c >> 18) & 0x3F) | 0x80; u8c[1] = ((u16c >> 24) & 0x3F) | 0x80; u8c[0] = ((u16c >> 30) & 0x01) | 0xFC; return 6; } return 0; } namespace JSON_SYNTAX { static constexpr auto _T_OBJECT_BEGIN{ static_cast<unsigned int>(0x01) }; // { static constexpr auto _T_OBJECT_END{ static_cast<unsigned int>(0x02) }; // } static constexpr auto _T_GROUP_BEGIN{ static_cast<unsigned int>(0x04) }; // [ static constexpr auto _T_GROUP_END{ static_cast<unsigned int>(0x08) }; // ] static constexpr auto _T_VALUE{ static_cast<unsigned int>(0x10) }; // : static constexpr auto _T_SPACE{ static_cast<unsigned int>(0x20) }; // 4个空白字符" " static constexpr auto _T_ENDL{ static_cast<unsigned int>(0x40) }; // 2个换行符" " static constexpr auto _T_TEXT{ static_cast<unsigned int>(0x80) }; // " static constexpr auto _T_ESCAPE_BEGIN{ static_cast<unsigned int>(0x100) }; // 转义符开始 '\' static constexpr auto _T_ESCAPE_TYPE{ static_cast<unsigned int>(0x200) }; // 转义符类型 "nrtbfu\" static constexpr auto _T_HEX{ static_cast<unsigned int>(0x400) }; // u之后UTF16的4字符HEX,"abcdefABCDEF" static constexpr auto _T_NUMBER{ static_cast<unsigned int>(0x800) }; // 数字"0-9" static constexpr auto _T_E{ static_cast<unsigned int>(0x1000) }; // 科学计数法 e或E static constexpr auto _T_NEGATIVE{ static_cast<unsigned int>(0x2000) }; // 负数 - static constexpr auto _T_BOOL{ static_cast<unsigned int>(0x4000) }; // true false static constexpr auto _T_BOOL_BEGIN{ static_cast<unsigned int>(0x8000) }; // t f static constexpr auto _T_NEXT{ static_cast<unsigned int>(0x10000) }; // , static constexpr auto _T_DECIMAL{ static_cast<unsigned int>(0x20000) }; // 小数点 . static constexpr auto _T_NULL{ static_cast<unsigned int>(0x40000) }; // null static constexpr auto _T_NULL_BEGIN{ static_cast<unsigned int>(0x80000) }; // n static constexpr auto _T_POSITIVE{ static_cast<unsigned int>(0x100000) }; // + } static constexpr auto _jnf{ static_cast<jsize_t>(-1) }; template<typename _Ty> class _json_parser; class _jts_base { public: _jts_base() { text = nullptr; } void init(const char *_Text, int _Size) { text = _Text; size = _Size; instr = false; flags = 0; index = 0; } jsize_t open_instr() { instr = true; jsize_t _Result = flags; flags = 0; return _Result; } void close_instr(jsize_t _Flags) { instr = false; flags = _Flags; } jsize_t set_flags(jsize_t _Flags) { auto _Result = flags; flags = _Flags; return _Result; } long subhextol(int left, int len) { long _Result = 0; int rlen = len; for (int i = 0; i < len; i++) { char c = text[--rlen]; long _Tmp; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': _Tmp = c - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': _Tmp = c - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': _Tmp = c - 'A' + 10; break; default: return 0; } _Result += (_Tmp << (i << 2)); } return _Result; } protected: const char *text; jsize_t size; unsigned int s; char c; unsigned char cl; bool instr; unsigned int flags; jsize_t index; std::string tmp; }; class _jts_utf8 : public _jts_base { public: int operator++() { c = text[index]; cl = utf8_char_len[(unsigned char)c]; if (cl != 1) { if (flags == JSON_SYNTAX::_T_ESCAPE_TYPE || !instr) return -1; do { index += cl; c = text[index]; cl = utf8_char_len[(unsigned char)c]; } while (cl != 1); } s = json_char_state[c]; if (flags & s) { index += cl; return 0; } if (instr) { if (s & JSON_SYNTAX::_T_ENDL) return -1; index += cl; return 0; } return -1; } private: friend class _json_parser<_jts_utf8>; }; class _jts_gbk : public _jts_base { public: int operator++() { c = text[index]; cl = ((unsigned char)c & 0x80) ? 2 : 1; if (cl != 1) { if (flags == JSON_SYNTAX::_T_ESCAPE_TYPE || !instr) return -1; do { index += cl; c = text[index]; cl = ((unsigned char)c & 0x80) ? 2 : 1; } while (cl != 1); } s = json_char_state[c]; if (flags & s) { index += cl; return 0; } if (instr) { if (s & JSON_SYNTAX::_T_ENDL) return -1; index += cl; return 0; } return -1; } private: friend class _json_parser<_jts_gbk>; }; class _json_tree { public: class node { public: node() { _Size = 0; _Bgn = _Parent = _jnf; } node(jsize_t _Pa) { _Size = 0; _Parent = _Pa; _Bgn = _jnf; } jsize_t size() { return _Size; } jsize_t begin() { return _Bgn; } private: friend class _json_parser<_jts_utf8>; friend class _json_parser<_jts_gbk>; friend class _json_tree; jsize_t _Size, _Bgn, _End, _Parent; }; class var { public: var() { Key = _jnf; Next = _jnf; Kty = 1; Type = 0; } var(short _KTy, jsize_t _Key) { Next = _jnf; Kty = _KTy; Key = _Key; Type = 0; } var(short _KTy, jsize_t _Key, short _Type, jsize_t _Val) { Next = _jnf; Kty = _KTy; Key = _Key; Type = _Type; Off = _Val; } var(short _KTy, jsize_t _Key, short _Type, bool _Val) { Next = _jnf; Kty = _KTy; Key = _Key; Type = _Type; Stat = _Val; } var(short _KTy, jsize_t _Key, short _Type, jnumber_t _Val) { Next = _jnf; Kty = _KTy; Key = _Key; Type = _Type; Number = _Val; } short type() { return Type; } bool is_ikey() { return Kty == 1; } var *next(_json_tree &_Tree) { if (Next == _jnf) return nullptr; return _Tree.get_val(Next); } jsize_t ikey() { return (is_ikey()) ? Key : _jnf; } const char *skey(_json_tree &_Tree) { return (!is_ikey()) ? _Tree.get_text(Key) : ""; } bool toboolean() { return Stat; } const char *tostring(_json_tree &_Tree) { return (type() == 1) ? _Tree.get_text(Off) : ""; } jnumber_t tonumber() { return (type() == 2) ? Number : 0; } node *toobject(_json_tree &_Tree) { return (type() == aqx::jsvt_object || type() == aqx::jsvt_group) ? _Tree.get_node(Off) : nullptr; } private: friend class _json_parser<_jts_utf8>; friend class _json_parser<_jts_gbk>; friend class _json_tree; jsize_t Key; jsize_t Next; short Type; short Kty; union { bool Stat; jsize_t Off; jnumber_t Number; }; }; _json_tree() { _Texts = { 0, 0, 0 }; } node *get_root() { if (_Nodes.size() < 2)return nullptr; return get_node(1); } var *get_root_val() { if (_Nodes.size() < 2)return nullptr; return get_val(1); } node *get_node(jsize_t _Ref) { return (_Ref < (jsize_t)_Nodes.size()) ? &(_Nodes[_Ref]) : nullptr; } var *get_val(jsize_t _Ref) { return (_Ref < (jsize_t)_Vals.size()) ? &(_Vals[_Ref]) : nullptr; } const char *get_text(jsize_t _Ref) { return (_Ref <= _Texts.size) ? _Texts.data + _Ref : nullptr; } void reserve(jsize_t _TextSize, jsize_t _Count) { if (_TextSize << 1 > _Texts.capacity) _Realloc_Texts(_TextSize << 1); _Vals.reserve(_Count << 1); _Nodes.reserve(_Count); } void clear() { _Texts.size = 0; _Vals.clear(); _Nodes.clear(); } private: void _set_child(node *e, jsize_t v) { if (e->_Bgn == _jnf) { e->_Bgn = v; e->_End = v; } else { get_val(e->_End)->Next = v; e->_End = v; } } jsize_t new_node(jsize_t _Node, jsize_t &_Name, short _Type) { jsize_t _Result = (jsize_t)_Nodes.size(); _Nodes.push_back(node(_Node)); jsize_t v = (jsize_t)_Vals.size(); auto e = get_node(_Node); if (_Name != _jnf) { _Vals.push_back(var(0, _Name, _Type, _Result)); _Name = _jnf; e->_Size++; } else _Vals.push_back(var(1, e->_Size++, _Type, _Result)); _set_child(e, v); return _Result; } jsize_t new_root() { jsize_t _Result = (jsize_t)_Nodes.size(); _Nodes.push_back(node()); jsize_t v = (jsize_t)_Vals.size(); _Vals.push_back(var(1, _jnf, aqx::jsvt_object, _Result)); return _Result; } void _Realloc_Texts(jsize_t _NewCapacity = 0) { if (_NewCapacity != 0) _Texts.capacity = (_NewCapacity + (_NewCapacity >> 1)); else _Texts.capacity = (_Texts.capacity + (_Texts.capacity >> 1)); if (_Texts.capacity < 0x1000) _Texts.capacity = 0x1000; char *_Tmp = new char[_Texts.capacity]; if (_Texts.data) { if (_Texts.size) memcpy_s(_Tmp, _Texts.capacity, _Texts.data, _Texts.size); delete _Texts.data; } _Texts.data = _Tmp; } jsize_t new_text(const char *_Text, int _Len) { jsize_t x = _Texts.size + (sizeof(size_t) - (_Texts.size % sizeof(size_t))); if (x + _Len >= _Texts.capacity) _Realloc_Texts(x + _Len); char *_Target = _Texts.data + x; _Texts.size = x + (_Len--); memcpy_s(_Target, _Len, _Text, _Len); _Target[_Len] = 0; return x; } void append_text(const char *_Text, int _Len) { if (_Texts.size + _Len >= _Texts.capacity) _Realloc_Texts(_Texts.size + _Len); char *_Target = _Texts.data + _Texts.size - 1; _Texts.size += _Len--; _Texts.size--; memcpy_s(_Target, _Len, _Text, _Len); _Target[_Len] = 0; } void append_char(char _Chr) { if (_Texts.size + 1 >= _Texts.capacity) _Realloc_Texts(_Texts.size + 1); _Texts.data[_Texts.size - 1] = _Chr; _Texts.data[_Texts.size++] = 0; } void back_text(int _Len) { _Texts.size -= _Len; _Texts.data[_Texts.size] = 0; } jsize_t new_var_string(jsize_t _Node, jsize_t &_Name, jsize_t _Text) { jsize_t v = (jsize_t)_Vals.size(); auto e = get_node(_Node); if (_Name != _jnf) { _Vals.push_back(var(0, _Name, aqx::jsvt_string, _Text)); _Name = _jnf; e->_Size++; } else _Vals.push_back(var(1, e->_Size++, aqx::jsvt_string, _Text)); _set_child(e, v); return v; } jsize_t new_var_number(jsize_t _Node, jsize_t &_Name, jnumber_t _Number) { jsize_t v = (jsize_t)_Vals.size(); auto e = get_node(_Node); if (_Name != _jnf) { _Vals.push_back(var(0, _Name, aqx::jsvt_number, _Number)); _Name = _jnf; e->_Size++; } else _Vals.push_back(var(1, e->_Size++, aqx::jsvt_number, _Number)); _set_child(e, v); return v; } jsize_t new_var_boolean(jsize_t _Node, jsize_t &_Name, bool _Stat) { jsize_t v = (jsize_t)_Vals.size(); auto e = get_node(_Node); if (_Name != _jnf) { _Vals.push_back(var(0, _Name, aqx::jsvt_boolean, _Stat)); _Name = _jnf; e->_Size++; } else _Vals.push_back(var(1, e->_Size++, aqx::jsvt_boolean, _Stat)); _set_child(e, v); return v; } jsize_t new_var_null(jsize_t _Node, jsize_t &_Name) { jsize_t v = (jsize_t)_Vals.size(); auto e = get_node(_Node); if (_Name != _jnf) { _Vals.push_back(var(0, _Name, aqx::jsvt_null, (jnumber_t)0)); _Name = _jnf; e->_Size++; } else _Vals.push_back(var(1, e->_Size++, aqx::jsvt_null, (jnumber_t)0)); _set_child(e, v); return v; } private: friend class _json_parser<_jts_utf8>; friend class _json_parser<_jts_gbk>; std::vector<var> _Vals; std::vector<node> _Nodes; struct _TEXTS_POOL { char *data; jsize_t size; jsize_t capacity; }_Texts; }; template<typename _Ty> class _json_parser { public: _json_parser(_json_tree &_Tree) { tree = &_Tree; } bool load_string(const char *_Text, jsize_t _Len = _jnf, bool _MultiRoot = false) { if ((int)_Len < 0) _Len = (jsize_t)strlen(_Text) + 1; jts.init(_Text, _Len); tree->clear(); return j_root(_MultiRoot) == 0; } bool load_file(const std::string _File, bool _MultiRoot = false) { std::ifstream f(_File.c_str(), std::ifstream::binary); if (!f) return false; f.seekg(0, f.end); size_t fs = (size_t)f.tellg(); f.seekg(0, f.beg); char *_Buf = new char[fs + 2]; _Buf[fs] = 0; _Buf[fs + 1] = 0; f.read(_Buf, fs); f.close(); bool _Result = load_string(_Buf, (jsize_t)fs, _MultiRoot); delete _Buf; return _Result; } jsize_t get_error_pos() { /*for (int i = err_pos; i < err_pos + 10; i++) printf("%c", jts.text[i]); printf(" ");*/ return err_pos; } private: void jtsnext() { if ((jts.index >= jts.size) || (++jts) != 0) { err_pos = jts.index; longjmp(_Rem, -1); } } void j_ec(jsize_t &_Off, jsize_t &_TextOff) { jsize_t len = jts.index - _Off; if (_TextOff == (jsize_t)-1) _TextOff = tree->new_text(jts.text + _Off, len); else tree->append_text(jts.text + _Off, len); jts.close_instr(JSON_SYNTAX::_T_ESCAPE_TYPE); jtsnext(); if (jts.c == 'u') { jsize_t ecpos = jts.index; unsigned long _uc1 = 0; int _uc1_len = 0; char u8c[7]; for (;;) { jts.set_flags(JSON_SYNTAX::_T_HEX); for (int i = 0; i < 4; i++) { jtsnext(); } unsigned long uc = (unsigned short)jts.subhextol(ecpos, jts.index - ecpos); if (_uc1 >= 0xD800 && _uc1 < 0xDBFF && uc >= 0xDC00 && uc < 0xDFFF) { int u8l = u16c2u8c((_uc1 - 0xD800) * 0x400 + (uc - 0xDC00) + 0x10000, (unsigned char*)u8c); u8c[u8l] = 0; tree->back_text(_uc1_len + 1); tree->append_text(u8c, u8l + 1); _uc1 = 0; } else { _uc1 = uc; _uc1_len = u16c2u8c(uc, (unsigned char*)u8c); u8c[_uc1_len] = 0; tree->append_text(u8c, _uc1_len + 1); } jts.open_instr(); if (jts.c != '\') { _Off = jts.index; jts.index--; break; } jts.close_instr(JSON_SYNTAX::_T_ESCAPE_TYPE); jtsnext(); if (jts.c != 'u') { _Off = jts.index - 1; jts.index -= 2; break; } } } else { switch (jts.c) { case '\': tree->append_char('\'); break; case 'n': tree->append_char(' '); break; case 'r': tree->append_char(' '); break; case 't': tree->append_char(' '); break; case 'b': tree->append_char(''); break; case 'f': tree->append_char('f'); break; case '/': tree->append_char('/'); break; } _Off = jts.index; } jts.open_instr(); //继续放飞自我 } void j_text(bool isname = false) { jsize_t pos = jts.index; auto f = jts.open_instr();//字符串里的东西就开始放飞自我了,允许所有,除了不能换行 jsize_t text_off = (jsize_t)-1; jsize_t text_len = 0; for (;;) { jtsnext(); if (jts.c == '\') { j_ec(pos, text_off); } else if (jts.c == '"') { break; } } jts.close_instr(f); jsize_t len = jts.index - pos; if (text_off == (jsize_t)-1) text_off = tree->new_text(jts.text + pos, len); else tree->append_text(jts.text + pos, len); if (isname) name_off = text_off; else tree->new_var_string(cur, name_off, text_off); } void j_number() { //考虑到可能会传入常量字符串到json解析,所以,在不拷贝源字符串,不能修改源字符串的情况下,只有自己实现数字转换的代码,这里统一使用浮点类型进行计算 /* 有一点没有遵循标准,标准对于数字前的多个0是不允许的, 但是它允许了-0 -0.00000000000 0e00000000000 之类的这些同样无意义的东西存在 而我没有判断这一点,因为我觉得这会带来额外的性能损失,也会使这段代码变得更为复杂, 我认为这一点,不管这些无意义的0在哪,由程序员自行控制它, 只约束头部,不管中间,尾巴的做法,除了降低性能,没有什么实际意义。 */ unsigned int myf; long double _Number = 0; long double factor; bool neg = false; if (jts.c == '-') { neg = true; jts.set_flags(JSON_SYNTAX::_T_NUMBER); jtsnext(); myf = JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_E | JSON_SYNTAX::_T_DECIMAL | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT; jts.set_flags(myf); } else { myf = JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_E | JSON_SYNTAX::_T_DECIMAL | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT; jts.set_flags(myf); } do { //整数部分 _Number = _Number * 10 + (jts.c - '0'); jtsnext(); } while (jts.s & JSON_SYNTAX::_T_NUMBER); if (jts.c == '.') { //小数点之后的数字 factor = 1.0; jts.set_flags(JSON_SYNTAX::_T_NUMBER); jtsnext(); myf ^= JSON_SYNTAX::_T_DECIMAL;//之后不再允许小数点 jts.set_flags(myf); do { factor *= 0.1; _Number += (jts.c - '0') * factor; jtsnext(); } while (jts.s & JSON_SYNTAX::_T_NUMBER); } if ((jts.c | 32) == 'e') { //科学计数的处理 unsigned int expo = 0;//指数 factor = 10.0;//因数 //e之后,必须是+-或者数字,如果是+-,那么后面必须是一个数字 //这里是json唯一允许+号出现的地方 jts.set_flags(JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_NEGATIVE | JSON_SYNTAX::_T_POSITIVE); jtsnext(); if (jts.c == '-') { jts.set_flags(JSON_SYNTAX::_T_NUMBER); jtsnext(); factor = 0.1; } else if (jts.c == '+') { jts.set_flags(JSON_SYNTAX::_T_NUMBER); jtsnext(); } jts.set_flags(JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT); do { expo = 10 * expo + (jts.c - '0'); jtsnext(); } while (jts.s & JSON_SYNTAX::_T_NUMBER); for (;;) { //根据指数计算因数的快速求幂的方法 if (expo & 1) _Number *= factor; if ((expo >>= 1) == 0) break; factor *= factor; } } if (!(jts.s & JSON_SYNTAX::_T_SPACE))//非空白字符时,倒退到上一个字符,由此处判断一下会由微小的性能提升,毕竟一次jtsnext()的代价更高一些 --jts.index; tree->new_var_number(cur, name_off, (jnumber_t)(neg ? -_Number : _Number)); } void j_true() { jts.set_flags(JSON_SYNTAX::_T_BOOL); for (int i = 0; i < 3; i++) { jtsnext(); if ("rue"[i] != jts.c) { err_pos = jts.index - 1; longjmp(_Rem, -1); } } tree->new_var_boolean(cur, name_off, true); } void j_false() { jts.set_flags(JSON_SYNTAX::_T_BOOL); for (int i = 0; i < 4; i++) { jtsnext(); if ("alse"[i] != jts.c) { err_pos = jts.index - 1; longjmp(_Rem, -1); } } tree->new_var_boolean(cur, name_off, false); } void j_null() { jts.set_flags(JSON_SYNTAX::_T_NULL); for (int i = 0; i < 3; i++) { jtsnext(); if ("ull"[i] != jts.c) { err_pos = jts.index - 1; longjmp(_Rem, -1); } } tree->new_var_null(cur, name_off); } void j_value() { jts.set_flags( JSON_SYNTAX::_T_SPACE | // 空白字符 JSON_SYNTAX::_T_TEXT | // " JSON_SYNTAX::_T_OBJECT_BEGIN | // { JSON_SYNTAX::_T_GROUP_BEGIN | // [ JSON_SYNTAX::_T_NUMBER | // 0-9 JSON_SYNTAX::_T_NEGATIVE | // -负号 JSON_SYNTAX::_T_BOOL_BEGIN | // true false开头 JSON_SYNTAX::_T_NULL_BEGIN ); bool ok = false; do { jtsnext(); } while (jts.s & JSON_SYNTAX::_T_SPACE); switch (jts.c) { case '"': j_text(); break; case '{': j_object(); break; case '[': j_group(); break; case '-': j_number(); break; case 't': j_true(); break; case 'f': j_false(); break; case 'n': j_null(); break; default: if (jts.s & JSON_SYNTAX::_T_NUMBER) { j_number(); break; } break; } } void j_group() { // [ 之后,允许空白字符,"{0-9] true false null auto f = jts.set_flags( JSON_SYNTAX::_T_SPACE | // 空白字符 JSON_SYNTAX::_T_TEXT | // " JSON_SYNTAX::_T_OBJECT_BEGIN | // { JSON_SYNTAX::_T_GROUP_END | // ] JSON_SYNTAX::_T_NUMBER | // 0-9 JSON_SYNTAX::_T_NEGATIVE | // -负号 JSON_SYNTAX::_T_BOOL_BEGIN | // t f JSON_SYNTAX::_T_NULL_BEGIN | // n JSON_SYNTAX::_T_GROUP_BEGIN // 在遇到[时就递归前进 ); auto _Node = cur; cur = tree->new_node(cur, name_off, aqx::jsvt_group); bool ok = false; do { jtsnext(); switch (jts.c) { case '"': j_text(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case '{': j_object(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case '[': j_group(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case '-': j_number(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case 't': j_true(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case 'f': j_false(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case 'n': j_null(); jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END); break; case ']': ok = true; break; case ',': jts.set_flags( JSON_SYNTAX::_T_SPACE | // 空白字符 JSON_SYNTAX::_T_TEXT | // " JSON_SYNTAX::_T_OBJECT_BEGIN | // { JSON_SYNTAX::_T_NUMBER | // 0-9 JSON_SYNTAX::_T_NEGATIVE | // -负号 JSON_SYNTAX::_T_BOOL_BEGIN | // t f JSON_SYNTAX::_T_NULL_BEGIN | // n JSON_SYNTAX::_T_GROUP_BEGIN // 在遇到[时就递归前进 ); break; default: if (jts.s & JSON_SYNTAX::_T_NUMBER) { j_number(); break; } break; } } while (!ok); jts.set_flags(f); cur = _Node; } void j_object() { auto _Node = cur; cur = tree->new_node(cur, name_off, aqx::jsvt_object); auto f = jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END); bool ok = false; do { jtsnext(); switch (jts.c) { case '"': j_text(true); //名称字符串结束后,只允许 : 和 空白字符 jts.set_flags(JSON_SYNTAX::_T_VALUE | JSON_SYNTAX::_T_SPACE); break; case ':': j_value(); jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_NEXT); break; case ',': // 碰到逗号时,新的一轮开始,但此时不再允许花括号,也就是不允许{"a":1,}这样的 jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE); break; case '}': ok = true; break; } } while (!ok); cur = _Node; } int j_root(bool _MultiRoot) { if (setjmp(_Rem)) { tree->clear(); return -1; } root = tree->new_root(); cur = root; name_off = _jnf; err_pos = 0; jts.set_flags(JSON_SYNTAX::_T_OBJECT_BEGIN | JSON_SYNTAX::_T_GROUP_BEGIN | JSON_SYNTAX::_T_SPACE); for (;;) { jtsnext(); if (jts.c == '{') { j_object(); break; } else if (jts.c == '[') { j_group(); break; } } if (!_MultiRoot) { jts.open_instr(); for (;;) { if (jts.index >= jts.size) break; char _Chr = jts.text[jts.index++]; if (!_Chr) break; if (!(json_char_state[(unsigned char)_Chr] & JSON_SYNTAX::_T_SPACE)) { err_pos = jts.index - 1; //tree->clear(); return -1; } } } return 0; } private: jmp_buf _Rem; _Ty jts; _json_tree *tree; jsize_t cur; jsize_t root; jsize_t name_off; jsize_t err_pos; }; } using json_tree = aqx_internal::_json_tree; template<typename _Ty> using json_parser_t = aqx_internal::_json_parser<_Ty>; using jts_gbk = aqx_internal::_jts_gbk; using jts_utf8 = aqx_internal::_jts_utf8; } /* //我已经把代码移植到C去了,最终我还是又回到C++来使用它,因为。。。C的性能,反而不如C++,无论是vc还是gcc都是不如c++... //可能的原因是我对C的二进制优化的手法并不纯熟而导致的问题,完全照搬结构大概是不合理的做法, //不过我认为更多的可能性还是,C入栈的参数比C++要多而导致的。 //毕竟,this指针总在cx si之间传,而C,要写入太多太多结构指针 //下面这一串是构建字符状态表的代码 int sztext[128]; memset(sztext, 0, 512); sztext['"'] = aqx::aqx_internal::JSON_SYNTAX::_T_TEXT | aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext[':'] = aqx::aqx_internal::JSON_SYNTAX::_T_VALUE; sztext[','] = aqx::aqx_internal::JSON_SYNTAX::_T_NEXT; sztext['{'] = aqx::aqx_internal::JSON_SYNTAX::_T_OBJECT_BEGIN; sztext['}'] = aqx::aqx_internal::JSON_SYNTAX::_T_OBJECT_END; sztext['['] = aqx::aqx_internal::JSON_SYNTAX::_T_GROUP_BEGIN; sztext[']'] = aqx::aqx_internal::JSON_SYNTAX::_T_GROUP_END; sztext['\'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_BEGIN | aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['n'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['r'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['t'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['b'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['f'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['u'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext['/'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE; sztext[' '] = aqx::aqx_internal::JSON_SYNTAX::_T_ENDL | aqx::aqx_internal::JSON_SYNTAX::_T_SPACE; sztext[' '] = aqx::aqx_internal::JSON_SYNTAX::_T_ENDL | aqx::aqx_internal::JSON_SYNTAX::_T_SPACE; sztext[' '] = aqx::aqx_internal::JSON_SYNTAX::_T_SPACE; sztext[' '] = aqx::aqx_internal::JSON_SYNTAX::_T_SPACE; for (size_t i = 0; i < strlen("0123456789"); i++) sztext["0123456789"[i]] = aqx::aqx_internal::JSON_SYNTAX::_T_NUMBER | aqx::aqx_internal::JSON_SYNTAX::_T_HEX; for (size_t i = 0; i < strlen("abcdefABCDEF"); i++) sztext["abcdefABCDEF"[i]] = aqx::aqx_internal::JSON_SYNTAX::_T_HEX; sztext['.'] = aqx::aqx_internal::JSON_SYNTAX::_T_DECIMAL; sztext['+'] = aqx::aqx_internal::JSON_SYNTAX::_T_POSITIVE; sztext['-'] = aqx::aqx_internal::JSON_SYNTAX::_T_NEGATIVE; sztext['e'] |= aqx::aqx_internal::JSON_SYNTAX::_T_E; sztext['E'] |= aqx::aqx_internal::JSON_SYNTAX::_T_E; sztext['t'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['t'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL_BEGIN; sztext['r'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['u'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['e'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['f'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['f'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL_BEGIN; sztext['a'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['l'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['s'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['n'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL_BEGIN; sztext['u'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL; sztext['l'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL; for (int y = 0; y < 8; y++) { for (int x = 0; x < 16; x++) { printf("%d,", sztext[y * 16 + x]); } printf(" "); } return 0; */
封装给lua使用的库:
//ljsonlib.h #pragma once #include "lua/lua.hpp" #include "aqx/json.h" class ljson_convert { public: ljson_convert(lua_State *_s, int ec); int table_to_json(int n); int json_to_table(const char *_Text, int _Len); private: friend int lua_table_to_json(lua_State *s); void json_to_object(aqx::jsize_t _Ref); void json_to_group(aqx::jsize_t _Ref); int ec_mode; aqx::json_tree jt; aqx::json_parser_t<aqx::jts_gbk> *pgbk; aqx::json_parser_t<aqx::jts_utf8> *putf8; lua_State *s; std::string b; }; //_CharEncoding为字符编码格式,默认为"gbk",可以传入"utf8" ljson_convert *lua_openljsonlib(lua_State *s, const char *_CharEncoding = "");
//ljsonlib.cpp #include "pch.h" #include "ljsonlib.h" #define lua_isintnum(_Number_) (_Number_ - floor(_Number_) < 1e-6) ljson_convert::ljson_convert(lua_State *_s, int ec) { s = _s; jt.reserve(0x1000, 0x400); b.reserve(0x1000); ec_mode = ec; if (!ec_mode) pgbk = new aqx::json_parser_t<aqx::jts_gbk>(jt); else putf8 = new aqx::json_parser_t<aqx::jts_utf8>(jt); } int ljson_convert::table_to_json(int n) { char sznum[128]; lua_pushnil(s); int t = 0; if (!lua_next(s, n)) return 0; switch (lua_type(s, -2)) { case LUA_TNUMBER: b += '['; t = 2; break; case LUA_TSTRING: b += "{""; b += lua_tostring(s, -2); b += "":"; t = 1; break; default: lua_pop(s, 1); return -1; } switch (lua_type(s, -1)) { case LUA_TBOOLEAN: b += (lua_toboolean(s, -1) == 1) ? "true" : "false"; break; case LUA_TNUMBER: { double dv = lua_tonumber(s, -1); if (lua_isintnum(dv)) sprintf_s(sznum, 128, "%I64d", (long long)dv); else sprintf_s(sznum, 128, "%lf", dv); b += sznum; break; } case LUA_TSTRING: b += '"'; b += lua_tostring(s, -1); b += '"'; break; case LUA_TTABLE: if (table_to_json(-2)) { lua_pop(s, 1); return -1; } break; default: lua_pop(s, 1); return -1; } lua_pop(s, 1); while (lua_next(s, n)) { switch (lua_type(s, -2)) { case LUA_TNUMBER: b += ','; break; case LUA_TSTRING: b += ",""; b += lua_tostring(s, -2); b += "":"; break; default: lua_pop(s, 1); return -1; } switch (lua_type(s, -1)) { case LUA_TBOOLEAN: b += (lua_toboolean(s, -1) == 1) ? "true" : "false"; break; case LUA_TNUMBER: { double dv = lua_tonumber(s, -1); if (lua_isintnum(dv)) sprintf_s(sznum, 128, "%I64d", (long long)dv); else sprintf_s(sznum, 128, "%lf", dv); b += sznum; break; } case LUA_TSTRING: b += '"'; b += lua_tostring(s, -1); b += '"'; break; case LUA_TTABLE: if (table_to_json(-2)) { lua_pop(s, 1); return -1; } break; default: lua_pop(s, 1); return -1; } lua_pop(s, 1); } b += t == 1 ? '}' : ']'; return 0; } int ljson_convert::json_to_table(const char *_Text, int _Len) { if (!ec_mode) { if (!pgbk->load_string(_Text, _Len, true)) { return -1; } } else { if (!putf8->load_string(_Text, _Len, true)) return -1; } auto root = jt.get_root(); if (!root) return -1; json_to_object(root->begin()); return 0; } void ljson_convert::json_to_object(aqx::jsize_t _Ref) { for (auto v = jt.get_val(_Ref); v != nullptr; v = v->next(jt)) { switch (v->type()) { case aqx::jsvt_null: lua_pushstring(s, v->skey(jt)); lua_pushnil(s); lua_settable(s, -3); break; case aqx::jsvt_string: lua_pushstring(s, v->skey(jt)); lua_pushstring(s, v->tostring(jt)); lua_settable(s, -3); break; case aqx::jsvt_number: { lua_pushstring(s, v->skey(jt)); double dv = v->tonumber(); if (lua_isintnum(dv)) lua_pushinteger(s, (intptr_t)dv); else lua_pushnumber(s, dv); lua_settable(s, -3); break; } case aqx::jsvt_boolean: lua_pushstring(s, v->skey(jt)); lua_pushboolean(s, v->toboolean()); lua_settable(s, -3); break; case aqx::jsvt_object: { auto n = v->toobject(jt); if (!n->size()) break; lua_pushstring(s, v->skey(jt)); lua_newtable(s); json_to_object(n->begin()); lua_settable(s, -3); break; } case aqx::jsvt_group: { auto n = v->toobject(jt); if (!n->size()) { break; } lua_pushstring(s, v->skey(jt)); lua_newtable(s); json_to_group(n->begin()); lua_settable(s, -3); break; } } } } void ljson_convert::json_to_group(aqx::jsize_t _Ref) { int i = 1; for (auto v = jt.get_val(_Ref); v != nullptr; v = v->next(jt)) { switch (v->type()) { case aqx::jsvt_null: lua_pushnil(s); lua_rawseti(s, -2, i++); break; case aqx::jsvt_string: lua_pushstring(s, v->tostring(jt)); lua_rawseti(s, -2, i++); break; case aqx::jsvt_number: { double dv = v->tonumber(); if (lua_isintnum(dv)) lua_pushinteger(s, (intptr_t)dv); else lua_pushnumber(s, dv); lua_rawseti(s, -2, i++); break; } case aqx::jsvt_boolean: lua_pushboolean(s, v->toboolean()); break; case aqx::jsvt_object: { auto n = v->toobject(jt); if (!n->size()) break; lua_newtable(s); json_to_object(n->begin()); lua_rawseti(s, -2, i++); break; } case aqx::jsvt_group: { auto n = v->toobject(jt); if (!n->size()) break; lua_newtable(s); json_to_group(n->begin()); lua_rawseti(s, -2, i++); break; } } } } ljson_convert *get_ljson_convert(lua_State *s) { lua_getglobal(s, "__ljsonlib_convert_"); if (lua_isnil(s, -1)) return nullptr; return (ljson_convert*)lua_touserdata(s, -1); } int lua_table_to_json(lua_State *s) { ljson_convert *pjc = get_ljson_convert(s); if (!pjc) return 0; if (!lua_gettop(s)) return 0; if (lua_type(s, 1) != LUA_TTABLE) return 0; pjc->b.clear(); if (pjc->table_to_json(1)) { pjc->b.clear(); } lua_pushstring(s, pjc->b.c_str()); return 1; } int lua_table_from_json(lua_State *s) { ljson_convert *pjc = get_ljson_convert(s); if (!pjc) return 0; if (!lua_gettop(s)) return 0; if (lua_type(s, 1) != LUA_TSTRING) return 0; lua_newtable(s); if (!pjc->json_to_table(lua_tostring(s, 1), -1)) { return 1; } lua_pop(s, 1); return 0; } ljson_convert *lua_openljsonlib(lua_State *s, const char *_CharEncoding) { ljson_convert *pjc = get_ljson_convert(s); if (pjc)return pjc; pjc = new ljson_convert(s, (strstr(_CharEncoding, "utf") == nullptr) ? 0 : 1); lua_pushlightuserdata(s, pjc); lua_setglobal(s, "__ljsonlib_convert_"); lua_getglobal(s, "table"); lua_pushcfunction(s, lua_table_to_json); lua_setfield(s, -2, "tojson"); lua_pushcfunction(s, lua_table_from_json); lua_setfield(s, -2, "fromjson"); return pjc; }
// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include <thread> #include <iostream> #pragma comment(lib, "lua54.lib") #include "lxsharelib.h" #include "ljsonlib.h" int main(int argc, char **argv) { lua_State *s = luaL_newstate(); luaL_openlibs(s); //使用这个接口,向lua本身的table对象中,添加两个函数table.tojson和table.fromjson auto p = lua_openljsonlib(s, "");//第2个参数可以传入"utf8"来应对utf8的lua文件,默认的情况下是gbk if (luaL_dofile(s, "G:\vs2017\ConsoleApplication2\x64\Release\script\testjson.lua")) printf("%s ", lua_tostring(s, -1)); lua_close(s); //用完之后,需要自己释放掉内存,这个问题没什么好办法解决,除非扩展到lua源码中,或者给lua_close实现回调 delete p; return 0; }
测试脚本代码:
-- testjson.lua local t = { x = 3.14159, y = 2, z = {10,20,30,40,50} }; local json_text = table.tojson(t); print(json_text);--{"z":[10,20,30,40,50],"y":2,"x":3.141590} local t2 = table.fromjson('{"a":1.21e-3,"b":2,"c":[3,4,5,6,7,"abcde"],"d":[]}'); print(t2) --[[ b:2 a:0.00121 c:table: 000001C74BABABE0 ]] for i, e in pairs(t2) do print(i..':'..tostring(e)); end --[[ 1:3 2:4 3:5 4:6 5:7 6:abcde ]] for i, e in ipairs(t2.c) do print(i..':'..e); end
{"y":2,"x":3.141590,"z":[10,20,30,40,50]}
table: 0000025A15D5EFC0
a:0.00121
c:table: 0000025A15D7A340
b:2
1:3
2:4
3:5
4:6
5:7
6:abcde