github.com/dacez/zzzjson

The fastest JSON parser written in pure C


Keywords
c, c-plus-plus, fast, json, json-parser, rapid
Install
go get github.com/dacez/zzzjson

Documentation

zzzJSON

简体中文

Abstract

  • Fastest parsing and serialization speed.

  • Wrote by pure C, no ambiguous grammar, easy to understand, compile, use and modify.

  • Only one header file.

  • Tencent is used on a large scale.

Parse on use

  • Like copy on write, zzzJSON only parse numbers when using get APIs.
  • zzzJSON only judge whether it is a correct number string when parsing JSON string into tree structure.

Benchmarks and Measurements

Simulate nativejson-benchmark

Conformance

Benchmark Description
Parse Validation Use JSON_checker test suite to test whether the library can identify valid and invalid JSONs. (fail01.json is excluded as it is relaxed in [RFC7159]. fail18.json is excluded as depth of JSON is not specified.)
Parse Double 66 JSONs, each with a decimal value in an array, are parsed. The parsed double values are compared to the correct answer.
Parse String 9 JSONs, each with a string value in an array, are parsed. The parsed strings are compared to the correct answer.
Roundtrip 27 condensed JSONs are parsed and stringified. The results are compared to the original JSONs.

Performance

Benchmark Description
Parse Parse in-memory JSON into tree structure.
Stringify Serialize tree structure into condensed JSON in memory.

Results

environment

CPU OS Compiler Optimization
i7-6700 (3.40GHZ) Ubuntu 18.04(WSL) G++-7.3 O3

conformance

zzzJSON pass all tests.(soure code: conformance_test.cpp)

performance

No Number JSON

Name Parse(ms) Stringify(ms) All(ms)
cjson 162 122 284
gason 60 321 398
jsoncpp 830 556 1588
nlohmannjson 994 312 1414
picojson 824 295 1214
rapidjson 128 92 224
rapidjsonfp 147 91 245
rapidjsonstr 127 89 225
taocppjson 724 261 1070
zzzjson 86 56 149

JSON From nativejson-benchmark

Name Parse(ms) Stringify(ms) All(ms)
arduinojson 779 25 807
cjson 53 183 230
gason 8 88 93
jsoncpp 88 126 221
nlohmannjson 62 24 91
parson 52 277 336
picojson 54 108 165
rapidjson 11 15 23
rapidjsonfp 20 17 39
rapidjsonstr 24 12 37
taocppjson 34 29 66
zzzjson 18 7 22

JSON From Taobao

Name Parse(ms) Stringify(ms) All(ms)
arduinojson 23 62 87
cjson 38 23 60
gason 9 51 63
jsoncpp 67 51 126
nlohmannjson 72 29 105
parson 48 85 141
picojson 54 35 96
rapidjson 18 12 28
rapidjsonfp 18 14 30
rapidjsonstr 16 12 29
taocppjson 47 28 86
zzzjson 14 7 23

All JSON Above

Name Parse(ms) Stringify(ms) All(ms)
arduinojson 2056 505 2508
cjson 243 345 596
gason 63 431 500
jsoncpp 451 431 961
nlohmannjson 518 217 840
parson 309 857 1214
picojson 405 387 862
rapidjson 97 119 220
rapidjsonfp 113 126 245
rapidjsonstr 116 121 240
taocppjson 278 207 561
zzzjson 95 59 166

Random Short JSON

Name Parse(ms) Stringify(ms) All(ms)
cjson 100 107 200
jsoncpp 136 127 284
nlohmannjson 177 58 242
picojson 94 95 205
rapidjson 31 39 56
rapidjsonfp 36 19 63
rapidjsonstr 37 35 60
taocppjson 90 50 143
zzzjson 26 16 38

Random Long JSON

Name Parse(ms) Stringify(ms) All(ms)
cjson 81 67 155
jsoncpp 130 112 244
nlohmannjson 199 42 254
picojson 127 93 222
rapidjson 24 17 45
rapidjsonfp 28 24 46
rapidjsonstr 30 24 48
taocppjson 100 34 149
zzzjson 20 9 29

You can use the commands below to get the results above

