ijst:基于反射的 C++ JSON 反序列化库

ijst

Github repo: github.com/h46incon/ijst

ijst (iJsonStruct) 一个是 C++ Json 序列化/反序列化库:

  • 只需定义一次结构体,无须重复添加元信息。
  • 支持 Getter Chaining,可以很简单地访问路径较深的字段。
  • 支持 unknown 字段和可选字段。
  • 支持 UTF-8, UTF-16, UTF-32 编码。
  • 轻量:header-only,仅依赖 stl 和 RapidJSON
  • 兼容 C++ 98/03。支持 C++ 11 特性,如右值构造、extern template 等。
  • 反序列失败时,会有详细的错误信息。

使用

安装

  1. 安装 RapidJSON v1.1.0 以上版本(将其加入 header 搜索路径即可)。
  2. include/ijst 文件夹复制进工程。

单元测试(可选)

可通过以下命令安装依赖并执行单元测试:

cd IJST
git submodule update --init
mkdir CMakeBuild && cd CMakeBuild
cmake ..
make
./unit_test/unit_test

基本使用

定义结构体

#include <ijst/ijst.h>
#include <ijst/types_std.h>
#include <ijst/types_container.h>
using namespace ijst;

//*** 需要反序列化的 JSON 字符串
const std::string jsonStr = R"(
{
    "int_val": 42, 
    "vec_val": ["str1", "str2"], 
    "map_val": {"k1": 1, "k2": 2}
})";

//*** 定义一个 ijst 结构体:
IJST_DEFINE_STRUCT(
    // 结构体名字
    JsonStruct
    // 定义字段
    , (T_int, iVal, "int_val", 0)  
    , (IJST_TVEC(T_string), vecVal, "vec_val", 0)
    , (IJST_TMAP(T_uint64), mapVal, "map_val", 0)
);

//*** 默认情况下会生成这样的类:
/*
class JsonStruct {
public:
    ijst::Accessor _;   // 通过这个对象进行序列化等操作
    int iVal; 
    std::vector<std::string> vecVal; 
    std::map<std::string, uint64_t> mapVal; 

private:
    //... Some private methods
};
*/

字段访问及(反)序列化

//*** 定义一个 JsonStruct 对象
JsonStruct jStruct;

//*** 反序列化
int ret = jStruct._.Deserialize(jsonStr);
assert(ret == 0);

//*** 访问字段
assert(jStruct.iVal == 42);
assert(jStruct.vecVal[0] == "str1");
assert(jStruct.mapVal["k2"] == 2);

//*** 序列化
std::string strOut;
ret = jStruct._.Serialize(strOut);
assert (ret == 0);

Getter Chaining

如果所需访问的字段的路径比较深的时候,为避免累赘的判断,可使用 get_* 方法,比如:

//*** 和 IJST_DEFINE_STRUCT 类似
IJST_DEFINE_STRUCT_WITH_GETTER(
    StIn
    , (T_int, iData, "i", ijst::FDesc::Optional)
    , (IJST_TVEC(T_int), vecData, "vec", ijst::FDesc::Optional)
    , (IJST_TMAP(T_int), mapData, "map", ijst::FDesc::Optional)
)

//*** 默认情况下会生成这样的结构体:
/*
class JsonStruct {
public:
    //... 普通的字段,同 IJST_DEFINE_STRUCT
    
    // Getters
    ijst::Optional<int> get_iData();
    ijst::Optional<std::vector<int> > get_vecData();
    ijst::Optional<std::map<std::string, int> > get_mapData();
private:
};
*/

IJST_DEFINE_STRUCT_WITH_GETTER(
    StOut
    , (IJST_TST(StOut), stIn, "inner", ijst::FDesc::Optional)
)
StOut st;

//*** 可以通过连串的 get_* 尝试直接访问字段,而不用关注路径的中间节点是否存在
// 下行语句可访问 "/stIn/vecData/2"
// int* pData = st.get_stIn()->get_vecData()[2].Ptr();
// 即:
int* pData = st         // StOut 对象
    .get_stIn()         // 访问 stIn 字段
    ->get_vecData()     // 访问 vecData 字段,注意需使用 -> 操作符
    [2]                 // 访问数组中第2个元素
    .Ptr();             // 获取最后结果的地址
assert (pData == NULL);

// 如果路径中的每个字段都是 kValid 的,且 vector 的下标存在,则最终得到的指针会指向该字段:
// int* pData = st.get_stIn()->get_vecData()[2].Ptr() == &st.stIn.vecData[2];

性能

ijst 底层使用的是 RapidJSON,其本身具有优秀的性能。

ijst 因有额外的工作,会带来一些性能上的开销,但也比常用的 JsonCpp 快上不少:

Library

序列化

反序列化

RapidJSON

14

10

ijst

16

23

JsonCpp

128

109

测试环境:Corei7-4790_3.60GHz_vc2017_win7x64,测试代码: nativejson-benchmark

注:不同环境测得的性能会有差异,一般而言,ijst 的序列化性能和 RapidJSON 相似,反序列化性能为其 1/4 ~ 1/2。

详细说明

详请请移步 Github : github.com/h46incon/ijst

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

iOS逆向工程之Hopper中的ARM指令

虽然前段时间ARM被日本软银收购了,但是科技是无国界的,所以呢ARM相关知识该学的学。现在看ARM指令集还是倍感亲切的,毕竟大学里开了ARM这门课,并且做了不少...

35770
来自专栏Charlie's Road

<Solidity学习系列四>使用编译器

Solidity存储库的一个构建目标是solc,solidity命令行编译器。 使用solc --help为您提供所有选项的解释。 编译器可以生成各种输出,范围...

16820
来自专栏犀利豆的技术空间

徒手撸框架--实现 RPC 远程调用

微服务已经是每个互联网开发者必须掌握的一项技术。而 RPC 框架,是构成微服务最重要的组成部分之一。趁最近有时间。又看了看 dubbo 的源码。dubbo 为了...

17620
来自专栏IT杂记

通过Java程序提交通用Mapreduce任务并获取Job信息

背景 我们的一个业务须要有对MR任务的提交和状态跟踪的功能,须要通过Java代码提交一个通用的MR任务(包括mr的jar、配置文件、依赖的第三方jar包),并且...

1.1K50
来自专栏程序员的SOD蜜

PostgreSQL的.NET驱动程序Npgsql中参数对象的一个Bug

最近将公司的项目从SqlServer移植到PostgreSQL数据库上来,在调用数据库的存储过程(自定义函数)的时候,发现一个奇怪的问题,老是报函数无法找到。 ...

31470
来自专栏IT杂记

通过Java程序提交通用Mapreduce无法回收类的问题

问题描述 上次发布的博客 通过Java程序提交通用Mapreduce,在实施过程中发现,每次提交一次Mapreduce任务,JVM无法回收过程中产生的MapRe...

31660
来自专栏Java架构师学习

带你深入了解Java线程中的那些事

引言 说到Thread大家都很熟悉,我们平常写并发代码的时候都会接触到,那么我们来看看下面这段代码是如何初始化以及执行的呢? public class Thre...

35080
来自专栏向治洪

微信支付实例

1,导入微信的libs包libammsdk.jar; 2,测试时使用weixinDemo中的debug_keystore; 3,需要注意应用要通过审核,并且几个...

66850
来自专栏纯洁的微笑

Guava 源码分析(Cache 原理【二阶段】)

在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理。

19210
来自专栏Java学习123

spring 注解积累

33790

扫码关注云+社区

领取腾讯云代金券