JSON库代码杂记1

最近在看github上一个JSON库教程.记一下临时的一些点

tutorial01

  • 头文件用宏加入include guard,防止重复声明
#ifndef LEPTJSON_H__
#define LEPTJSON_H__

/* ... */

#endif /* LEPTJSON_H__ */
  • 没有硬编码,全部枚举化,用了两次数据结构抽象来提高代码的复用性,健壮性
typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type;

typedef struct {
    lept_type type;
}lept_value;
  • 多行宏编写用了do{}while(0)的方式,防止宏预处理后的代码问题
#define M() do { a(); b(); } while(0)
  • 入参的合法性判断统一采用assert()

tutorial2

  • 统一的解析入口函数lept_parse_value(),划分类型进入对应的子解析函数,子解析函数的EXPECT()感觉多余了,重复判断首字符
static int lept_parse_value(lept_context* c, lept_value* v) {
    switch (*c->json) {
        case 't':  return lept_parse_true(c, v);
        case 'f':  return lept_parse_false(c, v);
        case 'n':  return lept_parse_null(c, v);
        default:   return lept_parse_number(c, v);
        case '\0': return LEPT_PARSE_EXPECT_VALUE;
    }
}

static int lept_parse_true(lept_context* c, lept_value* v) {
    EXPECT(c, 't');
    if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e')
        return LEPT_PARSE_INVALID_VALUE;
    c->json += 3;
    v->type = LEPT_TRUE;
    return LEPT_PARSE_OK;
}

tutorial03

  • 字符串的解析涉及到转义字符 / 。一个解析出来的值不可能同时为数字或者字符串,数据结构这块采用了union来节省内存.左边是struct的内存图,右边是union的
typedef struct {
    union {
        struct { char* s; size_t len; }s;  /* string */
        double n;                          /* number */
    }u;
    lept_type type;
}lept_value;

这里写图片描述
- 字符串的动态malloc和free函数也写的很简洁

void lept_set_string(lept_value* v, const char* s, size_t len) {
    assert(v != NULL && (s != NULL || len == 0));
    lept_free(v);
    v->u.s.s = (char*)malloc(len + 1);
    memcpy(v->u.s.s, s, len);
    v->u.s.s[len] = '\0';
    v->u.s.len = len;
    v->type = LEPT_STRING;
}

void lept_free(lept_value* v) {
    assert(v != NULL);
    if (v->type == LEPT_STRING)
        free(v->u.s.s);
    v->type = LEPT_NULL;
}
  • 缓存这块用动态数组,JSON用stack来做缓存,就可以满足解析数据对象的存取
//加入stack对应数据结构
typedef struct {
    const char* json;
    char* stack;
    size_t size, top;
}lept_context;
//parse函数添加stack的初始化和最后的free操作
int lept_parse(lept_value* v, const char* json) {
    lept_context c;
    int ret;
    assert(v != NULL);
    c.json = json;
    c.stack = NULL;        /* <- */
    c.size = c.top = 0;    /* <- */
    lept_init(v);
    lept_parse_whitespace(&c);
    if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
        /* ... */
    }
    assert(c.top == 0);    /* <- 保证所有数据正常解析后都会被pop,stack最后为空*/
    free(c.stack);         /* <- */
    return ret;
}
//push和pop函数
//宏设置的好处是可以在编译选项中动态修改
#ifndef LEPT_PARSE_STACK_INIT_SIZE
#define LEPT_PARSE_STACK_INIT_SIZE 256
#endif

static void* lept_context_push(lept_context* c, size_t size) {
    void* ret;
    assert(size > 0);
    //当前stack容量不足,需动态增加
    if (c->top + size >= c->size) {
        if (c->size == 0)
            c->size = LEPT_PARSE_STACK_INIT_SIZE;
        while (c->top + size >= c->size)
            //位操作扩大为原来的1.5倍
            c->size += c->size >> 1;  /* c->size * 1.5 */
        //初始化的时候realloc(NULL,size)等价于malloc(size)
        c->stack = (char*)realloc(c->stack, c->size);
    }
    ret = c->stack + c->top;
    c->top += size;
    //返回push后的top的地址
    return ret;
}

static void* lept_context_pop(lept_context* c, size_t size) {
    assert(c->top >= size);
    return c->stack + (c->top -= size);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值