所谓静态解析,就是将待解析字段,在C++中提前定义,格式类似于结构体,直接将解析出的内容放入字段中,这样和将字段内容解析到容器中相比,取值只有O(1)的时间复杂的,无需构造容器,解析无类型转换比较过程,缺点就是不太灵活。
关于json协议标准www.ecma-international.org要解析json数据需要那些元信息?
吃不到葡萄我会酸:C++ 元数据收集zhuanlan.zhihu.com为了保证解析效率足够高效,这里不会去收集字段的类型信息,而是通过收集其对应的操作函数入口来对json数据进行高效解析。
我们先来看看,在非宏编程状态下我们大概要怎样来怎样来解析一个数据
class Msg {
public:
int a;
private:
bool serialize_a() {
serialize<int>(&a);
}
bool unserialize_a() {
unserialize<int>(&a);
}
};
所以经过抽象后,我们的元数据结构定义如下:
struct data_impl_t {
void count_func_pointer_len() {}
char unserialize[sizeof(&data_impl_t::count_func_pointer_len)];
char serialize[sizeof(&data_impl_t::count_func_pointer_len)];
};
static std::unordered_map<no_copy_string, data_impl_t> fields;
先来解释一下为什么 data_impl_t 中会有一个空函数count_func_pointer_len,其实在不同的编译环境中,成员函数的地址大小是有差异的,在linux下sizeof(&data_impl_t::count_func_pointer_len) = 8,而在windows下这个值为4。
其实在最开始的时候我是用模板来定义元数据结构的,由于每个结构都会生成相应的的data_impl_t结构,这样导致的最大问题是生成的代码量比较大,同时比较费编译时间,所以使用了上面这种去模板化的方式来实现,只是会比较晦涩一点。
template<class T>
struct data_imple_t {
typedef size_t(T::*unserialize_t)(const char*, size_t);
typedef void(T::*serialize_t)(string &res);
unserialize_t unserialize;
serialize_t serialize;
};
来看看和repidjson的性能比较,以下为简单测试数据
{ "d":1.7976931348623157 }
{ "d":1.7976931348623157,"b" : "afsf","c" : [123,456],"f" : {"r":false,"r2" : true,"n" : null} }
如上图可见在处理简单高频json数据的时候,staticJson 的性能高出 rapidJson 至少一倍,其实在实际项目中使用得比较多的也是简单高频协议,以上可见静态解析的优势,缺点的话就是会牺牲一定的编译时间。