TkTech / yyjson

The fastest JSON library in C

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

YYJSON

Build Codecov License

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 process int64, uint64 and double number accurately.
  • No Limit: support large data size, unlimited JSON level, \u0000 string.
  • Extendable: support comments, trailing commas, nan/inf, custom memory allocator.
  • Developer Friendly: only one h and one c file, easy to use API.

Performance

Intel Core i5-8259U (3.8GHz) with Clang 10

Reader Intel Writer Intel

twitter.json read (GB/s) write (GB/s)
yyjson(insitu) 2.36 1.90
yyjson 2.17 1.70
simdjson 2.21 0.84
sajson 1.04
rapidjson(insitu) 0.47
rapidjson(utf8) 0.26 0.74
cjson 0.32 0.19
jansson 0.07 0.19

Apple A12 (2.5GHz) with Clang 12

Reader Apple Writer Apple

twitter.json read (GB/s) write (GB/s)
yyjson(insitu) 2.57 1.94
yyjson 2.39 1.59
simdjson 1.78 0.75
sajson 1.41
rapidjson(insitu) 0.51
rapidjson(utf8) 0.39 0.51
cjson 0.28 0.27
jansson 0.06 0.20

Benchmark project: yyjson_benchmark

More benchmark reports with interactive 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.

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

Build shared library:

cmake ..-DBUILD_SHARED_LIBS=ON
cmake --build .

Supported CMake options:

  • -DYYJSON_BUILD_TESTS=ON Build all tests.
  • -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.

Usage Example

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));

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));
    }
} else {
    printf("read error: %s at position: %ld\n", err.msg, err.pos);
}

Write JSON file with options

yyjson_doc *idoc = yyjson_read_file("/tmp/test.json", 0, NULL, NULL);
yyjson_mut_doc *doc = yyjson_doc_mut_copy(idoc, 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);
}

Documentation

TODO

  • Add documentation page.
  • Add GitHub workflow for CI and codecov.
  • Add more tests: valgrind, sanitizer.
  • Add fuzzer.
  • Support JSON Pointer to query value from document.
  • Add documentation for performance.
  • Optimize performance for gcc.
  • Optimize performance for 32-bit processor.
  • Optimize performance of double number reader/writer with other algorithms [1] [2].

License

This project is released under the MIT license.

About

The fastest JSON library in C

License:MIT License


Languages

Language:C 97.6%Language:CMake 2.3%Language:Objective-C 0.1%Language:C++ 0.0%