このページの内容

概要

Build Codecov License Version Packaging status

ANSI Cで書かれた高性能なJSONライブラリです。

特徴

  • 高速:現代のCPUでは、毎秒数ギガバイトのJSONデータを読み書きできます。
  • 移植性:ANSI C(C89)に準拠し、SIMDを明示的には使用しません。
  • 厳密:RFC 8259のJSON標準に準拠し、数値形式の厳密な処理とUTF-8の検証を行います。
  • 拡張性:JSON5の各機能や独自アロケーターを有効にするオプションを用意しています。
  • 正確:int64、uint64、doubleの数値を正確に読み書きできます。
  • 柔軟性:JSONのネスト段数に制限がなく、\u0000文字やNUL終端されていない文字列に対応します。
  • 操作:JSON Pointer、JSON Patch、JSON Merge Patchを使った検索と変更に対応します。
  • 開発者に使いやすい:.hファイル1つと.cファイル1つだけで簡単に組み込めます。

制限

  • 配列やオブジェクトは、連結リストのようなデータ構造で格納されます。そのため、インデックスやキーによる要素へのアクセスは、イテレーターを使う場合より遅くなります。
  • オブジェクトのキーは重複を許容し、キーの順序は保持されます。
  • JSONの解析結果は不変です。変更するには可変のコピーを作る必要があります。

性能

ベンチマーク用のプロジェクトとデータセット:yyjson_benchmark

JSONのフィールドの大半がコンパイル時に分かっている場合、simdjsonの新しいOn Demand APIのほうが高速です。 このベンチマーク用プロジェクトはDOM APIだけを検査しています。新しいベンチマークは今後追加する予定です。

AWS EC2(AMD EPYC 7R32、gcc 9.3)

ec2_chart
Original image / 図の原寸表示
twitter.json解析(GB/s)文字列化(GB/s)
yyjson(insitu)1.801.51
yyjson1.721.42
simdjson1.520.61
sajson1.16
rapidjson(insitu)0.77
rapidjson(utf8)0.260.39
cjson0.320.17
jansson0.050.11

iPhone(Apple A14、clang 12)

a14_chart
Original image / 図の原寸表示
twitter.json解析(GB/s)文字列化(GB/s)
yyjson(insitu)3.512.41
yyjson2.392.01
simdjson2.190.80
sajson1.74
rapidjson(insitu)0.75
rapidjson(utf8)0.300.58
cjson0.480.33
jansson0.090.24

対話型グラフを含む、その他のベンチマークレポート(最終更新日:2020-12-12)

プラットフォームCPUコンパイラーOSレポート
Intel NUC 8i5Core i5-8259Umsvc 2019Windows 10 2004グラフ
Intel NUC 8i5Core i5-8259Uclang 10.0Ubuntu 20.04グラフ
Intel NUC 8i5Core i5-8259Ugcc 9.3Ubuntu 20.04グラフ
AWS EC2 c5a.largeAMD EPYC 7R32gcc 9.3Ubuntu 20.04グラフ
AWS EC2 t4g.mediumGraviton2 (ARM64)gcc 9.3Ubuntu 20.04グラフ
Apple iPhone 12 ProA14 (ARM64)clang 12.0iOS 14グラフ

より良い性能を得るために、yyjsonが適している環境

  • 次の特性を持つ現代のプロセッサー:
    • 命令レベルの並列性が高い
    • 分岐予測が優れている
    • メモリアクセスがアラインメントに沿わない場合のペナルティーが小さい
  • 優れた最適化器を備えた現代のコンパイラー(clangなど)

サンプルコード

JSON文字列を読み込む

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);
yyjson_val *root = yyjson_doc_get_root(doc);

// 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_val *hit;
yyjson_arr_foreach(hits, idx, max, hit) {
    printf("hit%d: %d\n", (int)idx, (int)yyjson_get_int(hit));
}

// Free the doc
yyjson_doc_free(doc);

// All functions accept NULL input, and return NULL on error.

JSON文字列を書き出す

// Create a mutable doc
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);

// 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_mut_doc_free(doc);

オプションを指定してJSONファイルを読み込む

