HN 日本語サマリー

← 一覧へ戻る
オープンソース

Capcom RE:Dox、ゲームエンジン向けのオープンソースシリアライゼーション/デシリアライゼーション

Capcom RE:Dox, open source serialization/deserialization for game engines (github.com)

31 pointsby vblanco7 コメント

要約

Capcomが開発したRE:Doxは、.NET向けの高性能トークンベース構造化データエンジンです。JSON、CBOR、MessagePack、TOML、XMLなど多様なフォーマットに対応し、単なるシリアライザではなく、構造化データをコンパクトなトークンDOM/IRに解析し、それを基に読み込み、編集、フォーマット変換、シリアライズ、デシリアライズ、自動並列デシリアライズを行います。これにより、従来のシリアライザが持つ速度、編集性、柔軟性のトレードオフを克服し、高速かつ低アロケーションなデータ処理を実現します。

全文翻訳

RE:Dox 1. RE:Doxとは何か? RE:Doxは、CAPCOMの次世代ゲームエンジン「REX」テクノロジーのコアコンポーネントの一つとして開発された、.NET向けの高性能トークンベース構造化データエンジンです。 RE:Doxは単なるJSONシリアライザではありません。構造化データをコンパクトで固定サイズのトークンDOM / IRに解析し、その構造インデックスを使用して読み込み、編集、フォーマット変換、シリアライズ、デシリアライズ、自動並列デシリアライズを行います。 JSON / JSON5 / CBOR / MessagePack / TOML / XML / HTML / CSV / INI / DOX ↓ コンパクトなトークンDOM / IR ↓ Reader / Writer / Serializer / Deserializer ↓ .NETオブジェクト、JSON、CBOR、MessagePack、TOML、XML、HTML、DOX、... 同じトークン表現は、コンパクトな解析済みドキュメントモデルと、シリアライザ、コンバータ、サポートされているフォーマット間で共有される共通の構造レイヤーの両方として機能します。 2. なぜ気にかけるべきか? RE:Doxは、通常は相反する3つの目標を組み合わせています。テープDOM (System.Text.Json.JsonDocument) の解析速度、ノードDOM (System.Text.Json.Nodes.JsonNode) の編集性、Newtonsoft.Jsonの柔軟性 (位置に依存しない $type, $id / $ref、順不同のコンストラクタバインディング)。 得られるもの: 高性能なシリアライズとデシリアライズ — ベンチマークデータセットでは、System.Text.Jsonと比較して最大約1.8倍高速なシーケンシャルデシリアライズ、最大約2.8倍高速な自動並列デシリアライズ、最大約1.6倍高速なシリアライズを実現します。 テストされたワークロードでのアロケーション削減 — 例えば、canada.jsonのデシリアライズでは、RE:Doxは約2.56 MB、System.Text.Jsonは約8.53 MBをアロケーションします。 JSON、JSON5、CBOR、MessagePack、INI、DOXはコアモデルに統合されています。TOML、XML、HTML、CSVは現在プレビューコンポーネントです。 フォーマットを横断する単一のコンバータモデル — DataConverter<T>は、特定のワイヤーフォーマットではなく、フォーマットに依存しないDataReader / DataWriter抽象化をターゲットとしています。 ミュータブルなトークンDOM — 重いマネージドオブジェクトツリーでドキュメントを置き換えることなく、オブジェクトと配列を編集できます。 トリビアを保持するJSON5編集 — コメントやその他の保持されたトリビアは、ドキュメントの編集と再エンコード後も存続できます。 System.Text.Json、Newtonsoft.Json、DataContractJsonSerializerとの互換性レイヤー。 Apache-2.0ライセンス。 3. 30秒の例 コアパッケージをインストールします: dotnet add package CAPCOM.REDox 同じAPIサーフェスを通じて、シリアライズ、デシリアライズ、パース、編集を行います: using REDox.Json; var player = new Player { Name = "Leon", Level = 42, Items = ["Handgun", "Green Herb"] }; // シリアライズ / デシリアライズ var json = JsonSerializer.Serialize(player); var restored = JsonSerializer.Deserialize<Player>(json); // トークンDOMにパースしてインプレースで編集します using var doc = JsonDocument.Parse(json); var root = doc.RootElement.AsObject(); root["Name"] = "Claire"; // 置換 root.Add("Hp", 100); // 追加 root.Remove("Level"); // 削除 var items = root["Items"].AsArray(); items.Add("First Aid Spray"); // 追加 items.Insert(0, "Knife"); // 先頭に挿入 items.RemoveAt(1); // インデックスで削除 var edited = doc.RootElement.ToJsonString(); public sealed class Player { public string? Name { get; set; } public int Level { get; set; } public string[] Items { get; set; } = []; } 4. パフォーマンス 環境: BenchmarkDotNet, .NET 10 (X64 RyuJIT x86-64-v3), AMD Ryzen Threadripper PRO 5975WX, Windows 11。 概要: System.Text.Jsonに対する速度向上 | Dataset | Deserialize | Deserialize (parallel) | Serialize | |---------------|-------------|------------------------|-----------| | canada.json | 1.68x | 2.84x | 1.06x | | citm_catalog.json | 1.77x | 2.25x | 1.62x | | twitter.json | 1.36x | 2.34x | 1.42x | これらの比率は以下のベンチマークデータセットに対するものであり、普遍的なパフォーマンス保証ではありません。 デシリアライズ: canada.json (数値中心、約2.2 MB) | Dataset | Mean / Allocated (RE:Dox) | Mean / Allocated (RE:Dox (parallel)) | Mean / Allocated (System.Text.Json) | Mean / Allocated (STJ (JsonTypeInfo)) | Mean / Allocated (Utf8Json) | |---------------|-------------------------|------------------------------------|-------------------------------------|---------------------------------------|-----------------------------| | canada.json | 9,113.0 us / 2,619.92 KB | 5,384.6 us / 2,685.11 KB | 15,303.1 us / 8,734.66 KB | 15,005.9 us / 8,734.59 KB | 15,864.0 us / 6,655.67 KB | | citm_catalog.json | 2,280.5 us / 553.55 KB | 1,795.8 us / 631.87 KB | 4,041.1 us / 1,175.38 KB | 3,940.8 us / 1,175.38 KB | 2,605.5 us / 1,124.13 KB | | twitter.json | 1,008.8 us / 504.91 KB | 587.4 us / 555.84 KB | 1,371.6 us / 557.09 KB | 1,401.6 us / 557.09 KB | 1,370.6 us / 530.05 KB | シリアライズ: Mean / Allocated | Dataset | RE:Dox | System.Text.Json | STJ (JsonTypeInfo) | Utf8Json | |---------------|-------------------------|-----------------------------------|-----------------------------------|-----------------------------| | canada.json | 13,615.5 us / 2,041.41 KB | 14,388.3 us / 2,042.85 KB | 14,433.1 us / 2,042.85 KB | 11,714.2 us / 6,042.21 KB | | citm_catalog.json | 668.7 us / 494.41 KB | 1,085.4 us / 494.85 KB | 1,073.8 us / 494.87 KB | 707.3 us / 1,389.64 KB | | twitter.json | 557.3 us / 465.15 KB | 789.0 us / 467.95 KB | 800.3 us / 467.91 KB | 709.4 us / 1,361.37 KB | 再現方法: dotnet run -c Release --project benchmarks/REDox.Json.Benchmarks ベンチマーク結果は、データ形状、ターゲット型、ランタイム、CPU、シリアライザオプションによって異なります。常に独自のワークロードでベンチマークを行ってください。 5. アーキテクチャ コアにある64ビットデュアルモードトークン すべての値は固定サイズの64ビットトークンによって記述されます。拡張ビットは、ペイロードの解釈方法を選択します。 拡張ビット = 0 → ペイロードの解釈はドキュメント/フォーマットレイヤーに委任されます(ソースベース、フォーマット固有のペイロード。多くのフォーマット、1つのトークン形状)。 拡張ビット = 1 → ペイロードの解釈はRE:Doxによって固定され、制御トークンがフォーマットに依存しない編集(挿入/削除/置換)を可能にします。 これにより、1つのトークン構造が、フォーマットデータのソースベースのビューと、シリアライザ、コンバータ、サポートされているフォーマット間で共有される共通の構造レイヤーの両方として機能します。 ドキュメント/フォーマットレイヤーが元のペイロードを保持できる場合、変更されていない値は、早期にマテリアライズされることなく、ソーススライスを再利用し続けることができます。 トークンは、null、ブール値、整数、浮動小数点数、文字列、バイナリ、タイムスタンプ、大きな数値、配列、マップ/オブジェクト、トリビア(コメント/空白)、またはフォーマット固有の拡張データを表すことができます。インラインデータ、ソースオフセット/長さ、コンテナ数、リンク情報、または拡張IDを格納できます。 非対称な読み書き設計 読み込みと書き込みでは異なる情報要件があるため、RE:Doxはそれぞれ異なるパスを使用します。 シリアライズ: DataWriter、1パス、直接出力バッファに書き込まれます(情報は既知 → 先読みなし、中間DOMなし)。 デシリアライズ: トークンDOM上のDataReader、トークンIDによるランダムアクセス(情報は不明 → 先読み、順不同、コンテキストルックアップ)。 書き込みパスでは値は既にわかっているため、RE:Doxはバルク (WriteValues) およびフューズドプロパティ (WriteProperty*) ヘルパーを使用して直接バッファに書き込みます。中間オブジェクトツリーは構築されません。 読み込みパスでは構造が不明なため、RE:DoxはまずコンパクトなトークンDOMを構築します。構造が完全にアドレス可能になったため、RE:Doxは以下を実行できます。 配列とコレクションの事前サイズ設定。 マテリアライズする前に各要素のトークンIDを知る。 $type をオブジェクト内のどこにあっても解決する。 コンストラクタ引数を順不同で収集し、一度だけバインドする(レコードとプライマリコンストラクタ)。 ドキュメント全体のコンテキストを使用して $id / $ref サイクルを解決する。 シーケンシャルまたはパラレルデシリアライズを自動的に選択する。 要求されたときにのみ文字列と数値をデコードする。 変更されていない値に対して、生のソーススライスを再利用する。 遅延デコードとオンデマンドマテリアライゼーション トークンは、元のソースバッファへのオフセットと長さを格納できます。文字列、数値、タイムスタンプ、バイナリ値は、要求されたときにのみデコードされます。要素はドキュメントとトークンID上の軽量ハンドルであり、オブジェクトと配列ビューは必要になったときにのみマテリアライズされます。 ミュータブルなテープDOM テープDOMは通常読み取り専用ですが、その論理構造はフラットなトークンシーケンスによって表されます。RE:Doxはコンテナビューに間接参照を追加します。DArray、DObject、DMapは、再リンク可能な値スロットを保持し、フリーリストは空になったトークンスロットを再利用し、拡張/制御トークンは編集状態を運びます。これにより、シーケンシャルなトークン表現のキャッシュフレンドリーな特性を維持しながら、ドキュメント全体を編集ごとに再構築することなく、挿入、削除、置換などのノードライクな操作を提供できます。 ユニファイドコンバータ コンバータ (DataConverter<T>) は、仕様に直接対するのではなく、フォーマットに依存しないDataReader / DataWriter抽象化に対して記述されます。