guangmingwan / yyjson

The fastest JSON library in C

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

yyjson

Build Codecov License Version

A high performance JSON library written in ANSI C.

Features

  • Fast: can read or write gigabytes per second JSON data on modern CPU.
  • Portable: compliant with ANSI C (C89).
  • Standard: compliant with RFC 8259 and ECMA-404 standard.
  • Safe: complete JSON form, number format and UTF-8 validation.
  • Accuracy: can read and write int64, uint64 and double number accurately.
  • No Limit: support large data size, unlimited JSON level, \u0000 string.
  • Extendable: options to allow comments, trailing commas, nan/inf, custom memory allocator.
  • Developer Friendly: only one h and one c file, easy to use API.

Performance

Benchmark project and dataset: yyjson_benchmark

AWS EC2 (AMD EPYC 7R32, gcc 9.3)

ec2_chart

twitter.json parse (GB/s) stringify (GB/s)
yyjson(insitu) 1.80 1.51
yyjson 1.72 1.42
simdjson 1.52 0.61
sajson 1.16
rapidjson(insitu) 0.77
rapidjson(utf8) 0.26 0.39
cjson 0.32 0.17
jansson 0.05 0.11

iPhone (Apple A14, clang 12)

a14_chart

twitter.json parse (GB/s) stringify (GB/s)
yyjson(insitu) 3.51 2.41
yyjson 2.39 2.01
simdjson 2.19 0.80
sajson 1.74
rapidjson(insitu) 0.75
rapidjson(utf8) 0.30 0.58
cjson 0.48 0.33
jansson 0.09 0.24

More benchmark reports with interactive charts (update 2020-12-12)

Platform CPU Compiler OS Report
Intel NUC 8i5 Core i5-8259U msvc 2019 Windows 10 2004 Charts
Intel NUC 8i5 Core i5-8259U clang 10.0 Ubuntu 20.04 Charts
Intel NUC 8i5 Core i5-8259U gcc 9.3 Ubuntu 20.04 Charts
AWS EC2 c5a.large AMD EPYC 7R32 gcc 9.3 Ubuntu 20.04 Charts
AWS EC2 t4g.medium Graviton2 (ARM64) gcc 9.3 Ubuntu 20.04 Charts
Apple iPhone 12 Pro A14 (ARM64) clang 12.0 iOS 14 Charts

For better performance, yyjson prefers:

  • A modern processor with:
    • high instruction level parallelism
    • excellent branch predictor
    • low penalty for misaligned memory access
  • A modern compiler with good optimization.

Building

Manually

Just copy yyjson.h and yyjson.c to your project and start using it. Since yyjson is ANSI C compatible, no other configuration is needed typically.

We have tested yyjson with the following compilers: gcc, clang, msvc, icc, tcc. If you find a compile error, please report a bug.

yyjson includes all features by default, but you can trim out some of them by adding compile flags to get higher performance and/or smaller binary. See compile flags for details.

CMake

Clone repository and create build directory:

git clone https://github.com/ibireme/yyjson.git
mkdir build
cd build

Build static library:

cmake .. 
cmake --build .

Build static library and run tests:

cmake .. -DYYJSON_BUILD_TESTS=ON
cmake --build .
ctest

Supported CMake options:

  • -DYYJSON_BUILD_TESTS=ON Build all tests.
  • -DBUILD_SHARED_LIBS=ON Build shared library instead of static library.
  • -DYYJSON_ENABLE_COVERAGE=ON Enable code coverage for tests.
  • -DYYJSON_ENABLE_VALGRIND=ON Enable valgrind memory checker for tests.
  • -DYYJSON_ENABLE_SANITIZE=ON Enable sanitizer for tests.
  • -DYYJSON_DISABLE_READER=ON Disable JSON reader if you don't need it.
  • -DYYJSON_DISABLE_WRITER=ON Disable JSON writer if you don't need it.
  • -DYYJSON_DISABLE_FP_READER=ON Disable custom double number reader to reduce binary size.
  • -DYYJSON_DISABLE_FP_WRITER=ON Disable custom double number writer to reduce binary size.
  • -DYYJSON_DISABLE_COMMENT_READER=ON Disable non-standard comment support at compile time.
  • -DYYJSON_DISABLE_INF_AND_NAN_READER=ON Disable non-standard nan/inf support at compile time.