./build.sh all

Example

#include "zzzjson.h"
#include <stdio.h>

// DeepCopy
void GetAndSet(Value *srcv, Value *desv)
{
    // GetType
    const JSONType *t;
    t = Type(srcv);
    if (t == 0)
        return;
    switch (*t)
    {
    case JSONTYPEARRAY:
    {
        // DeepCopy Array
        SetArray(desv);
        Value *next = Begin(srcv);
        while (next != 0)
        {
            Value *v = NewValue(desv->A);
            GetAndSet(next, v);
            if (ArrayAddFast(desv, v) != True)
                return;
            next = Next(next);
        }
        break;
    }
    case JSONTYPEOBJECT:
    {
        // DeepCopy Object
        SetObj(desv);
        Value *next = Begin(srcv);
        while (next != 0)
        {
            Value *v = NewValue(desv->A);
            SetKeyFast(v, GetKey(next));
            GetAndSet(next, v);
            if (ObjAddFast(desv, v) != True)
                return;
            next = Next(next);
        }
        break;
    }
    case JSONTYPEBOOL:
    {
        // Copy Bool 
        const zzz_BOOL *b = GetBool(srcv);
        if (b == 0)
            return;
        SetBool(desv, *b);
        break;
    }
    case JSONTYPENULL:
    {
        // Copy nil
        if (IsNull(srcv) == False)
            return;
        SetNull(desv);
        break;
    }

    case JSONTYPESTRING:
    {
        // DeepCopy String
        const char *str = GetStr(srcv);
        if (str == 0)
            return;
        if (SetStrFast(desv, str) != True)
            return;
        break;
    }
    case JSONTYPENUMBER:
    {
        // DeepCopy Number
        const char *str = GetNumStr(srcv);
        if (str == 0)
            return;
        if (SetNumStrFast(desv, str) != True)
            return;
        break;
    }
    }
}
int main()
{
    const char *src_json = "[{\"key\":true},false,{\"key1\":true},[null,false,[],true],[\"\",123,\"str\"],null]";
    // New Allocator
    Allocator *A = NewAllocator();
    // New Value
    Value *src_v = NewValue(A);
    Value *des_v = NewValue(A);
    // Parse
    BOOL ret = ParseFast(src_v, src_json);
    if (ret != True)
    {
        printf("ParseFast Fail!\n");
        return 1;
    }
    // DeepCopy
    GetAndSet(src_v, des_v);
    // Stringify
    const char *des_json = Stringify(des_v);
    printf("src_json:%s\n", src_json);
    if (des_json != 0)
        printf("des_json:%s\n", des_json);
    // Free Allocator
    ReleaseAllocator(A);
    return 0;
}

API

Short APIs

Allocator *NewAllocator();
void ReleaseAllocator(Allocator *root_alloc);

Value *NewValue(Allocator *alloc);
BOOL ParseFast(Value *v, const char *s);
BOOL ParseLen(Value *v, const char *s, SIZE len);
BOOL Parse(Value *v, const char *s);
const char *Stringify(const Value *v);

const char *GetStrFast(const Value *v, SIZE *len);
const char *GetUnEscapeStr(Value *v);
const char *GetStr(Value *v);
const char *GetNumFast(const Value *v, zzz_SIZE *len);
const char *GetNumStr(Value *v);
const double *GetNum(Value *v);
const double *GetDouble(struct zzz_Value *v);
const int *GetInt(struct zzz_Value *v);
const long *GetLong(struct zzz_Value *v);
const long long *GetLongLong(struct zzz_Value *v);
const BOOL *GetBool(const Value *v);
BOOL IsNull(const Value *v);
const char *GetKey(Value *v);
const char *GetUnEscapeKey(Value *v);
const char *GetKeyFast(const Value *v, SIZE *len);
Value *ObjGet(const Value *v, const char *key);
Value *ObjGetLen(const Value *v, const char *key, SIZE len);
const JSONType *Type(const Value *v);
SIZE Size(const Value *v);
Value *ArrayGet(const Value *v, SIZE index);
Value *Begin(const Value *v);
Value *Next(const Value *v);

Value *Copy(const Value *v);
BOOL Move(Value *v);

