yyjson 0.5.0
A high performance C JSON library.
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: compliance with ANSI C (C89).
  • Standard: strict compliance with RFC 8259 standard.
  • Safe: complete JSON form, number format and UTF-8 validation.
  • Accuracy: can read and write int64, uint64 and double numbers accurately.
  • Less Restriction: support unlimited JSON level, \u0000 and non null-terminated string.
  • Extendable: options to allow comments, trailing commas, nan/inf, custom memory allocator.
  • Developer Friendly: only one h and one c file, easy to integrate.

Limitations

  • An array or object is stored as some data structure like linked list, access elements with index or key is slower than iterator.
  • Duplicate keys are allowed in an object, and the order of the keys is preserved.
  • JSON parsing result is immutable, a mutable copy is required for modification.

Performance

Benchmark project and dataset: yyjson_benchmark

The simdjson's new On Demand API is faster if most JSON fields are known at compile-time. This benchmark project only checks the DOM API, a new benchmark will be added later.

AWS EC2 (AMD EPYC 7R32, gcc 9.3)

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)

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 optimizer.

Build and test

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.

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

yyjson has all features enabled by default, but you can trim out some of them by adding compile-time options. For example, disable JSON writer to reduce the binary size when you don't need serialization, or disable comments support to improve parsing performance. See compile-time options for details.

CMake

Clone the 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:

  • -DBUILD_SHARED_LIBS=ON Build shared library instead of static library.
  • -DYYJSON_BUILD_TESTS=ON Build all 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_FAST_FP_CONV=ON Disable fast floating-point number conversion.
  • -DYYJSON_DISABLE_NON_STANDARD=ON Disable non-standard JSON support at compile-time.

More details

Sample Code

Read JSON string

const char *json = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3]}";
// Read JSON and get root
yyjson_doc *doc = yyjson_read(json, strlen(json), 0);
// Get root["name"]
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));
// Get root["star"]
yyjson_val *star = yyjson_obj_get(root, "star");
printf("star: %d\n", (int)yyjson_get_int(star));
// Get root["hits"], iterate over the array
yyjson_val *hits = yyjson_obj_get(root, "hits");
size_t idx, max;
yyjson_arr_foreach(hits, idx, max, hit) {
printf("hit%d: %d\n", (int)idx, (int)yyjson_get_int(hit));
}
// Free the doc
// All functions accept NULL input, and return NULL on error.
yyjson_api_inline yyjson_val * yyjson_obj_get(yyjson_val *obj, const char *key)
Definition: yyjson.h:3713
yyjson_api_inline int yyjson_get_int(yyjson_val *val)
Definition: yyjson.h:3574
#define yyjson_arr_foreach(arr, idx, max, val)
Definition: yyjson.h:1440
yyjson_api_inline const char * yyjson_get_str(yyjson_val *val)
Definition: yyjson.h:3582
yyjson_api_inline yyjson_val * yyjson_doc_get_root(yyjson_doc *doc)
Definition: yyjson.h:3442
yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc)
Definition: yyjson.h:3454
yyjson_api_inline size_t yyjson_get_len(yyjson_val *val)
Definition: yyjson.h:3586
yyjson_api_inline yyjson_doc * yyjson_read(const char *dat, size_t len, yyjson_read_flag flg)
Definition: yyjson.h:738
Definition: yyjson.h:3271
Definition: yyjson.h:3266

Write JSON string

// Create a mutable doc
// Set root["name"] and root["star"]
yyjson_mut_obj_add_str(doc, root, "name", "Mash");
yyjson_mut_obj_add_int(doc, root, "star", 4);
// Set root["hits"] with an array
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);
// To string, minified
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);
}
// Free the doc
yyjson_api_inline bool yyjson_mut_obj_add_val(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, yyjson_mut_val *val)
Definition: yyjson.h:5417
yyjson_api_inline yyjson_mut_val * yyjson_mut_arr_with_sint32(yyjson_mut_doc *doc, const int32_t *vals, size_t count)
Definition: yyjson.h:4409
yyjson_api_inline bool yyjson_mut_obj_add_int(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, int64_t val)
Definition: yyjson.h:5348
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj(yyjson_mut_doc *doc)
Definition: yyjson.h:5011
yyjson_api void yyjson_mut_doc_free(yyjson_mut_doc *doc)
yyjson_api_inline char * yyjson_mut_write(const yyjson_mut_doc *doc, yyjson_write_flag flg, size_t *len)
Definition: yyjson.h:1033
yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc, yyjson_mut_val *root)
Definition: yyjson.h:3919
yyjson_api_inline bool yyjson_mut_obj_add_str(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, const char *val)
Definition: yyjson.h:5368
yyjson_api yyjson_mut_doc * yyjson_mut_doc_new(const yyjson_alc *alc)
Definition: yyjson.h:3858
Definition: yyjson.h:3826