// Read JSON file, allowing comments and trailing commas
yyjson_read_flag flg = YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS;
yyjson_read_err err;
yyjson_doc *doc = yyjson_read_file("/tmp/config.json", flg, NULL, &err);

// Iterate over the root object
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 (%u): %s at position: %ld\n", err.code, err.msg, err.pos);
}

// Free the doc
yyjson_doc_free(doc);

オプションを指定してJSONファイルを書き出す

// Read the JSON file as a mutable doc
yyjson_doc *idoc = yyjson_read_file("/tmp/config.json", 0, NULL, NULL);
yyjson_mut_doc *doc = yyjson_doc_mut_copy(idoc, NULL);
yyjson_mut_val *obj = yyjson_mut_doc_get_root(doc);

// Remove null values in root object
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);
    }
}

// Write the JSON with pretty printing, escape unicode
yyjson_write_flag flg = YYJSON_WRITE_PRETTY | YYJSON_WRITE_ESCAPE_UNICODE;
yyjson_write_err err;
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_doc_free(idoc);
yyjson_mut_doc_free(doc);

ドキュメント

最新の(未リリースの)文書はdocディレクトリで参照できます。 リリース版について事前生成されたDoxygen HTMLは、次の場所で閲覧できます。

パッケージ提供状況

Packaging status

yyjsonを使って作られたもの

yyjsonをほかの言語から使えるようにするプロジェクトや、主要な機能の内部でyyjsonを使うプロジェクトの、網羅的ではない一覧です。 yyjsonを使うプロジェクトをお持ちでしたら、一覧への追加を提案するPRを気軽に送ってください。

プロジェクト言語説明
ssrJSONPythonyyjsonを基盤とする、SIMDで高速化された高性能かつ正確なPythonのJSON解析ライブラリ
py_yyjsonPythonyyjsonのPythonバインディング
orjsonPythonyyjsonのバックエンドを任意で使えるPython用JSONライブラリ
serinC++ / PythonTOON、JSON、YAMLに対応し、形式をまたいで変換できるC++・Pythonのシリアライズライブラリ
cpp-yyjsonC++yyjsonのバックエンドを持つC++用JSONライブラリ
reflect-cppC++構造体からフィールド名を自動取得してシリアライズするC++ライブラリ
xyjsonC++便利な演算子オーバーロードを備えた、yyjsonのC++プロキシーおよびラッパー
yyjsonrRyyjsonのRバインディング
AnandaSwiftyyjsonを用いたJSONモデルのデコード
ReerJSONSwiftJSONDecoderに代わる、より高速なもの
swift-yyjsonSwiftyyjsonを基盤とする高速なSwift用JSONライブラリ
duckdbC++プロセス内で動作するSQL OLAPデータベース管理システム
fastfetchCシステム情報を見やすく表示する、Cで書かれたneofetchのようなツール
ZrythmCJSONプロジェクトファイルのシリアライズにyyjsonを使うデジタルオーディオワークステーション
bemorehumanC推薦を受ける人の固有性を重視する推薦エンジン
mruby-yyjsonmrubymruby向けの、yyjsonを使った効率的なJSON解析とシリアライズ
YYJSON.jlJuliayyjsonのJuliaバインディング
yyjson-goGoGoへ変換されたyyjson。CGoを使わず、2〜4倍高速
nim-yyjsonNimyyjsonの薄いNimバインディング

v1.0に向けたTODO

  • ドキュメントページを追加する。
  • CIとcodecov用のGitHub workflowを追加する。
  • valgrind、sanitizer、fuzzingなどのテストを増やす。
  • 検索・変更のためのJSON Pointerに対応する。
  • JSONのリーダーとライターにRAW型を追加する。
  • 実数の出力精度を制限するオプションを追加する。
  • JSON5をサポートするオプションを追加する。
  • ストリーミングJSON APIを追加する。
  • 2つのJSONドキュメントの差分を求める関数を追加する。
  • 性能最適化についての文書を追加する。
  • ABIの安定性を確保する。

ライセンス

このプロジェクトはMITライセンスで公開されています。