BOOL SetNull(Value *v);
BOOL SetBool(Value *v, BOOL b);
BOOL SetNumStrFast(Value *v, const char *num);
BOOL SetNumStrLenFast(Value *v, const char *num, SIZE len);
BOOL SetNumStr(Value *v, const char *num);
BOOL SetNumStrLen(Value *v, const char *num, SIZE len);
BOOL SetNum(Value *v, const double d);
BOOL SetDouble(Value *v, const double d);
BOOL SetInt(Value *v, const int d);
BOOL SetLong(Value *v, const long d);
BOOL SetLongLong(Value *v, const long long d);
BOOL SetStrFast(Value *v, const char *str);
BOOL SetStrLenFast(Value *v, const char *str, SIZE len);
BOOL SetStr(Value *v, const char *str);
BOOL SetStrLen(Value *v, const char *str, SIZE len);
BOOL SetStrEscape(Value *v, const char *str);
BOOL SetStrLenEscape(Value *v, const char *str, SIZE len);
BOOL SetKeyFast(Value *v, const char *key);
BOOL SetKeyLenFast(Value *v, const char *key, SIZE len);
BOOL SetKey(Value *v, const char *key);
BOOL SetKeyLen(Value *v, const char *key, SIZE len);
BOOL SetKeyEscape(Value *v, const char *key);
BOOL SetKeyLenEscape(Value *v, const char *key, SIZE len);
BOOL SetArray(Value *v);
BOOL SetObj(Value *v);
BOOL SetFast(Value *v, Value *vv);
BOOL Set(Value *v, const Value *vv);
BOOL ObjAddFast(Value *v, Value *vv);
BOOL ObjAdd(Value *v, const Value *vv);
BOOL ArrayAddFast(Value *v, Value *vv);
BOOL ArrayAdd(Value *v, const Value *vv);

BOOL ArrayDel(Value *v, SIZE index);
BOOL ObjDel(Value *v, const char *key);

Long APIs

define “zzz_SHORT_API 0” to use long APIs

#define zzz_SHORT_API 0

// must be above to include

#include "zzzjson.h"

struct zzz_Allocator *zzz_AllocatorNew();
void zzz_AllocatorRelease(struct zzz_Allocator *root_alloc);

struct zzz_Value *zzz_ValueNew(struct zzz_Allocator *alloc);
zzz_BOOL zzz_ValueParseFast(struct zzz_Value *v, const char *s);
zzz_BOOL zzz_ValueParseLen(struct zzz_Value *v, const char *s, zzz_SIZE len);
zzz_BOOL zzz_ValueParse(struct zzz_Value *v, const char *s);
const char *zzz_ValueStringify(const struct zzz_Value *v);

const char *zzz_ValueGetStrFast(const struct zzz_Value *v, zzz_SIZE *len);
const char *zzz_ValueGetUnEscapeStr(struct zzz_Value *v);
const char *zzz_ValueGetStr(struct zzz_Value *v);
const char *zzz_ValueGetNumFast(const struct zzz_Value *v, zzz_SIZE *len);
const char *zzz_ValueGetNumStr(struct zzz_Value *v);
const double *zzz_ValueGetNum(struct zzz_Value *v);
const double *zzz_ValueGetDouble(struct zzz_Value *v);
const int *zzz_ValueGetInt(struct zzz_Value *v);
const long *zzz_ValueGetLong(struct zzz_Value *v);
const long long *zzz_ValueGetLongLong(struct zzz_Value *v);
const zzz_BOOL *zzz_ValueGetBool(const struct zzz_Value *v);
zzz_BOOL zzz_ValueIsNull(const struct zzz_Value *v);
const char *zzz_ValueGetKey(struct zzz_Value *v);
const char *zzz_ValueGetUnEscapeKey(struct zzz_Value *v);
const char *zzz_ValueGetKeyFast(const struct zzz_Value *v, zzz_SIZE *len);
struct zzz_Value *zzz_ValueObjGet(const struct zzz_Value *v, const char *key);
struct zzz_Value *zzz_ValueObjGetLen(const struct zzz_Value *v, const char *key, zzz_SIZE len);
const zzz_JSONType *zzz_ValueType(const struct zzz_Value *v);
zzz_SIZE zzz_ValueSize(const struct zzz_Value *v);
struct zzz_Value *zzz_ValueArrayGet(const struct zzz_Value *v, zzz_SIZE index);
struct zzz_Value *zzz_ValueBegin(const struct zzz_Value *v);
struct zzz_Value *zzz_ValueNext(const struct zzz_Value *v);