See compile flags for details.

Sample Code

Read JSON string

const char *json = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3]}";

yyjson_doc *doc = yyjson_read(json, strlen(json), 0);
yyjson_val *root = yyjson_doc_get_root(doc);

yyjson_val *name = yyjson_obj_get(root, "name");
printf("name: %s\n", yyjson_get_str(name));
printf("name length:%d\n", (int)yyjson_get_len(name));

yyjson_val *star = yyjson_obj_get(root, "star");
printf("star: %d\n", (int)yyjson_get_int(star));

yyjson_val *hits = yyjson_obj_get(root, "hits");
size_t idx, max;
yyjson_val *hit;
yyjson_arr_foreach(hits, idx, max, hit) {
    printf("hit%d: %d\n", (int)idx, (int)yyjson_get_int(hit));
}

yyjson_doc_free(doc);

Write JSON string

yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);

yyjson_mut_obj_add_str(doc, root, "name", "Mash");
yyjson_mut_obj_add_int(doc, root, "star", 4);

int hits_arr[] = {2, 2, 1, 3};
yyjson_mut_val *hits = yyjson_mut_arr_with_sint32(doc, hits_arr, 4);
yyjson_mut_obj_add_val(doc, root, "hits", hits);

const char *json = yyjson_mut_write(doc, 0, NULL);
if (json) {
    printf("json: %s\n", json); // {"name":"Mash","star":4,"hits":[2,2,1,3]}
    free((void *)json);
}

yyjson_mut_doc_free(doc);

Read JSON file with options

yyjson_read_err err;
yyjson_read_flag flg = YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS;
yyjson_doc *doc = yyjson_read_file("/tmp/test.json", flg, NULL, &err);

if (doc) {
    yyjson_val *obj = yyjson_doc_get_root(doc);
    yyjson_obj_iter iter;
    yyjson_obj_iter_init(obj, &iter);
    yyjson_val *key, *val;
    while ((key = yyjson_obj_iter_next(&iter))) {
        val = yyjson_obj_iter_get_val(key);
        printf("%s: %s\n", yyjson_get_str(key), yyjson_get_type_desc(val));
    }
    yyjson_doc_free(doc);
} else {
    printf("read error: %s at position: %ld\n", err.msg, err.pos);
}

Write JSON file with options

yyjson_mut_doc *doc = yyjson_mut_read_file("/tmp/test.json", 0, NULL, NULL);
yyjson_mut_val *obj = yyjson_mut_doc_get_root(doc);

yyjson_mut_obj_iter iter;
yyjson_mut_obj_iter_init(obj, &iter);
yyjson_mut_val *key, *val;
while ((key = yyjson_mut_obj_iter_next(&iter))) {
    val = yyjson_mut_obj_iter_get_val(key);
    if (yyjson_mut_is_null(val)) {
        yyjson_mut_obj_iter_remove(&iter);
    }
}

yyjson_write_err err;
yyjson_write_flag flg = YYJSON_WRITE_PRETTY | YYJSON_WRITE_ESCAPE_UNICODE;
yyjson_mut_write_file("/tmp/test.json", doc, flg, NULL, &err);
if (err.code) {
    printf("write error: %d, message: %s\n", err.code, err.msg);
}
yyjson_mut_doc_free(doc);

Documentation

TODO

  • Add documentation page.
  • Add GitHub workflow for CI and codecov.
  • Add more tests: valgrind, sanitizer.
  • Support JSON Pointer to query value from document.
  • Add fuzzer.
  • Add RAW type for JSON reader and writer.
  • Add streaming API for JSON reader and writer.
  • Add documentation about performance.
  • Optimize performance for 32-bit processor.

License

This project is released under the MIT license.

About

The fastest JSON library in C

License:MIT License


Languages

Language:C 97.4%Language:CMake 2.3%Language:Objective-C 0.2%Language:Swift 0.1%Language:C++ 0.0%