Read JSON file with options

// Read JSON file, allowing comments and trailing commas
yyjson_doc *doc = yyjson_read_file("/tmp/config.json", flg, NULL, &err);
// Iterate over the root object
if (doc) {
yyjson_obj_iter_init(obj, &iter);
yyjson_val *key, *val;
while ((key = yyjson_obj_iter_next(&iter))) {
printf("%s: %s\n", yyjson_get_str(key), yyjson_get_type_desc(val));
}
} else {
printf("read error (%u): %s at position: %ld\n", err.code, err.msg, err.pos);
}
// Free the doc
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS
Definition: yyjson.h:588
yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj, yyjson_obj_iter *iter)
Definition: yyjson.h:3749
yyjson_api_inline yyjson_val * yyjson_obj_iter_get_val(yyjson_val *key)
Definition: yyjson.h:3776
uint32_t yyjson_read_flag
Definition: yyjson.h:561
yyjson_api_inline const char * yyjson_get_type_desc(yyjson_val *val)
Definition: yyjson.h:3542
yyjson_read_code code
Definition: yyjson.h:661
yyjson_api_inline yyjson_val * yyjson_obj_iter_next(yyjson_obj_iter *iter)
Definition: yyjson.h:3766
yyjson_api yyjson_doc * yyjson_read_file(const char *path, yyjson_read_flag flg, const yyjson_alc *alc, yyjson_read_err *err)
size_t pos
Definition: yyjson.h:665
const char * msg
Definition: yyjson.h:663
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS
Definition: yyjson.h:591
Definition: yyjson.h:3742
Definition: yyjson.h:659

Write JSON file with options

// Read the JSON file as a mutable doc
yyjson_doc *idoc = yyjson_read_file("/tmp/config.json", 0, NULL, NULL);
// Remove null values in root object
yyjson_mut_val *key, *val;
while ((key = yyjson_mut_obj_iter_next(&iter))) {
if (yyjson_mut_is_null(val)) {
}
}
// Write the json pretty, escape unicode
yyjson_mut_write_file("/tmp/config.json", doc, flg, NULL, &err);
if (err.code) {
printf("write error (%u): %s\n", err.code, err.msg);
}
// Free the doc
yyjson_api yyjson_mut_doc * yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc)
yyjson_api_inline bool yyjson_mut_is_null(yyjson_mut_val *val)
Definition: yyjson.h:3934
const char * msg
Definition: yyjson.h:875
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_iter_next(yyjson_mut_obj_iter *iter)
Definition: yyjson.h:4944
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_iter_remove(yyjson_mut_obj_iter *iter)
Definition: yyjson.h:4961
yyjson_api_inline yyjson_mut_val * yyjson_mut_doc_get_root(yyjson_mut_doc *doc)
Definition: yyjson.h:3915
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_iter_get_val(yyjson_mut_val *key)
Definition: yyjson.h:4956
static const yyjson_write_flag YYJSON_WRITE_ESCAPE_UNICODE
Definition: yyjson.h:822
yyjson_api bool yyjson_mut_write_file(const char *path, const yyjson_mut_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc, yyjson_write_err *err)
yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj, yyjson_mut_obj_iter *iter)
Definition: yyjson.h:4926
yyjson_write_code code
Definition: yyjson.h:873
static const yyjson_write_flag YYJSON_WRITE_PRETTY
Definition: yyjson.h:819
uint32_t yyjson_write_flag
Definition: yyjson.h:809
Definition: yyjson.h:4918
Definition: yyjson.h:871

Documentation

TODO

  • [x] Add documentation page.
  • [x] Add GitHub workflow for CI and codecov.
  • [x] Add more tests: valgrind, sanitizer.
  • [x] Support JSON Pointer to query value from document.
  • [x] Add fuzzer.
  • [x] 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.