struct zzz_Value *zzz_ValueCopy(const struct zzz_Value *v);
zzz_BOOL zzz_ValueMove(struct zzz_Value *v);

zzz_BOOL zzz_ValueSetNull(struct zzz_Value *v);
zzz_BOOL zzz_ValueSetBool(struct zzz_Value *v, zzz_BOOL b);
zzz_BOOL zzz_ValueSetNumStrFast(struct zzz_Value *v, const char *num);
zzz_BOOL zzz_ValueSetNumStrLenFast(struct zzz_Value *v, const char *num, zzz_SIZE len);
zzz_BOOL zzz_ValueSetNumStr(struct zzz_Value *v, const char *num);
zzz_BOOL zzz_ValueSetNumStrLen(struct zzz_Value *v, const char *num, zzz_SIZE len);
zzz_BOOL zzz_ValueSetNum(struct zzz_Value *v, const double d);
zzz_BOOL zzz_ValueSetDouble(struct zzz_Value *v, const double d);
zzz_BOOL zzz_ValueSetInt(struct zzz_Value *v, const int n);
zzz_BOOL zzz_ValueSetLong(struct zzz_Value *v, const long n);
zzz_BOOL zzz_ValueSetLongLong(struct zzz_Value *v, const long long n);
zzz_BOOL zzz_ValueSetStrFast(struct zzz_Value *v, const char *str);
zzz_BOOL zzz_ValueSetStrLenFast(struct zzz_Value *v, const char *str, zzz_SIZE len);
zzz_BOOL zzz_ValueSetStr(struct zzz_Value *v, const char *str);
zzz_BOOL zzz_ValueSetStrLen(struct zzz_Value *v, const char *str, zzz_SIZE len);
zzz_BOOL zzz_ValueSetStrEscape(struct zzz_Value *v, const char *str);
zzz_BOOL zzz_ValueSetStrLenEscape(struct zzz_Value *v, const char *str, zzz_SIZE len);
zzz_BOOL zzz_ValueSetKeyFast(struct zzz_Value *v, const char *key);
zzz_BOOL zzz_ValueSetKeyLenFast(struct zzz_Value *v, const char *key, zzz_SIZE len);
zzz_BOOL zzz_ValueSetKey(struct zzz_Value *v, const char *key);
zzz_BOOL zzz_ValueSetKeyLen(struct zzz_Value *v, const char *key, zzz_SIZE len);
zzz_BOOL zzz_ValueSetKeyEscape(struct zzz_Value *v, const char *key);
zzz_BOOL zzz_ValueSetKeyLenEscape(struct zzz_Value *v, const char *key, zzz_SIZE len);
zzz_BOOL zzz_ValueSetArray(struct zzz_Value *v);
zzz_BOOL zzz_ValueSetObj(struct zzz_Value *v);
zzz_BOOL zzz_ValueSetFast(struct zzz_Value *v, struct zzz_Value *vv);
zzz_BOOL zzz_ValueSet(struct zzz_Value *v, const struct zzz_Value *vv);
zzz_BOOL zzz_ValueObjAddFast(struct zzz_Value *v, struct zzz_Value *vv);
zzz_BOOL zzz_ValueObjAdd(struct zzz_Value *v, const struct zzz_Value *vv);
zzz_BOOL zzz_ValueArrayAddFast(struct zzz_Value *v, struct zzz_Value *vv);
zzz_BOOL zzz_ValueArrayAdd(struct zzz_Value *v, const struct zzz_Value *vv);

zzz_BOOL zzz_ValueArrayDel(struct zzz_Value *v, zzz_SIZE index);
zzz_BOOL zzz_ValueObjDel(struct zzz_Value *v, const char *key);