aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64
diff options
context:
space:
mode:
Diffstat (limited to 'research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64')
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/complete.json5
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/environment.json96
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/fixtures.json128
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/plan.json177
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.csv211
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.json12532
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/benchmark.c391
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/plan.json32
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/run.py351
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/LICENSE21
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/UPSTREAM.json23
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.c11065
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.h8230
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/summary.json4006
-rw-r--r--research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/verification.json114
15 files changed, 37382 insertions, 0 deletions
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/complete.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/complete.json
new file mode 100644
index 0000000..5bde4c3
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/complete.json
@@ -0,0 +1,5 @@
+{
+ "samples": 210,
+ "all_branch_outputs_match": true,
+ "finished_utc": "2026-09-22T13:11:31Z"
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/environment.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/environment.json
new file mode 100644
index 0000000..3aa2455
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/environment.json
@@ -0,0 +1,96 @@
+{
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "python": "3.14.7",
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0\nCopyright (C) 2024 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n",
+ "cpu_affinity": 0,
+ "builds": [
+ {
+ "command": [
+ "cc",
+ "-std=c17",
+ "-O2",
+ "-g",
+ "-Wall",
+ "-Wextra",
+ "-Wpedantic",
+ "-Werror",
+ "-DYYJSON_DISABLE_WRITER=1",
+ "-DYYJSON_DISABLE_UTILS=1",
+ "-DYYJSON_DISABLE_INCR_READER=1",
+ "/home/eunhhu/work/pure/research/experiments/003-json-fanout/benchmark.c",
+ "/home/eunhhu/work/pure/research/experiments/003-json-fanout/vendor/yyjson/yyjson.c",
+ "-o",
+ "/tmp/pure-fanout-i4xs4fhg/benchmark"
+ ],
+ "stderr": "",
+ "sha256": "adfd209a990abe11bfd93337c56eb2c9266d6529899fc91cd2f3844c93ef67db",
+ "size_bytes": 842056,
+ "build_wall_ns": 15110774980
+ },
+ {
+ "command": [
+ "cc",
+ "-std=c17",
+ "-O2",
+ "-g",
+ "-Wall",
+ "-Wextra",
+ "-Wpedantic",
+ "-Werror",
+ "-DYYJSON_DISABLE_WRITER=1",
+ "-DYYJSON_DISABLE_UTILS=1",
+ "-DYYJSON_DISABLE_INCR_READER=1",
+ "-O1",
+ "-fsanitize=address,undefined",
+ "-fno-omit-frame-pointer",
+ "/home/eunhhu/work/pure/research/experiments/003-json-fanout/benchmark.c",
+ "/home/eunhhu/work/pure/research/experiments/003-json-fanout/vendor/yyjson/yyjson.c",
+ "-o",
+ "/tmp/pure-fanout-i4xs4fhg/benchmark-sanitized"
+ ],
+ "stderr": "",
+ "sha256": "c7516cf3c1c18463c72b96a75d70cc326a0ff43873fa278e0b13fb94d6e180d2",
+ "size_bytes": 5441872,
+ "build_wall_ns": 160671462690
+ }
+ ],
+ "source_sha256": {
+ "benchmark.c": "c9ccc4544ef296eb59a8d071ad7fb25afc4b3fe5a94a8978c415c557b8ea8d0d",
+ "run.py": "7ab64e454f3ce0a48c20a477d8924b06ece6ad29a442d0bb49f48b5a6ecffe49",
+ "plan.json": "69f1258b3afd616404c6853526a5fbb6523d406eb43db479fd4be43905bc9f5d",
+ "vendor/yyjson/UPSTREAM.json": "eab60a505ff59ca1f3271792c16aa57d61f596cb5c57ff04dcff15d22ba29cee",
+ "vendor/yyjson/yyjson.c": "ac2e9bbb2e2d9149d90878d40506a1d624fa0b33c979a11b61075c54782c6d6a",
+ "vendor/yyjson/yyjson.h": "175867c5493a5df648cec566717fa1c29aa2f6096f5f0cf1efad0b65e1f6d7b3",
+ "vendor/yyjson/LICENSE": "45e384d3d52c73cba3a64d6e6c25d47cd738cd8a55c30629e3201046eda62947"
+ },
+ "upstream": {
+ "project": "yyjson",
+ "version": "0.12.0",
+ "commit": "8b4a38dc994a110abaec8a400615567bd996105f",
+ "license": "MIT",
+ "files": {
+ "yyjson.c": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/src/yyjson.c",
+ "sha256": "ac2e9bbb2e2d9149d90878d40506a1d624fa0b33c979a11b61075c54782c6d6a",
+ "bytes": 410813
+ },
+ "yyjson.h": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/src/yyjson.h",
+ "sha256": "175867c5493a5df648cec566717fa1c29aa2f6096f5f0cf1efad0b65e1f6d7b3",
+ "bytes": 322407
+ },
+ "LICENSE": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/LICENSE",
+ "sha256": "45e384d3d52c73cba3a64d6e6c25d47cd738cd8a55c30629e3201046eda62947",
+ "bytes": 1084
+ }
+ }
+ },
+ "timing": "I/O, parsing, selection, consumers, instrumentation, cleanup; excludes setup/build/verification",
+ "parse_call_ns": "wall duration inside yyjson_read_opts including allocator backpressure and serviced consumers",
+ "rss": "Linux current-image VmHWM approximate; zero means unavailable on other OSes",
+ "limits": "synthetic closed-loop arrivals/delays; one thread; uncontrolled thermals/power; cached file I/O; no fsync",
+ "started_utc": "2026-09-22T13:10:45Z",
+ "cpuinfo": "processor\t: 0\nBogoMIPS\t: 108.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x4\nCPU part\t: 0xd0b\nCPU revision\t: 1\n\nprocessor\t: 1\nBogoMIPS\t: 108.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x4\nCPU part\t: 0xd0b\nCPU revision\t: 1\n\nprocessor\t: 2\nBogoMIPS\t: 108.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x4\nCPU part\t: 0xd0b\nCPU revision\t: 1\n\nprocessor\t: 3\nBogoMIPS\t: 108.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x4\nCPU part\t: 0xd0b\nCPU revision\t: 1\n\nRevision\t: d04171\nSerial\t\t: d3ba8e625dbe42ac\nModel\t\t: Raspberry Pi 5 Model B Rev 1.1\n"
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/fixtures.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/fixtures.json
new file mode 100644
index 0000000..dbd23e2
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/fixtures.json
@@ -0,0 +1,128 @@
+[
+ {
+ "case": "one_slow",
+ "seed": 20260923,
+ "records": 1024,
+ "input_bytes": 42083156,
+ "input_sha256": "ebd22d4a12c1369ce27459e454df0a93545ca816fe13a82401160130772a3bfd",
+ "keys": [
+ "tag"
+ ],
+ "output_bytes_by_branch": [
+ 57344
+ ],
+ "output_sha256_by_branch": [
+ "1acead91fea700e5a94dc4285a37251f71876a0b505d2638cae3b9abf99915dd"
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "seed": 20260923,
+ "records": 1024,
+ "input_bytes": 42083156,
+ "input_sha256": "ebd22d4a12c1369ce27459e454df0a93545ca816fe13a82401160130772a3bfd",
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "output_bytes_by_branch": [
+ 33554432,
+ 57344,
+ 57344
+ ],
+ "output_sha256_by_branch": [
+ "a48ec20b430e737841289f18d08572d3630f92bac4778c7b0aa5d23acf5361bd",
+ "1acead91fea700e5a94dc4285a37251f71876a0b505d2638cae3b9abf99915dd",
+ "1acead91fea700e5a94dc4285a37251f71876a0b505d2638cae3b9abf99915dd"
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "seed": 20260923,
+ "records": 1024,
+ "input_bytes": 42083156,
+ "input_sha256": "ebd22d4a12c1369ce27459e454df0a93545ca816fe13a82401160130772a3bfd",
+ "keys": [
+ "body",
+ "body",
+ "body"
+ ],
+ "output_bytes_by_branch": [
+ 33554432,
+ 33554432,
+ 33554432
+ ],
+ "output_sha256_by_branch": [
+ "a48ec20b430e737841289f18d08572d3630f92bac4778c7b0aa5d23acf5361bd",
+ "a48ec20b430e737841289f18d08572d3630f92bac4778c7b0aa5d23acf5361bd",
+ "a48ec20b430e737841289f18d08572d3630f92bac4778c7b0aa5d23acf5361bd"
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "seed": 20260923,
+ "records": 1024,
+ "input_bytes": 42083156,
+ "input_sha256": "ebd22d4a12c1369ce27459e454df0a93545ca816fe13a82401160130772a3bfd",
+ "keys": [
+ "tag",
+ "tag",
+ "body"
+ ],
+ "output_bytes_by_branch": [
+ 57344,
+ 57344,
+ 33554432
+ ],
+ "output_sha256_by_branch": [
+ "1acead91fea700e5a94dc4285a37251f71876a0b505d2638cae3b9abf99915dd",
+ "1acead91fea700e5a94dc4285a37251f71876a0b505d2638cae3b9abf99915dd",
+ "a48ec20b430e737841289f18d08572d3630f92bac4778c7b0aa5d23acf5361bd"
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "seed": 20260923,
+ "records": 1024,
+ "input_bytes": 49877076,
+ "input_sha256": "3bba97318415a0c32a6eb61b04b7d73214ffcca90ae00469b45c2db6b28f600c",
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "output_bytes_by_branch": [
+ 26757376,
+ 57344,
+ 57344
+ ],
+ "output_sha256_by_branch": [
+ "89a5a0467e4473dd4afb7307366793ba4840463a6e9d44cd1f13090f2775bac9",
+ "f9bdd5932d1e9201f9dfeaf5e85d14572740d5a13dd31491654f75dd4999b5cf",
+ "f9bdd5932d1e9201f9dfeaf5e85d14572740d5a13dd31491654f75dd4999b5cf"
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "seed": 20260923,
+ "records": 512,
+ "input_bytes": 5259666,
+ "input_sha256": "b3ddc9f18b946c466f3b5819538de80e062f734fcba70d2ed578445b0bd5392f",
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "output_bytes_by_branch": [
+ 262144,
+ 28672,
+ 28672
+ ],
+ "output_sha256_by_branch": [
+ "9aa5e0f4c17a62255942c9d23be621e437630e5fa34ef908d7c88033e132d700",
+ "a65807b99ca84b43058312cfdd6892e252bb47585f37f257f7dae2dcd7ee4be2",
+ "a65807b99ca84b43058312cfdd6892e252bb47585f37f257f7dae2dcd7ee4be2"
+ ]
+ }
+]
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/plan.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/plan.json
new file mode 100644
index 0000000..3ee7b4a
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/plan.json
@@ -0,0 +1,177 @@
+{
+ "version": 1,
+ "written_before_measurement": true,
+ "seed": 20260923,
+ "repeats": 5,
+ "policies": [
+ {
+ "name": "borrow",
+ "policy": "borrow"
+ },
+ {
+ "name": "copy",
+ "policy": "copy"
+ },
+ {
+ "name": "shared_copy",
+ "policy": "shared_copy"
+ },
+ {
+ "name": "threshold2",
+ "policy": "threshold",
+ "ratio": 2
+ },
+ {
+ "name": "threshold8",
+ "policy": "threshold",
+ "ratio": 8
+ },
+ {
+ "name": "compact",
+ "policy": "compact",
+ "ratio": 2
+ },
+ {
+ "name": "copy_no_pool",
+ "policy": "copy",
+ "pool": 0
+ }
+ ],
+ "cases": [
+ {
+ "name": "one_slow",
+ "shape": "large",
+ "records": 1024,
+ "keys": [
+ "tag"
+ ],
+ "hold_us": [
+ 8000
+ ],
+ "service_us": [
+ 0
+ ],
+ "budget": 8388608,
+ "slots": 64
+ },
+ {
+ "name": "three_distinct_speeds",
+ "shape": "large",
+ "records": 1024,
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "hold_us": [
+ 0,
+ 5000,
+ 8000
+ ],
+ "service_us": [
+ 0,
+ 0,
+ 0
+ ],
+ "budget": 8388608,
+ "slots": 64
+ },
+ {
+ "name": "same_large_field",
+ "shape": "large",
+ "records": 1024,
+ "keys": [
+ "body",
+ "body",
+ "body"
+ ],
+ "hold_us": [
+ 0,
+ 5000,
+ 8000
+ ],
+ "service_us": [
+ 0,
+ 0,
+ 0
+ ],
+ "budget": 8388608,
+ "slots": 64
+ },
+ {
+ "name": "slow_large_field",
+ "shape": "large",
+ "records": 1024,
+ "keys": [
+ "tag",
+ "tag",
+ "body"
+ ],
+ "hold_us": [
+ 0,
+ 5000,
+ 8000
+ ],
+ "service_us": [
+ 0,
+ 0,
+ 0
+ ],
+ "budget": 8388608,
+ "slots": 64
+ },
+ {
+ "name": "mixed_tight",
+ "shape": "mixed",
+ "records": 1024,
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "hold_us": [
+ 0,
+ 5000,
+ 8000
+ ],
+ "service_us": [
+ 0,
+ 0,
+ 0
+ ],
+ "budget": 2097152,
+ "slots": 64
+ },
+ {
+ "name": "metadata_heavy",
+ "shape": "metadata",
+ "records": 512,
+ "keys": [
+ "body",
+ "tag",
+ "tag"
+ ],
+ "hold_us": [
+ 0,
+ 5000,
+ 8000
+ ],
+ "service_us": [
+ 0,
+ 0,
+ 0
+ ],
+ "budget": 2097152,
+ "slots": 64
+ }
+ ],
+ "expectations": [
+ "A slow small-field consumer can retain the input after a fast large-field consumer finishes.",
+ "Sharing identical compact copies can remove duplicate per-consumer copies without a new runtime.",
+ "Late compaction may save copied bytes or fail to beat early size-based copying; all remaining owners matter.",
+ "Parser temporary memory and reader growth must be charged, even when retained selections are small.",
+ "No novel-policy advantage or production service SLO is presumed."
+ ],
+ "comparison_rule": "Report all fixed presets; exploratory measurements, no trained/held-out policy or significance claim.",
+ "limits": "Real yyjson parser and actual bytes, but synthetic NDJSON corpus and sink delays, three synchronous consumers in one event loop, no open-loop arrivals, thread races, durable output, or independent parser comparison."
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.csv b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.csv
new file mode 100644
index 0000000..d2b9a02
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.csv
@@ -0,0 +1,211 @@
+case,variant,repeat,status,policy,parser_version,budget_bytes,fixed_bytes,peak_reserved_bytes,source_peak_bytes,output_peak_bytes,parser_peak_bytes,rss_peak_bytes,elapsed_ns,cpu_ns,parse_call_ns,accepted,emitted,input_bytes,selection_copy_bytes,reader_copy_bytes,parser_realloc_copy_bytes,source_byte_seconds,output_byte_seconds,parser_byte_seconds,source_allocations,output_allocations,parser_allocations,reuses,budget_waits,slot_waits,compacted,compact_skipped,dedup_hits,sleep_ns,live_at_stop_bytes,unreleased_buffer_bytes,queues
+one_slow,threshold2,0,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1835008,131703634,34750648,21989760,1024,1024,42083156,57344,75711296,0,1842.615404,919.75921,2883.244752,9,64,1,6056,0,16,0,0,0,97097912,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8051720.034, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,compact,0,ok,compact,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,131996119,38004572,22434299,1024,1024,42083156,0,75711296,0,540791.270719,0.0,2928.256675,72,0,1,5033,0,26,0,0,0,94192606,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8057605.331, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,borrow,0,ok,borrow,0.12.0,8388608,33536,4427696,4230192,0,131120,5521408,132124751,37612015,22444229,1024,1024,42083156,0,75711296,0,540845.471315,0.0,2930.090388,72,0,1,5033,0,53,0,0,0,94791711,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8058299.849, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold8,0,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131620844,34446035,21905479,1024,1024,42083156,57344,75711296,0,1832.609103,920.078119,2872.388672,9,64,1,6056,0,16,0,0,0,97293567,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054286.008, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy_no_pool,0,ok,copy,0.12.0,8388608,33536,237296,98400,7168,131120,1835008,132233158,41767998,24756316,1024,1024,42083156,57344,75711296,0,2069.543688,920.140424,2901.308237,4082,1024,1024,0,0,19,0,0,0,90619067,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8059175.662, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy,0,ok,copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131600270,34455850,21964978,1024,1024,42083156,57344,75711296,0,1832.537919,920.025416,2880.380829,9,64,1,6056,0,16,0,0,0,97270417,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8053796.131, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,shared_copy,0,ok,shared_copy,0.12.0,8388608,33536,303072,98400,7168,131120,1802240,131715584,34456703,21940218,1024,1024,42083156,57344,75711296,0,1833.007769,920.07894,2877.016945,9,64,1,6056,0,16,0,0,0,97393619,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054276.953, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,compact,1,ok,compact,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,132171843,38070312,22523797,1024,1024,42083156,0,75711296,0,540815.06589,0.0,2937.269732,72,0,1,5033,0,40,0,0,0,94338529,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8057936.641, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy_no_pool,1,ok,copy,0.12.0,8388608,33536,237296,98400,7168,131120,1835008,132199048,42202499,24805054,1024,1024,42083156,57344,75711296,0,2084.967873,920.132302,2905.942804,4082,1024,1024,0,0,29,0,0,0,90146770,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8059478.906, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,shared_copy,1,ok,shared_copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131708165,34804961,22044118,1024,1024,42083156,57344,75711296,0,1844.634105,919.759432,2890.857973,9,64,1,6056,0,16,0,0,0,97053198,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8051751.524, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold8,1,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131798127,34803856,22044512,1024,1024,42083156,57344,75711296,0,1846.36305,919.612987,2891.382584,9,64,1,6056,0,16,0,0,0,97156768,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050483.774, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,borrow,1,ok,borrow,0.12.0,8388608,33536,4427696,4230192,0,131120,5521408,131976979,38591495,22573964,1024,1024,42083156,0,75711296,0,540860.949553,0.0,2940.513903,72,0,1,5033,0,28,0,0,0,93626665,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8058679.423, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy,1,ok,copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131752053,34888537,21974890,1024,1024,42083156,57344,75711296,0,1845.194241,919.599974,2880.87266,9,64,1,6056,0,17,0,0,0,97030621,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050419.036, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold2,1,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131720609,34747849,21999728,1024,1024,42083156,57344,75711296,0,1843.805295,919.628727,2884.923744,9,64,1,6056,0,16,0,0,0,97113750,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050578.244, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy,2,ok,copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131735071,34877739,22030534,1024,1024,42083156,57344,75711296,0,1847.409016,919.636562,2888.89668,9,64,1,6056,0,16,0,0,0,96987832,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050770.82, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,compact,2,ok,compact,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,132186905,38709650,22486562,1024,1024,42083156,0,75711296,0,540826.901328,0.0,2931.839266,72,0,1,5033,0,36,0,0,0,93736446,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8058254.455, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,shared_copy,2,ok,shared_copy,0.12.0,8388608,33536,303072,98400,7168,131120,1835008,134003964,36820353,22141327,1024,1024,42083156,57344,75711296,0,1907.646695,924.396419,2903.071145,9,116,1,6004,0,25,0,0,0,97345374,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8093864.112, ""latency_p99_upper_ns"": 9437184}]"
+one_slow,threshold2,2,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,132093280,37140317,22338927,1024,1024,42083156,57344,75711296,0,1928.638533,919.864631,2930.310014,9,68,1,6052,0,20,0,0,0,95013211,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054865.09, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,borrow,2,ok,borrow,0.12.0,8388608,33536,4427696,4230192,0,131120,5554176,132469040,41862764,22964342,1024,1024,42083156,0,75711296,0,541099.43903,0.0,2986.938382,73,0,1,5032,0,49,0,0,0,90878204,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8063020.332, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy_no_pool,2,ok,copy,0.12.0,8388608,33536,237296,98400,7168,131120,1802240,137450461,46306762,25720817,1024,1024,42083156,57344,75711296,0,2217.245474,934.97033,2945.941354,4082,1024,1024,0,0,23,0,0,0,91429169,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8191749.104, ""latency_p99_upper_ns"": 11534336}]"
+one_slow,threshold8,2,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131976855,36997295,22056693,1024,1024,42083156,57344,75711296,0,1904.528214,920.059714,2891.295258,9,65,1,6055,0,21,0,0,0,95230128,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056258.001, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold2,3,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,132144262,36810738,22394390,1024,1024,42083156,57344,75711296,0,1914.610493,920.080986,2937.462741,9,71,1,6049,0,39,0,0,0,95437850,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056316.891, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold8,3,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131627799,34748983,22050963,1024,1024,42083156,57344,75711296,0,1845.118437,920.020651,2891.313221,9,64,1,6056,0,19,0,0,0,96996391,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054019.278, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,compact,3,ok,compact,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,132093080,38378509,22460168,1024,1024,42083156,0,75711296,0,540907.798619,0.0,2928.186919,72,0,1,5033,0,43,0,0,0,93965206,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8059384.654, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy_no_pool,3,ok,copy,0.12.0,8388608,33536,237296,98400,7168,131120,1802240,132246841,41768202,24673720,1024,1024,42083156,57344,75711296,0,2066.312998,920.19798,2896.434244,4082,1024,1024,0,0,16,0,0,0,90608121,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8059680.607, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy,3,ok,copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131689453,35243759,22012604,1024,1024,42083156,57344,75711296,0,1857.757504,919.947028,2887.51415,9,68,1,6052,0,27,0,0,0,96622803,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8053765.222, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,shared_copy,3,ok,shared_copy,0.12.0,8388608,33536,303072,98400,7168,131120,1802240,132103712,35248408,22004780,1024,1024,42083156,57344,75711296,0,1858.44117,919.973445,2885.070598,9,73,1,6047,0,22,0,0,0,97018510,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054006.321, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,borrow,3,ok,borrow,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,132436008,40869521,22656213,1024,1024,42083156,0,75711296,0,540941.338269,0.0,2953.318689,75,0,1,5030,0,52,0,0,0,91954404,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8060462.982, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,compact,4,ok,compact,0.12.0,8388608,33536,4427696,4230192,0,131120,5554176,132110379,38257181,22557256,1024,1024,42083156,0,75711296,0,540811.125254,0.0,2944.323595,72,0,1,5033,0,56,0,0,0,94112952,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8057929.717, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,threshold8,4,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1802240,131804916,34977352,22094634,1024,1024,42083156,57344,75711296,0,1853.831647,920.149467,2897.713188,9,67,1,6053,0,31,0,0,0,96937037,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8055361.395, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy_no_pool,4,ok,copy,0.12.0,8388608,33536,237296,98400,7168,131120,1818624,135161451,44330024,25503982,1024,1024,42083156,57344,75711296,0,2157.809223,924.543547,2946.975235,4082,1024,1024,0,0,35,0,0,0,91118882,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8099348.558, ""latency_p99_upper_ns"": 10485760}]"
+one_slow,threshold2,4,ok,threshold,0.12.0,8388608,33536,303072,98400,7168,131120,1802240,132588310,37673671,22518430,1024,1024,42083156,57344,75711296,0,1949.11739,920.155569,2954.042078,9,78,1,6042,0,36,0,0,0,94895218,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8057756.78, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,copy,4,ok,copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,131620718,34580946,21993246,1024,1024,42083156,57344,75711296,0,1837.245494,919.925321,2884.001314,9,64,1,6056,0,16,0,0,0,97154068,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8053071.22, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,borrow,4,ok,borrow,0.12.0,8388608,33536,4427696,4230192,0,131120,5537792,132000791,37927424,22507290,1024,1024,42083156,0,75711296,0,540831.163899,0.0,2938.768696,72,0,1,5033,0,30,0,0,0,94241105,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8058140.749, ""latency_p99_upper_ns"": 8388608}]"
+one_slow,shared_copy,4,ok,shared_copy,0.12.0,8388608,33536,303072,98400,7168,131120,1818624,132283829,37157688,22116989,1024,1024,42083156,57344,75711296,0,1917.711679,920.053817,2900.603467,9,67,1,6053,0,38,0,0,0,95415784,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056291.708, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,borrow,0,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5373952,132804710,49883960,22784485,1024,3072,42083156,0,75711296,0,540593.356702,0.0,2990.235132,72,0,1,5033,0,578,0,0,0,84130488,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45505.588, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070252.164, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8055489.045, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,compact,0,ok,compact,0.12.0,8388608,41728,4436784,4230192,6944,131120,5537792,132699783,50261222,22546544,1024,3072,42083156,57344,75711296,0,340105.36302,342.277671,2958.801865,897,913,1,4319,0,550,1024,0,0,83652241,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45463.711, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069982.729, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054576.42, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,shared_copy,0,ok,shared_copy,0.12.0,8388608,41728,311264,98400,39984,131120,1835008,132438636,46508730,22104890,1024,3072,42083156,33611776,75711296,0,1994.687521,1188.73405,2903.952009,9,64,1,7080,0,538,0,0,1024,87037859,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42492.519, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069205.345, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052022.729, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy,0,ok,copy,0.12.0,8388608,41728,318432,98400,47152,131120,1851392,132301692,46274024,22012014,1024,3072,42083156,33669120,75711296,0,1991.776071,1766.57547,2891.89841,9,1025,1,7143,0,563,0,0,0,87083196,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42221.575, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068352.743, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8049671.308, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy_no_pool,0,ok,copy,0.12.0,8388608,41728,252544,98400,47152,131120,1933312,132221655,46432790,22094470,1024,3072,42083156,33669120,75711296,0,2002.66499,1764.18462,2896.537304,4082,3072,1024,0,0,534,0,0,0,86822233,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42461.52, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068300.921, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054065.407, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold2,0,ok,threshold,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132423215,46202689,22137673,1024,3072,42083156,33611776,75711296,0,1992.776523,1183.803646,2909.259091,9,64,1,7080,0,559,0,0,1024,87298460,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42209.067, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068504.791, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052025.9, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold8,0,ok,threshold,0.12.0,8388608,41728,311264,98400,7168,131120,1851392,132072752,44818714,22007505,1024,3072,42083156,57344,75711296,0,2372.402719,919.579066,2891.111165,9,64,1,6056,0,531,0,0,1024,88271004,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41081.91, ""latency_p99_upper_ns"": 49152}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067409.945, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052229.961, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy,1,ok,copy,0.12.0,8388608,41728,318432,98400,47152,131120,1851392,132122049,45960158,22062914,1024,3072,42083156,33669120,75711296,0,1985.913742,1766.681864,2899.647733,9,1025,1,7143,0,530,0,0,0,87159643,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42080.341, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068084.019, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8053834.564, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy_no_pool,1,ok,copy,0.12.0,8388608,41728,252544,98400,47152,131120,1884160,132225178,46345346,22106440,1024,3072,42083156,33669120,75711296,0,1998.568774,1764.360213,2898.609,4082,3072,1024,0,0,531,0,0,0,86929226,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42412.925, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068204.178, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052346.592, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold2,1,ok,threshold,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132119197,45785542,22119160,1024,3072,42083156,33611776,75711296,0,1985.975023,1182.61037,2906.107753,9,64,1,7080,0,535,0,0,1024,87289352,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42063.476, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068193.573, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8051854.179, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,compact,1,ok,compact,0.12.0,8388608,41728,4436784,4230192,6944,131120,5603328,132689456,50225388,22679397,1024,3072,42083156,57344,75711296,0,340115.562513,342.313483,2976.797692,896,908,1,4325,0,548,1024,0,0,83654110,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45534.298, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070135.917, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8055038.37, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold8,1,ok,threshold,0.12.0,8388608,41728,311264,98400,7168,131120,1851392,132687220,45610919,22143479,1024,3072,42083156,57344,75711296,0,2398.303122,919.310014,2908.551305,9,73,1,6047,0,557,0,0,1024,88180228,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41592.506, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067924.312, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050249.576, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,shared_copy,1,ok,shared_copy,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,133179387,47009567,22053622,1024,3072,42083156,33611776,75711296,0,2001.098596,1195.094634,2898.481421,9,64,1,7080,0,619,0,0,1024,87400987,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42811.697, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068344.258, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054983.926, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,borrow,1,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5373952,132590517,49691116,22667622,1024,3072,42083156,0,75711296,0,540625.036225,0.0,2974.002082,72,0,1,5033,0,555,0,0,0,84069041,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45356.652, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069262.154, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8055874.806, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,borrow,2,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5373952,132595906,48936945,22622066,1024,3072,42083156,0,75711296,0,540538.226737,0.0,2969.006017,72,0,1,5033,0,550,0,0,0,84820014,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 44590.665, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069713.765, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054486.477, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold2,2,ok,threshold,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132243573,45674856,22029775,1024,3072,42083156,33611776,75711296,0,1978.146096,1181.588579,2894.51268,9,64,1,7080,0,547,0,0,1024,87607899,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41881.888, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067912.655, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8049931.179, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,compact,2,ok,compact,0.12.0,8388608,41728,4436784,4230192,6944,131120,5603328,132732463,49739534,22671992,1024,3072,42083156,57344,75711296,0,340105.112239,342.468555,2974.922545,893,887,1,4349,0,562,1024,0,0,84142850,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 44979.318, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069891.561, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056164.197, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold8,2,ok,threshold,0.12.0,8388608,41728,311264,98400,7168,131120,1851392,132272059,45320979,22141356,1024,3072,42083156,57344,75711296,0,2389.486333,919.390876,2908.882515,9,64,1,6056,0,563,0,0,1024,88007671,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41406.16, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068143.112, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050851.553, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy,2,ok,copy,0.12.0,8388608,41728,318432,98400,47152,131120,1867776,132351078,46122525,22082400,1024,3072,42083156,33669120,75711296,0,1991.903399,1762.771138,2900.645032,9,1026,1,7142,0,558,0,0,0,87297075,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42091.413, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068444.485, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8048834.24, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,shared_copy,2,ok,shared_copy,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132284819,45823432,22066434,1024,3072,42083156,33611776,75711296,0,1983.569581,1182.323172,2898.432644,9,64,1,7080,0,542,0,0,1024,87424368,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42064.699, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068229.227, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050900.843, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy_no_pool,2,ok,copy,0.12.0,8388608,41728,252544,98400,47152,131120,1900544,132459707,47692750,22170762,1024,3072,42083156,33669120,75711296,0,2023.677274,1777.322506,2907.132194,4082,3072,1024,0,0,540,0,0,0,85990890,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 43327.485, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070694.294, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8055086.674, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,shared_copy,3,ok,shared_copy,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132140503,45825210,22125197,1024,3072,42083156,33611776,75711296,0,1985.69773,1183.215978,2906.687041,9,64,1,7080,0,533,0,0,1024,87310088,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42062.03, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068036.782, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050191.375, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy_no_pool,3,ok,copy,0.12.0,8388608,41728,252544,98400,47152,131120,1916928,132297747,46669804,22175323,1024,3072,42083156,33669120,75711296,0,2009.648765,1766.146335,2907.094824,4082,3072,1024,0,0,542,0,0,0,86663675,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42678.905, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068637.263, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054142.04, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy,3,ok,copy,0.12.0,8388608,41728,318432,98400,47152,131120,1851392,132282510,46415608,22079359,1024,3072,42083156,33669120,75711296,0,1996.444688,1765.761752,2901.17633,9,1025,1,7143,0,554,0,0,0,86986908,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42277.028, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070038.574, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050279.443, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,borrow,3,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5373952,132489898,48808681,22654163,1024,3072,42083156,0,75711296,0,540484.370521,0.0,2972.753951,72,0,1,5033,0,556,0,0,0,84863248,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 44578.165, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069410.422, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8053620.063, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold2,3,ok,threshold,0.12.0,8388608,41728,311264,98400,39984,131120,1835008,132283398,45911917,22085581,1024,3072,42083156,33611776,75711296,0,1984.871517,1183.416247,2903.347153,9,64,1,7080,0,561,0,0,1024,87433143,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42043.254, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068356.958, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8050581.195, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold8,3,ok,threshold,0.12.0,8388608,41728,311264,98400,7168,131120,1851392,132082805,44815017,22070822,1024,3072,42083156,57344,75711296,0,2374.331913,919.214871,2899.672121,9,64,1,6056,0,534,0,0,1024,88275454,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41070.548, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067369.015, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8049008.122, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,compact,3,ok,compact,0.12.0,8388608,41728,4436784,4230192,7056,131120,5488640,132597323,49981497,22749218,1024,3072,42083156,57344,75711296,0,340108.105991,342.554096,2986.081381,912,907,1,4310,0,563,1024,0,0,83819563,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45265.223, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069991.558, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056976.805, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy_no_pool,4,ok,copy,0.12.0,8388608,41728,252544,98400,47152,131120,1900544,132985160,49981054,23442854,1024,3072,42083156,33669120,75711296,0,2129.142526,1795.211172,3074.346252,4082,3072,1024,0,0,542,0,0,0,84089494,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45510.754, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5098662.604, ""latency_p99_upper_ns"": 6291456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8056999.864, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,borrow,4,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5373952,133433884,51462618,23747967,1024,3072,42083156,0,75711296,0,540814.68462,0.0,3118.422109,72,0,1,5033,0,596,0,0,0,83315856,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 46811.327, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070925.9, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8058845.673, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold2,4,ok,threshold,0.12.0,8388608,41728,311264,98400,39984,131120,1867776,132186422,45811373,22083462,1024,3072,42083156,33611776,75711296,0,1983.12097,1182.647891,2900.448352,9,64,1,7080,0,532,0,0,1024,87421696,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42006.171, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068025.061, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8049545.414, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,shared_copy,4,ok,shared_copy,0.12.0,8388608,41728,311264,98400,39984,131120,1851392,132188663,45991210,22145612,1024,3072,42083156,33611776,75711296,0,1991.371251,1184.961172,2909.800223,9,64,1,7080,0,543,0,0,1024,87186189,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42139.616, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068490.238, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052428.242, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,compact,4,ok,compact,0.12.0,8388608,41728,4436784,4230192,7056,131120,5537792,132746292,50870250,22660664,1024,3072,42083156,57344,75711296,0,340246.674827,342.038296,2973.982939,893,895,1,4341,0,545,1024,0,0,83141858,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 45809.599, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5072116.599, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8054634.315, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,threshold8,4,ok,threshold,0.12.0,8388608,41728,311264,98400,7168,131120,1851392,132177385,44977578,22128368,1024,3072,42083156,57344,75711296,0,2381.095196,919.555429,2907.397974,9,64,1,6056,0,539,0,0,1024,88187889,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 41268.295, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067698.961, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8052209.973, ""latency_p99_upper_ns"": 8388608}]"
+three_distinct_speeds,copy,4,ok,copy,0.12.0,8388608,41728,318432,98400,47152,131120,1867776,132225648,46118905,22053057,1024,3072,42083156,33669120,75711296,0,1988.501642,1767.427593,2896.491937,9,1025,1,7143,0,536,0,0,0,87128865,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 42165.024, ""latency_p99_upper_ns"": 53248}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068266.918, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8051060.116, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy_no_pool,0,ok,copy,0.12.0,8388608,41728,4373248,98400,4233264,131120,6078464,216945564,116157398,25703347,1024,3072,42083156,100663296,75711296,0,3917.681175,512250.563648,3150.964519,4082,3072,1024,0,0,383,0,0,0,48939452,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 117402.264, ""latency_p99_upper_ns"": 524288}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 6063368.282, ""latency_p99_upper_ns"": 31457280}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 9260486.827, ""latency_p99_upper_ns"": 33554432}]"
+same_large_field,shared_copy,0,ok,shared_copy,0.12.0,8388608,41728,2371504,98400,2100224,131120,3178496,133534289,66640259,22303696,1024,3072,42083156,33554432,75711296,0,2044.238204,269834.895225,2930.529378,82,0,1,6047,0,500,0,0,2048,67897726,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51484.234, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078396.125, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8065897.697, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,borrow,0,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133553215,68694192,22344284,1024,3072,42083156,0,75711296,0,541236.958782,0.0,2932.875901,76,0,1,5029,0,479,0,0,0,65966946,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52115.836, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078241.217, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8065472.756, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy,0,ok,copy,0.12.0,8388608,41728,4504544,98400,4233264,131120,5292032,134319516,74842901,22151327,1024,3072,42083156,100663296,75711296,0,2277.11069,440218.115158,2909.330552,9,841,1,7327,0,490,0,0,0,60554269,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 57181.88, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5083619.048, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8071315.085, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold2,0,ok,threshold,0.12.0,8388608,41728,2371504,98400,2100224,131120,3194880,133454646,66234578,22159339,1024,3072,42083156,33554432,75711296,0,2031.818258,269861.554419,2910.266617,78,0,1,6051,0,487,0,0,2048,68332882,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51484.504, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5077341.499, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066441.419, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,compact,0,ok,compact,0.12.0,8388608,41728,4730672,4230192,2001776,131120,6340608,134096312,74886880,22733900,1024,3072,42083156,33554432,75711296,0,341111.908821,100293.13752,2983.138393,921,779,1,4429,0,471,1024,0,0,60362834,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 54080.027, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5083405.479, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068401.165, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold8,0,ok,threshold,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133447386,68765370,22353361,1024,3072,42083156,0,75711296,0,541359.828153,0.0,2934.692831,77,0,1,5028,0,487,0,0,0,65809490,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52372.427, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078845.858, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067374.837, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,compact,1,ok,compact,0.12.0,8388608,41728,4730672,4230192,2034592,131120,6340608,134204038,74836392,22853483,1024,3072,42083156,33554432,75711296,0,341117.919471,100364.674661,2998.098529,881,767,1,4481,0,478,1024,0,0,60375968,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 54356.541, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5083649.875, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070735.206, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,shared_copy,1,ok,shared_copy,0.12.0,8388608,41728,2371504,98400,2100224,131120,3244032,133593447,66172548,22181499,1024,3072,42083156,33554432,75711296,0,2031.917671,269851.910584,2913.380586,80,0,1,6049,0,471,0,0,2048,68489180,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51688.946, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5077231.39, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066199.086, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy,1,ok,copy,0.12.0,8388608,41728,4504544,98400,4233264,131120,5292032,134436483,75053693,22215239,1024,3072,42083156,100663296,75711296,0,2284.410516,440251.541897,2917.091676,9,832,1,7336,0,483,0,0,0,60480780,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 57382.812, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5083530.123, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8072471.683, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold2,1,ok,threshold,0.12.0,8388608,41728,2371504,98400,2100224,131120,3194880,134034428,69077852,22386881,1024,3072,42083156,33554432,75711296,0,2071.219143,269907.925264,2941.415878,82,0,1,6047,0,521,0,0,2048,66160244,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52463.206, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5079970.677, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068543.087, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold8,1,ok,threshold,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133602318,69361342,22347294,1024,3072,42083156,0,75711296,0,541336.354919,0.0,2933.602437,76,0,1,5029,0,500,0,0,0,65433839,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52034.221, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5079700.568, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067086.654, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,borrow,1,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133878082,69431646,22393309,1024,3072,42083156,0,75711296,0,541341.633608,0.0,2938.771712,78,0,1,5027,0,504,0,0,0,65629618,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52136.236, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078986.712, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067041.718, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy_no_pool,1,ok,copy,0.12.0,8388608,41728,4373248,98400,4233264,131120,5816320,134331933,75355273,22600489,1024,3072,42083156,100663296,75711296,0,2317.391148,440282.284319,2923.56271,4082,3072,1024,0,0,497,0,0,0,60100461,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 58242.85, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5084649.973, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8073924.058, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,compact,2,ok,compact,0.12.0,8388608,41728,4730672,4230192,2001776,131120,6340608,134074359,74679639,22736073,1024,3072,42083156,33554432,75711296,0,341236.488763,100267.211633,2982.994817,917,794,1,4418,0,471,1024,0,0,60515136,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 53738.105, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5085195.058, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069412.397, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy,2,ok,copy,0.12.0,8388608,41728,4504544,98400,4233264,131120,5275648,136064340,79416596,22572078,1024,3072,42083156,100663296,75711296,0,2363.378088,440586.829499,2964.218039,9,623,1,7545,0,463,0,0,0,57551670,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 60112.085, ""latency_p99_upper_ns"": 114688}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5087074.439, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8080314.649, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold2,2,ok,threshold,0.12.0,8388608,41728,2371504,98400,2100224,131120,3244032,133655494,66354625,22289900,1024,3072,42083156,33554432,75711296,0,2049.709126,269797.797722,2927.700988,78,0,1,6051,0,500,0,0,2048,68212138,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51495.073, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078118.015, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8064823.351, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,shared_copy,2,ok,shared_copy,0.12.0,8388608,41728,2371504,98400,2100224,131120,3293184,133683827,66973903,22176603,1024,3072,42083156,33554432,75711296,0,2039.054037,269818.155226,2912.084727,78,0,1,6051,0,494,0,0,2048,67816366,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51459.966, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5079235.137, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8065334.704, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold8,2,ok,threshold,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133681327,68797289,22338685,1024,3072,42083156,0,75711296,0,541289.267391,0.0,2932.086428,77,0,1,5028,0,482,0,0,0,65978872,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52563.022, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078578.492, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066255.165, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,borrow,2,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133814643,68888479,22335355,1024,3072,42083156,0,75711296,0,541341.207084,0.0,2930.637289,79,0,1,5026,0,510,0,0,0,66149871,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51550.405, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5079607.126, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067127.786, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy_no_pool,2,ok,copy,0.12.0,8388608,41728,4373248,98400,4233264,131120,5816320,134471775,75393460,22629325,1024,3072,42083156,100663296,75711296,0,2321.181236,440258.792854,2921.16977,4082,3072,1024,0,0,508,0,0,0,60227676,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 57516.822, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5084982.783, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8073926.553, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold2,3,ok,threshold,0.12.0,8388608,41728,2371504,98400,2100224,131120,3194880,133441147,66434679,22119254,1024,3072,42083156,33554432,75711296,0,2030.079604,269825.85573,2905.779822,80,0,1,6049,0,482,0,0,2048,68150063,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51190.857, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5077733.031, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8065349.133, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy_no_pool,3,ok,copy,0.12.0,8388608,41728,4373248,98400,4233264,131120,5816320,134289332,76002725,22740343,1024,3072,42083156,100663296,75711296,0,2334.193158,440332.993703,2936.962125,4082,3072,1024,0,0,504,0,0,0,59412631,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 59077.132, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5084960.638, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8075279.097, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,shared_copy,3,ok,shared_copy,0.12.0,8388608,41728,2371504,98400,2100224,131120,3309568,133495777,66421587,22309367,1024,3072,42083156,33554432,75711296,0,2045.123956,269842.975673,2931.949276,76,0,1,6053,0,497,0,0,2048,68249668,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51216.396, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078028.333, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066089.677, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,borrow,3,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,134337593,71105404,22575073,1024,3072,42083156,0,75711296,0,541448.462493,0.0,2962.344728,83,0,1,5022,0,495,0,0,0,64431294,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 53339.614, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5080292.879, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068765.424, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy,3,ok,copy,0.12.0,8388608,41728,4504544,98400,4233264,131120,5292032,134254523,76196602,22285338,1024,3072,42083156,100663296,75711296,0,2295.795833,440394.753415,2927.722098,9,820,1,7348,0,485,0,0,0,59133245,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 58635.959, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5084371.237, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8075247.27, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,compact,3,ok,compact,0.12.0,8388608,41728,4730672,4230192,2034592,131120,6340608,134306041,75274107,22714288,1024,3072,42083156,33554432,75711296,0,341191.973388,100297.728905,2980.354846,917,749,1,4463,0,478,1024,0,0,60108647,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 54208.683, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5084673.227, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069796.873, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold8,3,ok,threshold,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133817208,69542587,22437830,1024,3072,42083156,0,75711296,0,541408.186663,0.0,2945.936502,80,0,1,5025,0,483,0,0,0,65488224,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52016.168, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5080750.668, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068031.861, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy_no_pool,4,ok,copy,0.12.0,8388608,41728,4373248,98400,4233264,131120,5799936,134597856,77396908,22833216,1024,3072,42083156,100663296,75711296,0,2355.524795,440416.150759,2941.859195,4082,3072,1024,0,0,512,0,0,0,58493375,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 59008.762, ""latency_p99_upper_ns"": 98304}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5086107.088, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8076875.839, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,copy,4,ok,copy,0.12.0,8388608,41728,4504544,98400,4233264,131120,5292032,139508137,88332555,22864596,1024,3072,42083156,100663296,75711296,0,2528.253394,442384.852596,3002.901193,9,688,1,7480,0,372,0,0,0,51495885,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 66698.854, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5129096.339, ""latency_p99_upper_ns"": 6815744}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8093643.623, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold8,4,ok,threshold,0.12.0,8388608,41728,4435888,4230192,0,131120,4833280,134457305,70251788,22431999,1024,3072,42083156,0,75711296,0,541395.863387,0.0,2942.397573,87,0,1,5018,0,495,0,0,0,65292089,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 53169.212, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5080238.856, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068047.314, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,threshold2,4,ok,threshold,0.12.0,8388608,41728,2371504,98400,2100224,131120,3211264,133756102,67373341,22155214,1024,3072,42083156,33554432,75711296,0,2045.927873,269868.863264,2910.706656,81,0,1,6048,0,506,0,0,2048,67548515,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 51135.428, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078670.025, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066898.388, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,shared_copy,4,ok,shared_copy,0.12.0,8388608,41728,2371504,98400,2100224,131120,3571712,135030934,71236281,22446961,1024,3072,42083156,33554432,75711296,0,2100.123381,269953.875704,2948.934561,94,0,1,6035,0,507,0,0,2048,65033726,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 53626.014, ""latency_p99_upper_ns"": 90112}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5087279.412, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070672.959, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,compact,4,ok,compact,0.12.0,8388608,41728,4730672,4230192,1936144,131120,6340608,135831514,84355786,23107923,1024,3072,42083156,33554432,75711296,0,341580.411374,100419.005421,3032.899482,853,676,1,4600,0,455,1024,0,0,52913091,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 60319.001, ""latency_p99_upper_ns"": 114688}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5091148.147, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8079928.47, ""latency_p99_upper_ns"": 8388608}]"
+same_large_field,borrow,4,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133667291,68534602,22264001,1024,3072,42083156,0,75711296,0,541292.227145,0.0,2921.518156,77,0,1,5028,0,481,0,0,0,66216721,0,0,"[{""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 1, ""latency_mean_ns"": 52072.538, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 5078370.622, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066280.939, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy,0,ok,copy,0.12.0,8388608,41728,2378784,98400,2107504,131120,3899392,133407209,54623208,22433685,1024,3072,42083156,33669120,75711296,0,2079.608844,270519.575773,2946.904954,118,838,1,7221,0,547,0,0,0,79664236,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 47700.066, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070062.768, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069584.641, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold2,0,ok,threshold,0.12.0,8388608,41728,2378672,98400,2107392,131120,3751936,133312135,53364925,22316231,1024,3072,42083156,33611776,75711296,0,2049.372724,270524.406644,2928.92106,137,841,1,6175,0,552,0,0,1024,80930688,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46742.189, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068879.809, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069119.599, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,shared_copy,0,ok,shared_copy,0.12.0,8388608,41728,2378672,98400,2107392,131120,3948544,154001095,65368726,23437273,1024,3072,42083156,33611776,75711296,0,2683.230182,276097.966097,3083.783614,228,746,1,6179,0,542,0,0,1024,75659422,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 64443.196, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5134851.331, ""latency_p99_upper_ns"": 7340032}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8252758.487, ""latency_p99_upper_ns"": 15728640}]"
+slow_large_field,copy_no_pool,0,ok,copy,0.12.0,8388608,41728,2312896,98400,2107504,131120,3194880,133648283,61986524,25370210,1024,3072,42083156,33669120,75711296,0,2299.022458,270612.233717,2983.123314,4082,3072,1024,0,0,653,0,0,0,72630111,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 53967.42, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080263.648, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8075763.615, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,compact,0,ok,compact,0.12.0,8388608,41728,4730672,4230192,2067408,131120,6340608,133472857,62602975,23134595,1024,3072,42083156,33554432,75711296,0,340709.17918,100724.838498,3036.377571,923,841,1,4365,0,526,1024,0,0,71679132,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 48473.289, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5073065.738, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070772.518, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold8,0,ok,threshold,0.12.0,8388608,41728,4443056,4230192,7168,131120,4751360,133297584,55094453,22718797,1024,3072,42083156,57344,75711296,0,541537.659914,577.166247,2982.289653,130,809,1,5190,0,541,0,0,1024,79050000,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 48100.386, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069482.618, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070037.129, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,borrow,0,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133477288,54372368,22466675,1024,3072,42083156,0,75711296,0,541562.393801,0.0,2949.789857,80,0,1,5025,0,554,0,0,0,80055686,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46918.51, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069158.581, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070277.888, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold2,1,ok,threshold,0.12.0,8388608,41728,2378672,98400,2107392,131120,3932160,133312509,53734268,22533891,1024,3072,42083156,33611776,75711296,0,2071.170012,270512.249274,2959.58098,159,828,1,6166,0,575,0,0,1024,80473327,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46789.037, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070040.373, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069081.323, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy_no_pool,1,ok,copy,0.12.0,8388608,41728,2312896,98400,2107504,131120,3194880,134281084,62190824,25213500,1024,3072,42083156,33669120,75711296,0,2300.277794,270647.838041,2975.251132,4082,3072,1024,0,0,663,0,0,0,73016473,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 54287.927, ""latency_p99_upper_ns"": 98304}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080276.456, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8077074.059, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy,1,ok,copy,0.12.0,8388608,41728,2378784,98400,2107504,131120,3948544,133395362,55263103,22335683,1024,3072,42083156,33669120,75711296,0,2070.323199,270570.958879,2935.679247,123,825,1,7229,0,563,0,0,0,79157676,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 47428.456, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070071.895, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070912.004, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,shared_copy,1,ok,shared_copy,0.12.0,8388608,41728,2378672,98400,2107392,131120,3522560,133405307,53873137,22349414,1024,3072,42083156,33611776,75711296,0,2061.271642,270527.998952,2936.171471,144,811,1,6198,0,551,0,0,1024,80515381,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46564.507, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069570.9, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069438.264, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,compact,1,ok,compact,0.12.0,8388608,41728,4730672,4230192,2100224,131120,6340608,133295478,60929076,22892803,1024,3072,42083156,33554432,75711296,0,340588.424197,100730.999866,3007.852808,919,842,1,4368,0,524,1024,0,0,73271182,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 48259.733, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5071843.127, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069717.131, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,borrow,1,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,5390336,133317978,54530428,22789187,1024,3072,42083156,0,75711296,0,541551.170985,0.0,2991.654899,72,0,1,5033,0,541,0,0,0,79523636,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 47420.19, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5069779.505, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070214.071, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold8,1,ok,threshold,0.12.0,8388608,41728,4443056,4230192,7168,131120,5357568,133341496,54857945,22618201,1024,3072,42083156,57344,75711296,0,541518.37496,577.265132,2971.205031,122,835,1,5172,0,562,0,0,1024,79396532,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 47550.497, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070242.543, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069675.14, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold8,2,ok,threshold,0.12.0,8388608,41728,4443056,4230192,7168,131120,5292032,134650847,58145169,22801055,1024,3072,42083156,57344,75711296,0,542663.104532,578.298773,2995.063232,127,804,1,5198,0,553,0,0,1024,77457652,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 49310.575, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080294.837, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8086977.866, ""latency_p99_upper_ns"": 9437184}]"
+slow_large_field,copy,2,ok,copy,0.12.0,8388608,41728,2378784,98400,2107504,131120,3964928,133179940,52486508,22146823,1024,3072,42083156,33669120,75711296,0,2028.917653,270508.558846,2910.035715,119,875,1,7183,0,532,0,0,0,81744820,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46179.91, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068139.702, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068218.996, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,borrow,2,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133254368,52756869,22242096,1024,3072,42083156,0,75711296,0,541465.495701,0.0,2919.456949,79,0,1,5026,0,537,0,0,0,81620293,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45804.026, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067325.337, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068611.8, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,compact,2,ok,compact,0.12.0,8388608,41728,4730672,4230192,2100224,131120,6340608,133273853,59503628,22579568,1024,3072,42083156,33554432,75711296,0,340521.103381,100725.988305,2964.439632,921,839,1,4369,0,529,1024,0,0,75001351,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46820.147, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5071087.53, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068767.35, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,shared_copy,2,ok,shared_copy,0.12.0,8388608,41728,2378672,98400,2107392,131120,3293184,133216315,51631438,22079426,1024,3072,42083156,33611776,75711296,0,2014.496107,270449.091989,2901.711431,152,827,1,6174,0,543,0,0,1024,82698735,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45041.785, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068002.393, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8066161.602, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy_no_pool,2,ok,copy,0.12.0,8388608,41728,2312896,98400,2107504,131120,3178496,133362779,58084129,24178012,1024,3072,42083156,33669120,75711296,0,2196.167723,270535.919777,2934.024512,4082,3072,1024,0,0,605,0,0,0,76526627,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 50758.917, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5074265.021, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8071772.438, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold2,2,ok,threshold,0.12.0,8388608,41728,2378672,98400,2107392,131120,3751936,133094723,52669444,22153975,1024,3072,42083156,33611776,75711296,0,2026.350691,270487.081841,2910.446252,162,813,1,6178,0,529,0,0,1024,81515465,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46192.459, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067955.414, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067608.796, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,compact,3,ok,compact,0.12.0,8388608,41728,4730672,4230192,2100224,131120,6340608,133282278,59568109,22558632,1024,3072,42083156,33554432,75711296,0,340502.324772,100714.490169,2961.00573,923,826,1,4380,0,521,1024,0,0,74934523,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46941.425, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5070856.899, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068200.595, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy_no_pool,3,ok,copy,0.12.0,8388608,41728,2312896,98400,2107504,131120,3194880,133540522,58472614,24345793,1024,3072,42083156,33669120,75711296,0,2208.417867,270579.890216,2933.62499,4082,3072,1024,0,0,602,0,0,0,76325826,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 51364.197, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5074603.185, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8073207.582, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,borrow,3,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133275839,52234245,22266351,1024,3072,42083156,0,75711296,0,541367.893955,0.0,2922.935825,79,0,1,5026,0,545,0,0,0,82113024,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45842.847, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5066801.978, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067096.868, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,shared_copy,3,ok,shared_copy,0.12.0,8388608,41728,2378672,98400,2107392,131120,3899392,133064931,52117164,22057182,1024,3072,42083156,33611776,75711296,0,2015.469116,270480.700872,2897.68644,130,842,1,6181,0,555,0,0,1024,82111301,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45400.789, ""latency_p99_upper_ns"": 57344}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068255.587, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067189.304, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold8,3,ok,threshold,0.12.0,8388608,41728,4443056,4230192,7168,131120,5292032,133337450,53670610,22263776,1024,3072,42083156,57344,75711296,0,541459.255198,577.165832,2922.14622,137,796,1,5196,0,551,0,0,1024,80837357,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46321.397, ""latency_p99_upper_ns"": 65536}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068514.702, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8068639.91, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold2,3,ok,threshold,0.12.0,8388608,41728,2378672,98400,2107392,131120,3522560,134333542,52726291,22219255,1024,3072,42083156,33611776,75711296,0,2039.714059,270798.061653,2918.877137,140,894,1,6119,0,516,0,0,1024,82638596,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46056.021, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5218345.888, ""latency_p99_upper_ns"": 9437184}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8076530.434, ""latency_p99_upper_ns"": 9437184}]"
+slow_large_field,copy,3,ok,copy,0.12.0,8388608,41728,2378784,98400,2107504,131120,3948544,133174357,52057974,22117835,1024,3072,42083156,33669120,75711296,0,2021.284206,270501.113842,2905.858494,114,849,1,7214,0,548,0,0,0,82257586,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45428.889, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068142.38, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067808.96, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy_no_pool,4,ok,copy,0.12.0,8388608,41728,2312896,98400,2107504,131120,3178496,133410638,57999768,24134627,1024,3072,42083156,33669120,75711296,0,2191.645151,270510.58659,2926.663567,4082,3072,1024,0,0,603,0,0,0,76638749,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 51016.097, ""latency_p99_upper_ns"": 81920}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5074074.877, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8071032.382, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold2,4,ok,threshold,0.12.0,8388608,41728,2378672,98400,2107392,131120,3342336,133213102,52362717,22103023,1024,3072,42083156,33611776,75711296,0,2022.420003,270482.639278,2904.168619,127,855,1,6171,0,539,0,0,1024,81964913,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46044.098, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5068262.707, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067371.07, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,copy,4,ok,copy,0.12.0,8388608,41728,2378784,98400,2107504,131120,3751936,133177547,52033688,22154380,1024,3072,42083156,33669120,75711296,0,2025.354638,270478.813202,2910.934805,129,851,1,7197,0,527,0,0,0,82109654,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 45825.604, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067937.156, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067321.024, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,borrow,4,ok,borrow,0.12.0,8388608,41728,4435888,4230192,0,131120,4767744,133311566,53725285,22239925,1024,3072,42083156,0,75711296,0,541575.408384,0.0,2920.340305,80,0,1,5025,0,555,0,0,0,80727666,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46306.509, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067147.548, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8070390.562, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,threshold8,4,ok,threshold,0.12.0,8388608,41728,4443056,4230192,7168,131120,5439488,134101658,54158047,22315394,1024,3072,42083156,57344,75711296,0,541512.874989,578.716358,2931.279646,161,826,1,5142,0,533,0,0,1024,81103821,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46533.691, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082538.041, ""latency_p99_upper_ns"": 6291456}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8069591.938, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,shared_copy,4,ok,shared_copy,0.12.0,8388608,41728,2378672,98400,2107392,131120,3948544,133134639,52075173,22128273,1024,3072,42083156,33611776,75711296,0,2026.862393,270471.476005,2908.200691,122,816,1,6215,0,512,0,0,1024,82080012,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 46182.627, ""latency_p99_upper_ns"": 61440}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5067504.389, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067072.688, ""latency_p99_upper_ns"": 8388608}]"
+slow_large_field,compact,4,ok,compact,0.12.0,8388608,41728,4730672,4230192,2100224,131120,6406144,133118662,59607669,22648269,1024,3072,42083156,33554432,75711296,0,340524.867797,100684.088672,2973.798584,921,855,1,4353,0,532,1024,0,0,74562185,0,0,"[{""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 1, ""latency_mean_ns"": 47236.674, ""latency_p99_upper_ns"": 73728}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5071269.907, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 33554432, ""peak_count"": 64, ""latency_mean_ns"": 8067723.707, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy,0,ok,copy,0.12.0,2097152,41728,1104848,393312,79920,524336,1884160,134798098,52545277,26282225,1024,3072,49877076,26872064,114814580,0,6883.203763,1809.304759,10115.296993,367,948,374,6256,0,579,0,0,0,83482902,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47583.467, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081460.678, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8083520.998, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold8,0,ok,threshold,0.12.0,2097152,41728,1097792,393312,11312,524336,2031616,134514858,50924568,26180831,1024,3072,49877076,1059072,114814580,0,7475.627393,924.635553,10091.334952,237,96,257,5800,0,593,0,0,1024,84806597,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 46212.018, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080764.964, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8080296.584, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy_no_pool,0,ok,copy,0.12.0,2097152,41728,842368,393312,79920,524336,1949696,135580728,59055276,27303180,1024,3072,49877076,26872064,114814580,0,8268.860241,1866.643736,10141.702783,3849,3072,1024,0,0,540,0,0,0,77683199,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 53763.312, ""latency_p99_upper_ns"": 163840}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5090947.59, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8093934.847, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,shared_copy,0,ok,shared_copy,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134733970,52189389,26273407,1024,3072,49877076,26814720,114814580,0,6865.482399,1226.436074,10135.432887,365,246,368,5942,0,587,0,0,1024,83766349,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47383.279, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081532.837, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082383.547, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold2,0,ok,threshold,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134703694,51981424,26239241,1024,3072,49877076,26814720,114814580,0,6818.11346,1220.93584,10109.238408,368,240,366,5947,0,592,0,0,1024,83962412,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47186.16, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082027.365, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082717.212, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,compact,0,ok,compact,0.12.0,2097152,41728,2096880,2047296,3360,524336,3702784,330325402,56526552,257818693,1024,3072,49877076,57344,114814580,0,542057.64214,342.456081,10454.037412,1653,1018,587,2639,1256,0,1024,0,0,275134226,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 313916.181, ""latency_p99_upper_ns"": 4718592}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5359649.404, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 49, ""latency_mean_ns"": 8345801.06, ""latency_p99_upper_ns"": 12582912}]"
+mixed_tight,borrow,0,ok,borrow,0.12.0,2097152,41728,2097024,2047296,0,524336,3702784,517444947,58385263,414175159,1024,3072,49877076,0,114814580,0,866552.611778,0.0,10646.478365,1612,0,580,2681,1250,0,0,0,0,460552293,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 496739.613, ""latency_p99_upper_ns"": 7864320}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5531099.266, ""latency_p99_upper_ns"": 12582912}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 8547759.071, ""latency_p99_upper_ns"": 15728640}]"
+mixed_tight,copy_no_pool,1,ok,copy,0.12.0,2097152,41728,842368,393312,79920,524336,1916928,135818181,60130654,27699522,1024,3072,49877076,26872064,114814580,0,8398.686166,1885.555543,10206.603011,3849,3072,1024,0,0,537,0,0,0,76838088,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 54782.86, ""latency_p99_upper_ns"": 180224}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5093567.929, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8096201.349, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold8,1,ok,threshold,0.12.0,2097152,41728,1097792,393312,11312,524336,2064384,134627181,51051158,26242598,1024,3072,49877076,1059072,114814580,0,7499.787736,924.734083,10090.493068,237,100,258,5795,0,587,0,0,1024,84733901,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 46365.068, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080938.783, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8081319.231, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,shared_copy,1,ok,shared_copy,0.12.0,2097152,41728,1097792,393312,72752,524336,1900544,134660107,51849496,26235438,1024,3072,49877076,26814720,114814580,0,6785.330268,1222.453816,10103.005533,366,239,366,5950,0,579,0,0,1024,84013028,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47133.761, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081549.099, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082113.784, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,borrow,1,ok,borrow,0.12.0,2097152,41728,2097024,2047296,0,524336,3719168,516876187,58189132,413488109,1024,3072,49877076,0,114814580,0,866155.703795,0.0,10618.392921,1617,0,581,2675,1263,0,0,0,0,460124695,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 496219.126, ""latency_p99_upper_ns"": 7864320}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5528237.536, ""latency_p99_upper_ns"": 12582912}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 8541844.312, ""latency_p99_upper_ns"": 15728640}]"
+mixed_tight,threshold2,1,ok,threshold,0.12.0,2097152,41728,1097792,393312,72752,524336,1867776,134596389,51879163,26207832,1024,3072,49877076,26814720,114814580,0,6795.293198,1224.224319,10089.609534,369,233,365,5954,0,596,0,0,1024,83947198,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47146.396, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082305.345, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082431.98, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy,1,ok,copy,0.12.0,2097152,41728,1104848,393312,79920,524336,1884160,134667407,52286009,26255995,1024,3072,49877076,26872064,114814580,0,6830.10163,1802.54536,10104.51946,370,952,375,6248,0,590,0,0,0,83595691,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47383.187, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081689.522, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082200.92, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,compact,1,ok,compact,0.12.0,2097152,41728,2097104,2047296,3360,524336,3833856,330507221,57227425,258042238,1024,3072,49877076,57344,114814580,0,542403.396989,342.198165,10516.149038,1657,1018,592,2630,1262,0,1024,0,0,274671771,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 314160.033, ""latency_p99_upper_ns"": 4718592}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5361935.781, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 49, ""latency_mean_ns"": 8345834.982, ""latency_p99_upper_ns"": 12582912}]"
+mixed_tight,threshold2,2,ok,threshold,0.12.0,2097152,41728,1097792,393312,72752,524336,1900544,134805557,52099602,26201196,1024,3072,49877076,26814720,114814580,0,6802.764732,1222.5673,10082.699192,363,241,368,5949,0,592,0,0,1024,83969655,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47229.56, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5083369.83, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082868.22, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy,2,ok,copy,0.12.0,2097152,41728,1104736,393312,79920,524336,1900544,135397301,55535720,28191073,1024,3072,49877076,26872064,114814580,0,7296.683374,1825.786254,10851.770961,364,925,376,6280,0,556,0,0,0,81078620,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 50441.328, ""latency_p99_upper_ns"": 163840}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5086253.071, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8088040.091, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold8,2,ok,threshold,0.12.0,2097152,41728,1097792,393312,11312,524336,2048000,135143135,54181725,28073539,1024,3072,49877076,1059072,114814580,0,7971.142415,924.89692,10793.387694,237,89,259,5805,0,587,0,0,1024,82256234,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 49150.131, ""latency_p99_upper_ns"": 163840}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5084346.661, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8083800.547, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,borrow,2,ok,borrow,0.12.0,2097152,41728,2097024,2047296,0,524336,3719168,519737827,63401151,410873515,1024,3072,49877076,0,114814580,0,869390.688093,0.0,10874.854354,1612,0,584,2677,1267,0,0,0,0,457480540,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 498894.016, ""latency_p99_upper_ns"": 7864320}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5554388.391, ""latency_p99_upper_ns"": 12582912}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 8572436.932, ""latency_p99_upper_ns"": 15728640}]"
+mixed_tight,copy_no_pool,2,ok,copy,0.12.0,2097152,41728,842368,393312,79920,524336,1933312,135808674,61310764,27409732,1024,3072,49877076,26872064,114814580,0,8492.13471,1909.35548,10184.015437,3849,3072,1024,0,0,538,0,0,0,75774039,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 55750.675, ""latency_p99_upper_ns"": 196608}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5097561.83, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8097147.871, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,compact,2,ok,compact,0.12.0,2097152,41728,2096496,2047296,3360,524336,3719168,330655613,57992572,257126466,1024,3072,49877076,57344,114814580,0,542286.835871,342.201335,10592.82654,1620,1018,589,2670,1246,0,1024,0,0,274045502,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 314214.117, ""latency_p99_upper_ns"": 4718592}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5361784.028, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 49, ""latency_mean_ns"": 8345733.162, ""latency_p99_upper_ns"": 12582912}]"
+mixed_tight,shared_copy,2,ok,shared_copy,0.12.0,2097152,41728,1097792,393312,72752,524336,1900544,134725602,52125932,26256537,1024,3072,49877076,26814720,114814580,0,6831.305534,1226.062002,10092.239062,365,226,360,5970,0,576,0,0,1024,83779201,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47423.973, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082508.901, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082650.268, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,compact,3,ok,compact,0.12.0,2097152,41728,2096656,2047296,3360,524336,3719168,332809762,64506702,255295188,1024,3072,49877076,57344,114814580,0,544031.993873,348.13532,10927.535411,1623,1008,583,2683,1227,0,1024,0,0,270135277,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 316210.616, ""latency_p99_upper_ns"": 4718592}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5373501.093, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 49, ""latency_mean_ns"": 8409239.137, ""latency_p99_upper_ns"": 12582912}]"
+mixed_tight,threshold2,3,ok,threshold,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134646087,51969989,26192074,1024,3072,49877076,26814720,114814580,0,6812.54134,1229.637184,10083.25152,369,241,365,5946,0,582,0,0,1024,83864700,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47274.193, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082291.09, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8084035.099, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy,3,ok,copy,0.12.0,2097152,41728,1104848,393312,79920,524336,1900544,134732754,52218674,26241260,1024,3072,49877076,26872064,114814580,0,6810.984162,1804.529206,10104.502269,368,949,374,6254,0,584,0,0,0,83719457,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47404.955, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082343.96, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082308.803, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,shared_copy,3,ok,shared_copy,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134687032,52085095,26215409,1024,3072,49877076,26814720,114814580,0,6852.502663,1223.987439,10100.060122,365,235,364,5957,0,585,0,0,1024,83840818,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47354.551, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081713.058, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082095.55, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,borrow,3,ok,borrow,0.12.0,2097152,41728,2097072,2047296,0,524336,3719168,516415971,57490634,412616864,1024,3072,49877076,0,114814580,0,865936.173669,0.0,10532.202462,1624,0,582,2667,1258,0,0,0,0,460245677,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 495746.732, ""latency_p99_upper_ns"": 7864320}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5527499.187, ""latency_p99_upper_ns"": 12582912}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 8541909.699, ""latency_p99_upper_ns"": 15728640}]"
+mixed_tight,copy_no_pool,3,ok,copy,0.12.0,2097152,41728,842368,393312,79920,524336,1916928,135708499,59498427,27293452,1024,3072,49877076,26872064,114814580,0,8320.069469,1853.590142,10172.640074,3849,3072,1024,0,0,550,0,0,0,77469437,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 53679.489, ""latency_p99_upper_ns"": 180224}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5093041.554, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8093789.758, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold8,3,ok,threshold,0.12.0,2097152,41728,1097792,393312,11312,524336,2048000,134580129,50901202,26138215,1024,3072,49877076,1059072,114814580,0,7468.893211,924.833553,10074.589742,237,99,260,5794,0,603,0,0,1024,84894241,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 46199.245, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5080295.214, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082153.254, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,compact,4,ok,compact,0.12.0,2097152,41728,2095936,2047296,3360,524336,3768320,330364653,56737666,257390641,1024,3072,49877076,57344,114814580,0,542129.496495,342.3922,10487.947668,1626,1018,584,2669,1234,0,1024,0,0,274961005,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 314000.227, ""latency_p99_upper_ns"": 4718592}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5359881.678, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 49, ""latency_mean_ns"": 8345470.393, ""latency_p99_upper_ns"": 12582912}]"
+mixed_tight,threshold2,4,ok,threshold,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134641407,51772899,26303805,1024,3072,49877076,26814720,114814580,0,6823.249522,1222.425123,10156.044791,363,239,367,5952,0,584,0,0,1024,83930889,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47208.702, ""latency_p99_upper_ns"": 131072}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081715.549, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8082551.032, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,threshold8,4,ok,threshold,0.12.0,2097152,41728,1097792,393312,11312,524336,2048000,134636889,51692325,26232175,1024,3072,49877076,1059072,114814580,0,7604.090343,924.831397,10109.160375,237,97,259,5797,0,600,0,0,1024,84203974,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 46850.104, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5081772.482, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8081990.295, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,borrow,4,ok,borrow,0.12.0,2097152,41728,2097024,2047296,0,524336,3719168,516507633,56956626,413462854,1024,3072,49877076,0,114814580,0,866066.604394,0.0,10498.181654,1635,0,588,2650,1258,0,0,0,0,460890935,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 495819.875, ""latency_p99_upper_ns"": 7864320}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 5527650.658, ""latency_p99_upper_ns"": 12582912}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 30, ""latency_mean_ns"": 8542682.03, ""latency_p99_upper_ns"": 15728640}]"
+mixed_tight,shared_copy,4,ok,shared_copy,0.12.0,2097152,41728,1097792,393312,72752,524336,1884160,134698503,52062419,26232455,1024,3072,49877076,26814720,114814580,0,6807.634601,1226.698884,10096.010075,358,229,363,5971,0,573,0,0,1024,83820760,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 47338.287, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5082803.919, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8081430.476, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy_no_pool,4,ok,copy,0.12.0,2097152,41728,842368,393312,79920,524336,1933312,135617374,59370307,27370335,1024,3072,49877076,26872064,114814580,0,8306.118105,1881.770411,10193.350967,3849,3072,1024,0,0,541,0,0,0,77447978,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 54118.737, ""latency_p99_upper_ns"": 180224}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5093193.132, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8094306.969, ""latency_p99_upper_ns"": 8388608}]"
+mixed_tight,copy,4,ok,copy,0.12.0,2097152,41728,1104736,393312,79920,524336,1884160,135101765,53612089,26369173,1024,3072,49877076,26872064,114814580,0,6944.794448,1822.831558,10130.150831,348,886,368,6343,0,561,0,0,0,82695691,0,0,"[{""emitted"": 1024, ""bytes"": 26757376, ""peak_count"": 1, ""latency_mean_ns"": 48573.396, ""latency_p99_upper_ns"": 147456}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 5083912.79, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 1024, ""bytes"": 57344, ""peak_count"": 64, ""latency_mean_ns"": 8083831.809, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy_no_pool,0,ok,copy,0.12.0,2097152,41728,170672,24672,14896,98400,1835008,66381179,14937944,10634360,512,1536,5259666,319488,6312628,14086144,191.835816,748.822762,436.544508,1273,1536,1024,0,0,200,0,0,0,51858352,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26502.654, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055591.338, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038187.436, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,borrow,0,ok,borrow,0.12.0,2097152,41728,1208192,1059888,0,98400,2785280,66395496,14949295,10748920,512,1536,5259666,0,6312628,14086144,67632.156584,0.0,441.340054,70,0,2,2225,0,210,0,0,0,51867983,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26677.738, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055635.91, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040456.355, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold8,0,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1851392,66344311,14626628,10598197,512,1536,5259666,290816,6312628,14086144,189.993439,460.282359,437.832685,6,65,2,3248,0,201,0,0,512,52108022,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26057.676, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054707.516, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038718.686, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,shared_copy,0,ok,shared_copy,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66360126,14610198,10558947,512,1536,5259666,290816,6312628,14086144,189.278595,460.358957,433.475216,6,65,2,3248,0,210,0,0,512,52155647,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26056.072, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054720.746, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039527.611, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,compact,0,ok,compact,0.12.0,2097152,41728,1209200,1059888,7168,98400,2899968,66352515,15174956,10767457,512,1536,5259666,28672,6312628,14086144,42522.512719,170.992644,444.338525,462,456,2,1889,0,203,512,0,0,51584350,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26833.023, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055824.906, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037818.045, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy,0,ok,copy,0.12.0,2097152,41728,187312,24672,14896,98400,1835008,66358774,14704746,10580140,512,1536,5259666,319488,6312628,14086144,190.401936,748.797361,434.190092,6,546,2,3279,0,198,0,0,0,52055904,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26138.373, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054837.756, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038347.354, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold2,0,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1851392,66343256,14610428,10601249,512,1536,5259666,290816,6312628,14086144,190.005404,460.293238,435.304664,6,65,2,3248,0,199,0,0,512,52113330,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26103.785, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054791.455, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038668.434, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold8,1,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66620533,15009658,10599246,512,1536,5259666,290816,6312628,14086144,190.711835,461.162485,439.194778,6,67,2,3246,0,195,0,0,512,52089340,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26514.744, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5059599.168, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8052646.494, ""latency_p99_upper_ns"": 9437184}]"
+metadata_heavy,copy_no_pool,1,ok,copy,0.12.0,2097152,41728,170672,24672,14896,98400,1835008,69246534,16610834,11758115,512,1536,5259666,319488,6312628,14086144,215.365911,778.347747,481.501477,1273,1536,1024,0,0,164,0,0,0,52395416,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 29861.328, ""latency_p99_upper_ns"": 57344}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5481519.523, ""latency_p99_upper_ns"": 10485760}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8132478.682, ""latency_p99_upper_ns"": 10485760}]"
+metadata_heavy,shared_copy,1,ok,shared_copy,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,67338922,15543047,10965512,512,1536,5259666,290816,6312628,14086144,198.833427,461.43294,455.786835,6,88,2,3225,0,170,0,0,512,52096250,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 27620.291, ""latency_p99_upper_ns"": 53248}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5405312.287, ""latency_p99_upper_ns"": 9437184}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8058747.33, ""latency_p99_upper_ns"": 9437184}]"
+metadata_heavy,copy,1,ok,copy,0.12.0,2097152,41728,187312,24672,14896,98400,1835008,66437867,14887131,10719986,512,1536,5259666,319488,6312628,14086144,192.97609,748.927344,442.835871,6,546,2,3279,0,206,0,0,0,51911693,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26502.299, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055229.1, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040517.863, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold2,1,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66341459,14573003,10555283,512,1536,5259666,290816,6312628,14086144,189.19959,460.262935,433.563583,6,65,2,3248,0,202,0,0,512,52150322,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26047.523, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054844.742, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037890.609, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,borrow,1,ok,borrow,0.12.0,2097152,41728,1208192,1059888,0,98400,2801664,66302663,14680433,10680579,512,1536,5259666,0,6312628,14086144,67603.216745,0.0,441.482243,70,0,2,2225,0,203,0,0,0,52022749,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26241.209, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054887.895, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8036938.547, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,compact,1,ok,compact,0.12.0,2097152,41728,1209200,1059888,7168,98400,2916352,66647996,15645769,10897093,512,1536,5259666,28672,6312628,14086144,42531.184104,171.185155,448.382215,462,456,2,1889,0,208,512,0,0,51484721,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 27363.605, ""latency_p99_upper_ns"": 49152}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5056927.043, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8042303.346, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,shared_copy,2,ok,shared_copy,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66509552,15439851,10723161,512,1536,5259666,290816,6312628,14086144,194.692414,460.401472,443.814792,6,65,2,3248,0,188,0,0,512,51559999,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 27221.904, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5102159.828, ""latency_p99_upper_ns"": 6291456}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039936.652, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold2,2,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1851392,66675868,15617313,10794500,512,1536,5259666,290816,6312628,14086144,196.368374,460.582208,453.168708,6,72,2,3241,0,206,0,0,512,51576007,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 27391.873, ""latency_p99_upper_ns"": 45056}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5063401.098, ""latency_p99_upper_ns"": 5767168}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8043009.266, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold8,2,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66346091,14749114,10663838,512,1536,5259666,290816,6312628,14086144,191.566293,460.387978,441.272197,6,65,2,3248,0,198,0,0,512,51956135,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26444.111, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055009.982, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040053.549, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,borrow,2,ok,borrow,0.12.0,2097152,41728,1208192,1059888,0,98400,2768896,66340906,14840713,10710339,512,1536,5259666,0,6312628,14086144,67628.848076,0.0,441.911742,70,0,2,2225,0,214,0,0,0,51926596,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26533.881, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055556.934, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040046.408, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy_no_pool,2,ok,copy,0.12.0,2097152,41728,170672,24672,14896,98400,1851392,66367572,14844612,10626817,512,1536,5259666,319488,6312628,14086144,191.787957,748.742987,439.039763,1273,1536,1024,0,0,202,0,0,0,51918865,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26443.496, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055503.67, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037164.848, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,compact,2,ok,compact,0.12.0,2097152,41728,1209200,1059888,7168,98400,2916352,66456221,15237761,10832907,512,1536,5259666,28672,6312628,14086144,42524.965388,171.106633,446.50427,462,456,2,1889,0,211,512,0,0,51628844,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26894.043, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5056115.033, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040094.787, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy,2,ok,copy,0.12.0,2097152,41728,187312,24672,14896,98400,1818624,66358054,14786258,10588699,512,1536,5259666,319488,6312628,14086144,190.767691,748.949984,437.20655,6,546,2,3279,0,202,0,0,0,51982953,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26290.178, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055243.682, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040476.592, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,shared_copy,3,ok,shared_copy,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66340017,14641398,10583202,512,1536,5259666,290816,6312628,14086144,189.850967,460.201756,434.46664,6,65,2,3248,0,200,0,0,512,52101474,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26126.43, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054896.006, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037126.236, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,borrow,3,ok,borrow,0.12.0,2097152,41728,1208192,1059888,0,98400,2768896,66397387,14926280,10743184,512,1536,5259666,0,6312628,14086144,67622.063537,0.0,442.942199,70,0,2,2225,0,212,0,0,0,51935519,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26540.598, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055706.689, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039215.434, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy,3,ok,copy,0.12.0,2097152,41728,187312,24672,14896,98400,1835008,66347591,14688841,10558757,512,1536,5259666,319488,6312628,14086144,190.237303,748.906445,434.052077,6,546,2,3279,0,201,0,0,0,52048363,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26185.322, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054934.725, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039957.693, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,compact,3,ok,compact,0.12.0,2097152,41728,1209200,1059888,7168,98400,2916352,66425702,15126826,10762572,512,1536,5259666,28672,6312628,14086144,42518.234312,171.124375,442.813559,462,456,2,1889,0,207,512,0,0,51722109,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26699.592, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055311.875, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039588.77, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold8,3,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66342183,14624958,10558072,512,1536,5259666,290816,6312628,14086144,189.596919,460.250779,436.103934,6,65,2,3248,0,199,0,0,512,52113950,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26082.711, ""latency_p99_upper_ns"": 32768}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054439.891, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037911.916, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy_no_pool,3,ok,copy,0.12.0,2097152,41728,170672,24672,14896,98400,1835008,66421906,14924036,10733514,512,1536,5259666,319488,6312628,14086144,193.388376,748.846289,443.059571,1273,1536,1024,0,0,207,0,0,0,51871512,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26630.812, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055263.076, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039399.533, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold2,3,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66363184,14629240,10568715,512,1536,5259666,290816,6312628,14086144,189.501318,460.195707,436.121559,6,65,2,3248,0,199,0,0,512,52142767,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26129.004, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054684.932, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8036606.693, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold2,4,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66354498,14608671,10552983,512,1536,5259666,290816,6312628,14086144,189.286265,460.245208,433.358809,6,65,2,3248,0,197,0,0,512,52143565,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26044.074, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054765.459, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037717.471, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy_no_pool,4,ok,copy,0.12.0,2097152,41728,170672,24672,14896,98400,1851392,66440315,15042208,10714630,512,1536,5259666,319488,6312628,14086144,193.34471,749.072578,442.776453,1273,1536,1024,0,0,203,0,0,0,51818059,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26719.596, ""latency_p99_upper_ns"": 40960}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055539.021, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8042928.75, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,shared_copy,4,ok,shared_copy,0.12.0,2097152,41728,180144,24672,7728,98400,1835008,66550686,14565611,10569760,512,1536,5259666,290816,6312628,14086144,189.196651,460.427963,435.936714,6,70,2,3243,0,199,0,0,512,52394259,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26054.17, ""latency_p99_upper_ns"": 30720}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054468.873, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8040821.889, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,compact,4,ok,compact,0.12.0,2097152,41728,1209200,1059888,7168,98400,2932736,66346982,15115580,10730381,512,1536,5259666,28672,6312628,14086144,42539.689103,170.963142,440.137993,462,456,2,1889,0,200,512,0,0,51642878,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26772.898, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5057876.094, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8039346.365, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,threshold8,4,ok,threshold,0.12.0,2097152,41728,180144,24672,7728,98400,1851392,66367685,14678765,10612300,512,1536,5259666,290816,6312628,14086144,190.199351,460.290364,438.024028,6,65,2,3248,0,200,0,0,512,52099788,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26178.92, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054797.43, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038471.338, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,borrow,4,ok,borrow,0.12.0,2097152,41728,1208192,1059888,0,98400,2785280,66395630,14769876,10679603,512,1536,5259666,0,6312628,14086144,67615.986637,0.0,438.40001,70,0,2,2225,0,207,0,0,0,52035492,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26350.551, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5054965.338, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8038469.066, ""latency_p99_upper_ns"": 8388608}]"
+metadata_heavy,copy,4,ok,copy,0.12.0,2097152,41728,187312,24672,14896,98400,1835008,66338315,14754424,10609310,512,1536,5259666,319488,6312628,14086144,190.968242,748.772024,435.574111,6,546,2,3279,0,199,0,0,0,51978025,0,0,"[{""emitted"": 512, ""bytes"": 262144, ""peak_count"": 1, ""latency_mean_ns"": 26285.051, ""latency_p99_upper_ns"": 36864}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 5055200.059, ""latency_p99_upper_ns"": 5242880}, {""emitted"": 512, ""bytes"": 28672, ""peak_count"": 64, ""latency_mean_ns"": 8037468.172, ""latency_p99_upper_ns"": 8388608}]"
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.json
new file mode 100644
index 0000000..9bf47cb
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/raw.json
@@ -0,0 +1,12532 @@
+[
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 131703634,
+ "cpu_ns": 34750648,
+ "parse_call_ns": 21989760,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1842.615404,
+ "output_byte_seconds": 919.75921,
+ "parser_byte_seconds": 2883.244752,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97097912,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8051720.034,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 131996119,
+ "cpu_ns": 38004572,
+ "parse_call_ns": 22434299,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540791.270719,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2928.256675,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 26,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94192606,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8057605.331,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5521408,
+ "elapsed_ns": 132124751,
+ "cpu_ns": 37612015,
+ "parse_call_ns": 22444229,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540845.471315,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2930.090388,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 53,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94791711,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8058299.849,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131620844,
+ "cpu_ns": 34446035,
+ "parse_call_ns": 21905479,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1832.609103,
+ "output_byte_seconds": 920.078119,
+ "parser_byte_seconds": 2872.388672,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97293567,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054286.008,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 237296,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 132233158,
+ "cpu_ns": 41767998,
+ "parse_call_ns": 24756316,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2069.543688,
+ "output_byte_seconds": 920.140424,
+ "parser_byte_seconds": 2901.308237,
+ "source_allocations": 4082,
+ "output_allocations": 1024,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 19,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 90619067,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8059175.662,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131600270,
+ "cpu_ns": 34455850,
+ "parse_call_ns": 21964978,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1832.537919,
+ "output_byte_seconds": 920.025416,
+ "parser_byte_seconds": 2880.380829,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97270417,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8053796.131,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 131715584,
+ "cpu_ns": 34456703,
+ "parse_call_ns": 21940218,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1833.007769,
+ "output_byte_seconds": 920.07894,
+ "parser_byte_seconds": 2877.016945,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97393619,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054276.953,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132171843,
+ "cpu_ns": 38070312,
+ "parse_call_ns": 22523797,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540815.06589,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2937.269732,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 40,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94338529,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8057936.641,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 237296,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 132199048,
+ "cpu_ns": 42202499,
+ "parse_call_ns": 24805054,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2084.967873,
+ "output_byte_seconds": 920.132302,
+ "parser_byte_seconds": 2905.942804,
+ "source_allocations": 4082,
+ "output_allocations": 1024,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 29,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 90146770,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8059478.906,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131708165,
+ "cpu_ns": 34804961,
+ "parse_call_ns": 22044118,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1844.634105,
+ "output_byte_seconds": 919.759432,
+ "parser_byte_seconds": 2890.857973,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97053198,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8051751.524,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131798127,
+ "cpu_ns": 34803856,
+ "parse_call_ns": 22044512,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1846.36305,
+ "output_byte_seconds": 919.612987,
+ "parser_byte_seconds": 2891.382584,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97156768,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050483.774,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5521408,
+ "elapsed_ns": 131976979,
+ "cpu_ns": 38591495,
+ "parse_call_ns": 22573964,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540860.949553,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2940.513903,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 28,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 93626665,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8058679.423,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131752053,
+ "cpu_ns": 34888537,
+ "parse_call_ns": 21974890,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1845.194241,
+ "output_byte_seconds": 919.599974,
+ "parser_byte_seconds": 2880.87266,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 17,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97030621,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050419.036,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131720609,
+ "cpu_ns": 34747849,
+ "parse_call_ns": 21999728,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1843.805295,
+ "output_byte_seconds": 919.628727,
+ "parser_byte_seconds": 2884.923744,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97113750,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050578.244,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131735071,
+ "cpu_ns": 34877739,
+ "parse_call_ns": 22030534,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1847.409016,
+ "output_byte_seconds": 919.636562,
+ "parser_byte_seconds": 2888.89668,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 96987832,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050770.82,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132186905,
+ "cpu_ns": 38709650,
+ "parse_call_ns": 22486562,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540826.901328,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2931.839266,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 36,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 93736446,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8058254.455,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 134003964,
+ "cpu_ns": 36820353,
+ "parse_call_ns": 22141327,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1907.646695,
+ "output_byte_seconds": 924.396419,
+ "parser_byte_seconds": 2903.071145,
+ "source_allocations": 9,
+ "output_allocations": 116,
+ "parser_allocations": 1,
+ "reuses": 6004,
+ "budget_waits": 0,
+ "slot_waits": 25,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97345374,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8093864.112,
+ "latency_p99_upper_ns": 9437184
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 132093280,
+ "cpu_ns": 37140317,
+ "parse_call_ns": 22338927,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1928.638533,
+ "output_byte_seconds": 919.864631,
+ "parser_byte_seconds": 2930.310014,
+ "source_allocations": 9,
+ "output_allocations": 68,
+ "parser_allocations": 1,
+ "reuses": 6052,
+ "budget_waits": 0,
+ "slot_waits": 20,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 95013211,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054865.09,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5554176,
+ "elapsed_ns": 132469040,
+ "cpu_ns": 41862764,
+ "parse_call_ns": 22964342,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541099.43903,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2986.938382,
+ "source_allocations": 73,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5032,
+ "budget_waits": 0,
+ "slot_waits": 49,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 90878204,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8063020.332,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 237296,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 137450461,
+ "cpu_ns": 46306762,
+ "parse_call_ns": 25720817,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2217.245474,
+ "output_byte_seconds": 934.97033,
+ "parser_byte_seconds": 2945.941354,
+ "source_allocations": 4082,
+ "output_allocations": 1024,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 23,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 91429169,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8191749.104,
+ "latency_p99_upper_ns": 11534336
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131976855,
+ "cpu_ns": 36997295,
+ "parse_call_ns": 22056693,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1904.528214,
+ "output_byte_seconds": 920.059714,
+ "parser_byte_seconds": 2891.295258,
+ "source_allocations": 9,
+ "output_allocations": 65,
+ "parser_allocations": 1,
+ "reuses": 6055,
+ "budget_waits": 0,
+ "slot_waits": 21,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 95230128,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056258.001,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 132144262,
+ "cpu_ns": 36810738,
+ "parse_call_ns": 22394390,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1914.610493,
+ "output_byte_seconds": 920.080986,
+ "parser_byte_seconds": 2937.462741,
+ "source_allocations": 9,
+ "output_allocations": 71,
+ "parser_allocations": 1,
+ "reuses": 6049,
+ "budget_waits": 0,
+ "slot_waits": 39,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 95437850,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056316.891,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131627799,
+ "cpu_ns": 34748983,
+ "parse_call_ns": 22050963,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1845.118437,
+ "output_byte_seconds": 920.020651,
+ "parser_byte_seconds": 2891.313221,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 19,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 96996391,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054019.278,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132093080,
+ "cpu_ns": 38378509,
+ "parse_call_ns": 22460168,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540907.798619,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2928.186919,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 43,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 93965206,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8059384.654,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 237296,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 132246841,
+ "cpu_ns": 41768202,
+ "parse_call_ns": 24673720,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2066.312998,
+ "output_byte_seconds": 920.19798,
+ "parser_byte_seconds": 2896.434244,
+ "source_allocations": 4082,
+ "output_allocations": 1024,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 90608121,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8059680.607,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131689453,
+ "cpu_ns": 35243759,
+ "parse_call_ns": 22012604,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1857.757504,
+ "output_byte_seconds": 919.947028,
+ "parser_byte_seconds": 2887.51415,
+ "source_allocations": 9,
+ "output_allocations": 68,
+ "parser_allocations": 1,
+ "reuses": 6052,
+ "budget_waits": 0,
+ "slot_waits": 27,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 96622803,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8053765.222,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 132103712,
+ "cpu_ns": 35248408,
+ "parse_call_ns": 22004780,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1858.44117,
+ "output_byte_seconds": 919.973445,
+ "parser_byte_seconds": 2885.070598,
+ "source_allocations": 9,
+ "output_allocations": 73,
+ "parser_allocations": 1,
+ "reuses": 6047,
+ "budget_waits": 0,
+ "slot_waits": 22,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97018510,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054006.321,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132436008,
+ "cpu_ns": 40869521,
+ "parse_call_ns": 22656213,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540941.338269,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2953.318689,
+ "source_allocations": 75,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5030,
+ "budget_waits": 0,
+ "slot_waits": 52,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 91954404,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8060462.982,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5554176,
+ "elapsed_ns": 132110379,
+ "cpu_ns": 38257181,
+ "parse_call_ns": 22557256,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540811.125254,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2944.323595,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 56,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94112952,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8057929.717,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 131804916,
+ "cpu_ns": 34977352,
+ "parse_call_ns": 22094634,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1853.831647,
+ "output_byte_seconds": 920.149467,
+ "parser_byte_seconds": 2897.713188,
+ "source_allocations": 9,
+ "output_allocations": 67,
+ "parser_allocations": 1,
+ "reuses": 6053,
+ "budget_waits": 0,
+ "slot_waits": 31,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 96937037,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8055361.395,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 237296,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 135161451,
+ "cpu_ns": 44330024,
+ "parse_call_ns": 25503982,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2157.809223,
+ "output_byte_seconds": 924.543547,
+ "parser_byte_seconds": 2946.975235,
+ "source_allocations": 4082,
+ "output_allocations": 1024,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 35,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 91118882,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8099348.558,
+ "latency_p99_upper_ns": 10485760
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1802240,
+ "elapsed_ns": 132588310,
+ "cpu_ns": 37673671,
+ "parse_call_ns": 22518430,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1949.11739,
+ "output_byte_seconds": 920.155569,
+ "parser_byte_seconds": 2954.042078,
+ "source_allocations": 9,
+ "output_allocations": 78,
+ "parser_allocations": 1,
+ "reuses": 6042,
+ "budget_waits": 0,
+ "slot_waits": 36,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94895218,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8057756.78,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 131620718,
+ "cpu_ns": 34580946,
+ "parse_call_ns": 21993246,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1837.245494,
+ "output_byte_seconds": 919.925321,
+ "parser_byte_seconds": 2884.001314,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 16,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 97154068,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8053071.22,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 4427696,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132000791,
+ "cpu_ns": 37927424,
+ "parse_call_ns": 22507290,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540831.163899,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2938.768696,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 30,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 94241105,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8058140.749,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 33536,
+ "peak_reserved_bytes": 303072,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 132283829,
+ "cpu_ns": 37157688,
+ "parse_call_ns": 22116989,
+ "accepted": 1024,
+ "emitted": 1024,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1917.711679,
+ "output_byte_seconds": 920.053817,
+ "parser_byte_seconds": 2900.603467,
+ "source_allocations": 9,
+ "output_allocations": 67,
+ "parser_allocations": 1,
+ "reuses": 6053,
+ "budget_waits": 0,
+ "slot_waits": 38,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 95415784,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056291.708,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5373952,
+ "elapsed_ns": 132804710,
+ "cpu_ns": 49883960,
+ "parse_call_ns": 22784485,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540593.356702,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2990.235132,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 578,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84130488,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45505.588,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070252.164,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8055489.045,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4436784,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 6944,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132699783,
+ "cpu_ns": 50261222,
+ "parse_call_ns": 22546544,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340105.36302,
+ "output_byte_seconds": 342.277671,
+ "parser_byte_seconds": 2958.801865,
+ "source_allocations": 897,
+ "output_allocations": 913,
+ "parser_allocations": 1,
+ "reuses": 4319,
+ "budget_waits": 0,
+ "slot_waits": 550,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83652241,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45463.711,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069982.729,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054576.42,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 132438636,
+ "cpu_ns": 46508730,
+ "parse_call_ns": 22104890,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1994.687521,
+ "output_byte_seconds": 1188.73405,
+ "parser_byte_seconds": 2903.952009,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 538,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87037859,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42492.519,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069205.345,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052022.729,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 318432,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132301692,
+ "cpu_ns": 46274024,
+ "parse_call_ns": 22012014,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1991.776071,
+ "output_byte_seconds": 1766.57547,
+ "parser_byte_seconds": 2891.89841,
+ "source_allocations": 9,
+ "output_allocations": 1025,
+ "parser_allocations": 1,
+ "reuses": 7143,
+ "budget_waits": 0,
+ "slot_waits": 563,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 87083196,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42221.575,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068352.743,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8049671.308,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 252544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1933312,
+ "elapsed_ns": 132221655,
+ "cpu_ns": 46432790,
+ "parse_call_ns": 22094470,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2002.66499,
+ "output_byte_seconds": 1764.18462,
+ "parser_byte_seconds": 2896.537304,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 534,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 86822233,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42461.52,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068300.921,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054065.407,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132423215,
+ "cpu_ns": 46202689,
+ "parse_call_ns": 22137673,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1992.776523,
+ "output_byte_seconds": 1183.803646,
+ "parser_byte_seconds": 2909.259091,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 559,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87298460,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42209.067,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068504.791,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052025.9,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132072752,
+ "cpu_ns": 44818714,
+ "parse_call_ns": 22007505,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2372.402719,
+ "output_byte_seconds": 919.579066,
+ "parser_byte_seconds": 2891.111165,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 531,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 88271004,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41081.91,
+ "latency_p99_upper_ns": 49152
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067409.945,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052229.961,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 318432,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132122049,
+ "cpu_ns": 45960158,
+ "parse_call_ns": 22062914,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1985.913742,
+ "output_byte_seconds": 1766.681864,
+ "parser_byte_seconds": 2899.647733,
+ "source_allocations": 9,
+ "output_allocations": 1025,
+ "parser_allocations": 1,
+ "reuses": 7143,
+ "budget_waits": 0,
+ "slot_waits": 530,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 87159643,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42080.341,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068084.019,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8053834.564,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 252544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 132225178,
+ "cpu_ns": 46345346,
+ "parse_call_ns": 22106440,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1998.568774,
+ "output_byte_seconds": 1764.360213,
+ "parser_byte_seconds": 2898.609,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 531,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 86929226,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42412.925,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068204.178,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052346.592,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132119197,
+ "cpu_ns": 45785542,
+ "parse_call_ns": 22119160,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1985.975023,
+ "output_byte_seconds": 1182.61037,
+ "parser_byte_seconds": 2906.107753,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 535,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87289352,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42063.476,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068193.573,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8051854.179,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4436784,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 6944,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5603328,
+ "elapsed_ns": 132689456,
+ "cpu_ns": 50225388,
+ "parse_call_ns": 22679397,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340115.562513,
+ "output_byte_seconds": 342.313483,
+ "parser_byte_seconds": 2976.797692,
+ "source_allocations": 896,
+ "output_allocations": 908,
+ "parser_allocations": 1,
+ "reuses": 4325,
+ "budget_waits": 0,
+ "slot_waits": 548,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83654110,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45534.298,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070135.917,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8055038.37,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132687220,
+ "cpu_ns": 45610919,
+ "parse_call_ns": 22143479,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2398.303122,
+ "output_byte_seconds": 919.310014,
+ "parser_byte_seconds": 2908.551305,
+ "source_allocations": 9,
+ "output_allocations": 73,
+ "parser_allocations": 1,
+ "reuses": 6047,
+ "budget_waits": 0,
+ "slot_waits": 557,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 88180228,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41592.506,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067924.312,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050249.576,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 133179387,
+ "cpu_ns": 47009567,
+ "parse_call_ns": 22053622,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2001.098596,
+ "output_byte_seconds": 1195.094634,
+ "parser_byte_seconds": 2898.481421,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 619,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87400987,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42811.697,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068344.258,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054983.926,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5373952,
+ "elapsed_ns": 132590517,
+ "cpu_ns": 49691116,
+ "parse_call_ns": 22667622,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540625.036225,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2974.002082,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 555,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84069041,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45356.652,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069262.154,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8055874.806,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5373952,
+ "elapsed_ns": 132595906,
+ "cpu_ns": 48936945,
+ "parse_call_ns": 22622066,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540538.226737,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2969.006017,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 550,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84820014,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 44590.665,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069713.765,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054486.477,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132243573,
+ "cpu_ns": 45674856,
+ "parse_call_ns": 22029775,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1978.146096,
+ "output_byte_seconds": 1181.588579,
+ "parser_byte_seconds": 2894.51268,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 547,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87607899,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41881.888,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067912.655,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8049931.179,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4436784,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 6944,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5603328,
+ "elapsed_ns": 132732463,
+ "cpu_ns": 49739534,
+ "parse_call_ns": 22671992,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340105.112239,
+ "output_byte_seconds": 342.468555,
+ "parser_byte_seconds": 2974.922545,
+ "source_allocations": 893,
+ "output_allocations": 887,
+ "parser_allocations": 1,
+ "reuses": 4349,
+ "budget_waits": 0,
+ "slot_waits": 562,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84142850,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 44979.318,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069891.561,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056164.197,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132272059,
+ "cpu_ns": 45320979,
+ "parse_call_ns": 22141356,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2389.486333,
+ "output_byte_seconds": 919.390876,
+ "parser_byte_seconds": 2908.882515,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 563,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 88007671,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41406.16,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068143.112,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050851.553,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 318432,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1867776,
+ "elapsed_ns": 132351078,
+ "cpu_ns": 46122525,
+ "parse_call_ns": 22082400,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1991.903399,
+ "output_byte_seconds": 1762.771138,
+ "parser_byte_seconds": 2900.645032,
+ "source_allocations": 9,
+ "output_allocations": 1026,
+ "parser_allocations": 1,
+ "reuses": 7142,
+ "budget_waits": 0,
+ "slot_waits": 558,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 87297075,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42091.413,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068444.485,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8048834.24,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132284819,
+ "cpu_ns": 45823432,
+ "parse_call_ns": 22066434,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1983.569581,
+ "output_byte_seconds": 1182.323172,
+ "parser_byte_seconds": 2898.432644,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 542,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87424368,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42064.699,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068229.227,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050900.843,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 252544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 132459707,
+ "cpu_ns": 47692750,
+ "parse_call_ns": 22170762,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2023.677274,
+ "output_byte_seconds": 1777.322506,
+ "parser_byte_seconds": 2907.132194,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 540,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 85990890,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 43327.485,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070694.294,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8055086.674,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132140503,
+ "cpu_ns": 45825210,
+ "parse_call_ns": 22125197,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1985.69773,
+ "output_byte_seconds": 1183.215978,
+ "parser_byte_seconds": 2906.687041,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 533,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87310088,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42062.03,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068036.782,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050191.375,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 252544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1916928,
+ "elapsed_ns": 132297747,
+ "cpu_ns": 46669804,
+ "parse_call_ns": 22175323,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2009.648765,
+ "output_byte_seconds": 1766.146335,
+ "parser_byte_seconds": 2907.094824,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 542,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 86663675,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42678.905,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068637.263,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054142.04,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 318432,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132282510,
+ "cpu_ns": 46415608,
+ "parse_call_ns": 22079359,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1996.444688,
+ "output_byte_seconds": 1765.761752,
+ "parser_byte_seconds": 2901.17633,
+ "source_allocations": 9,
+ "output_allocations": 1025,
+ "parser_allocations": 1,
+ "reuses": 7143,
+ "budget_waits": 0,
+ "slot_waits": 554,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 86986908,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42277.028,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070038.574,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050279.443,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5373952,
+ "elapsed_ns": 132489898,
+ "cpu_ns": 48808681,
+ "parse_call_ns": 22654163,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540484.370521,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2972.753951,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 556,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84863248,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 44578.165,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069410.422,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8053620.063,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 132283398,
+ "cpu_ns": 45911917,
+ "parse_call_ns": 22085581,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1984.871517,
+ "output_byte_seconds": 1183.416247,
+ "parser_byte_seconds": 2903.347153,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 561,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87433143,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42043.254,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068356.958,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8050581.195,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132082805,
+ "cpu_ns": 44815017,
+ "parse_call_ns": 22070822,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2374.331913,
+ "output_byte_seconds": 919.214871,
+ "parser_byte_seconds": 2899.672121,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 534,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 88275454,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41070.548,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067369.015,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8049008.122,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4436784,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7056,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5488640,
+ "elapsed_ns": 132597323,
+ "cpu_ns": 49981497,
+ "parse_call_ns": 22749218,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340108.105991,
+ "output_byte_seconds": 342.554096,
+ "parser_byte_seconds": 2986.081381,
+ "source_allocations": 912,
+ "output_allocations": 907,
+ "parser_allocations": 1,
+ "reuses": 4310,
+ "budget_waits": 0,
+ "slot_waits": 563,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83819563,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45265.223,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069991.558,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056976.805,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 252544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 132985160,
+ "cpu_ns": 49981054,
+ "parse_call_ns": 23442854,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2129.142526,
+ "output_byte_seconds": 1795.211172,
+ "parser_byte_seconds": 3074.346252,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 542,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 84089494,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45510.754,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5098662.604,
+ "latency_p99_upper_ns": 6291456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8056999.864,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5373952,
+ "elapsed_ns": 133433884,
+ "cpu_ns": 51462618,
+ "parse_call_ns": 23747967,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 540814.68462,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 3118.422109,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 596,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83315856,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 46811.327,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070925.9,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8058845.673,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1867776,
+ "elapsed_ns": 132186422,
+ "cpu_ns": 45811373,
+ "parse_call_ns": 22083462,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1983.12097,
+ "output_byte_seconds": 1182.647891,
+ "parser_byte_seconds": 2900.448352,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 532,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87421696,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42006.171,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068025.061,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8049545.414,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 39984,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132188663,
+ "cpu_ns": 45991210,
+ "parse_call_ns": 22145612,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1991.371251,
+ "output_byte_seconds": 1184.961172,
+ "parser_byte_seconds": 2909.800223,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 7080,
+ "budget_waits": 0,
+ "slot_waits": 543,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 87186189,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42139.616,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068490.238,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052428.242,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4436784,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7056,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5537792,
+ "elapsed_ns": 132746292,
+ "cpu_ns": 50870250,
+ "parse_call_ns": 22660664,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340246.674827,
+ "output_byte_seconds": 342.038296,
+ "parser_byte_seconds": 2973.982939,
+ "source_allocations": 893,
+ "output_allocations": 895,
+ "parser_allocations": 1,
+ "reuses": 4341,
+ "budget_waits": 0,
+ "slot_waits": 545,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83141858,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 45809.599,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5072116.599,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8054634.315,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 311264,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 132177385,
+ "cpu_ns": 44977578,
+ "parse_call_ns": 22128368,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2381.095196,
+ "output_byte_seconds": 919.555429,
+ "parser_byte_seconds": 2907.397974,
+ "source_allocations": 9,
+ "output_allocations": 64,
+ "parser_allocations": 1,
+ "reuses": 6056,
+ "budget_waits": 0,
+ "slot_waits": 539,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 88187889,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 41268.295,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067698.961,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8052209.973,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 318432,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 47152,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 1867776,
+ "elapsed_ns": 132225648,
+ "cpu_ns": 46118905,
+ "parse_call_ns": 22053057,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 1988.501642,
+ "output_byte_seconds": 1767.427593,
+ "parser_byte_seconds": 2896.491937,
+ "source_allocations": 9,
+ "output_allocations": 1025,
+ "parser_allocations": 1,
+ "reuses": 7143,
+ "budget_waits": 0,
+ "slot_waits": 536,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 87128865,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 42165.024,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068266.918,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8051060.116,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4373248,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6078464,
+ "elapsed_ns": 216945564,
+ "cpu_ns": 116157398,
+ "parse_call_ns": 25703347,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 3917.681175,
+ "output_byte_seconds": 512250.563648,
+ "parser_byte_seconds": 3150.964519,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 383,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 48939452,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 117402.264,
+ "latency_p99_upper_ns": 524288
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 6063368.282,
+ "latency_p99_upper_ns": 31457280
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 9260486.827,
+ "latency_p99_upper_ns": 33554432
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3178496,
+ "elapsed_ns": 133534289,
+ "cpu_ns": 66640259,
+ "parse_call_ns": 22303696,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2044.238204,
+ "output_byte_seconds": 269834.895225,
+ "parser_byte_seconds": 2930.529378,
+ "source_allocations": 82,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6047,
+ "budget_waits": 0,
+ "slot_waits": 500,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 67897726,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51484.234,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078396.125,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8065897.697,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133553215,
+ "cpu_ns": 68694192,
+ "parse_call_ns": 22344284,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541236.958782,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2932.875901,
+ "source_allocations": 76,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5029,
+ "budget_waits": 0,
+ "slot_waits": 479,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65966946,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52115.836,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078241.217,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8065472.756,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4504544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 134319516,
+ "cpu_ns": 74842901,
+ "parse_call_ns": 22151327,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2277.11069,
+ "output_byte_seconds": 440218.115158,
+ "parser_byte_seconds": 2909.330552,
+ "source_allocations": 9,
+ "output_allocations": 841,
+ "parser_allocations": 1,
+ "reuses": 7327,
+ "budget_waits": 0,
+ "slot_waits": 490,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60554269,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 57181.88,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5083619.048,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8071315.085,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 133454646,
+ "cpu_ns": 66234578,
+ "parse_call_ns": 22159339,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2031.818258,
+ "output_byte_seconds": 269861.554419,
+ "parser_byte_seconds": 2910.266617,
+ "source_allocations": 78,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6051,
+ "budget_waits": 0,
+ "slot_waits": 487,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 68332882,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51484.504,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5077341.499,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066441.419,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2001776,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 134096312,
+ "cpu_ns": 74886880,
+ "parse_call_ns": 22733900,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 341111.908821,
+ "output_byte_seconds": 100293.13752,
+ "parser_byte_seconds": 2983.138393,
+ "source_allocations": 921,
+ "output_allocations": 779,
+ "parser_allocations": 1,
+ "reuses": 4429,
+ "budget_waits": 0,
+ "slot_waits": 471,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60362834,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 54080.027,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5083405.479,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068401.165,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133447386,
+ "cpu_ns": 68765370,
+ "parse_call_ns": 22353361,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541359.828153,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2934.692831,
+ "source_allocations": 77,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5028,
+ "budget_waits": 0,
+ "slot_waits": 487,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65809490,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52372.427,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078845.858,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067374.837,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2034592,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 134204038,
+ "cpu_ns": 74836392,
+ "parse_call_ns": 22853483,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 341117.919471,
+ "output_byte_seconds": 100364.674661,
+ "parser_byte_seconds": 2998.098529,
+ "source_allocations": 881,
+ "output_allocations": 767,
+ "parser_allocations": 1,
+ "reuses": 4481,
+ "budget_waits": 0,
+ "slot_waits": 478,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60375968,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 54356.541,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5083649.875,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070735.206,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3244032,
+ "elapsed_ns": 133593447,
+ "cpu_ns": 66172548,
+ "parse_call_ns": 22181499,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2031.917671,
+ "output_byte_seconds": 269851.910584,
+ "parser_byte_seconds": 2913.380586,
+ "source_allocations": 80,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6049,
+ "budget_waits": 0,
+ "slot_waits": 471,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 68489180,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51688.946,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5077231.39,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066199.086,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4504544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 134436483,
+ "cpu_ns": 75053693,
+ "parse_call_ns": 22215239,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2284.410516,
+ "output_byte_seconds": 440251.541897,
+ "parser_byte_seconds": 2917.091676,
+ "source_allocations": 9,
+ "output_allocations": 832,
+ "parser_allocations": 1,
+ "reuses": 7336,
+ "budget_waits": 0,
+ "slot_waits": 483,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60480780,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 57382.812,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5083530.123,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8072471.683,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 134034428,
+ "cpu_ns": 69077852,
+ "parse_call_ns": 22386881,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2071.219143,
+ "output_byte_seconds": 269907.925264,
+ "parser_byte_seconds": 2941.415878,
+ "source_allocations": 82,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6047,
+ "budget_waits": 0,
+ "slot_waits": 521,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 66160244,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52463.206,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5079970.677,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068543.087,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133602318,
+ "cpu_ns": 69361342,
+ "parse_call_ns": 22347294,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541336.354919,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2933.602437,
+ "source_allocations": 76,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5029,
+ "budget_waits": 0,
+ "slot_waits": 500,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65433839,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52034.221,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5079700.568,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067086.654,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133878082,
+ "cpu_ns": 69431646,
+ "parse_call_ns": 22393309,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541341.633608,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2938.771712,
+ "source_allocations": 78,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5027,
+ "budget_waits": 0,
+ "slot_waits": 504,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65629618,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52136.236,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078986.712,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067041.718,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4373248,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5816320,
+ "elapsed_ns": 134331933,
+ "cpu_ns": 75355273,
+ "parse_call_ns": 22600489,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2317.391148,
+ "output_byte_seconds": 440282.284319,
+ "parser_byte_seconds": 2923.56271,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 497,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60100461,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 58242.85,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5084649.973,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8073924.058,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2001776,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 134074359,
+ "cpu_ns": 74679639,
+ "parse_call_ns": 22736073,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 341236.488763,
+ "output_byte_seconds": 100267.211633,
+ "parser_byte_seconds": 2982.994817,
+ "source_allocations": 917,
+ "output_allocations": 794,
+ "parser_allocations": 1,
+ "reuses": 4418,
+ "budget_waits": 0,
+ "slot_waits": 471,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60515136,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 53738.105,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5085195.058,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069412.397,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4504544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5275648,
+ "elapsed_ns": 136064340,
+ "cpu_ns": 79416596,
+ "parse_call_ns": 22572078,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2363.378088,
+ "output_byte_seconds": 440586.829499,
+ "parser_byte_seconds": 2964.218039,
+ "source_allocations": 9,
+ "output_allocations": 623,
+ "parser_allocations": 1,
+ "reuses": 7545,
+ "budget_waits": 0,
+ "slot_waits": 463,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 57551670,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 60112.085,
+ "latency_p99_upper_ns": 114688
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5087074.439,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8080314.649,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3244032,
+ "elapsed_ns": 133655494,
+ "cpu_ns": 66354625,
+ "parse_call_ns": 22289900,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2049.709126,
+ "output_byte_seconds": 269797.797722,
+ "parser_byte_seconds": 2927.700988,
+ "source_allocations": 78,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6051,
+ "budget_waits": 0,
+ "slot_waits": 500,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 68212138,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51495.073,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078118.015,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8064823.351,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3293184,
+ "elapsed_ns": 133683827,
+ "cpu_ns": 66973903,
+ "parse_call_ns": 22176603,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2039.054037,
+ "output_byte_seconds": 269818.155226,
+ "parser_byte_seconds": 2912.084727,
+ "source_allocations": 78,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6051,
+ "budget_waits": 0,
+ "slot_waits": 494,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 67816366,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51459.966,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5079235.137,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8065334.704,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133681327,
+ "cpu_ns": 68797289,
+ "parse_call_ns": 22338685,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541289.267391,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2932.086428,
+ "source_allocations": 77,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5028,
+ "budget_waits": 0,
+ "slot_waits": 482,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65978872,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52563.022,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078578.492,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066255.165,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133814643,
+ "cpu_ns": 68888479,
+ "parse_call_ns": 22335355,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541341.207084,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2930.637289,
+ "source_allocations": 79,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5026,
+ "budget_waits": 0,
+ "slot_waits": 510,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 66149871,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51550.405,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5079607.126,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067127.786,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4373248,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5816320,
+ "elapsed_ns": 134471775,
+ "cpu_ns": 75393460,
+ "parse_call_ns": 22629325,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2321.181236,
+ "output_byte_seconds": 440258.792854,
+ "parser_byte_seconds": 2921.16977,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 508,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60227676,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 57516.822,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5084982.783,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8073926.553,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 133441147,
+ "cpu_ns": 66434679,
+ "parse_call_ns": 22119254,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2030.079604,
+ "output_byte_seconds": 269825.85573,
+ "parser_byte_seconds": 2905.779822,
+ "source_allocations": 80,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6049,
+ "budget_waits": 0,
+ "slot_waits": 482,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 68150063,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51190.857,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5077733.031,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8065349.133,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4373248,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5816320,
+ "elapsed_ns": 134289332,
+ "cpu_ns": 76002725,
+ "parse_call_ns": 22740343,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2334.193158,
+ "output_byte_seconds": 440332.993703,
+ "parser_byte_seconds": 2936.962125,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 504,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 59412631,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 59077.132,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5084960.638,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8075279.097,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3309568,
+ "elapsed_ns": 133495777,
+ "cpu_ns": 66421587,
+ "parse_call_ns": 22309367,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2045.123956,
+ "output_byte_seconds": 269842.975673,
+ "parser_byte_seconds": 2931.949276,
+ "source_allocations": 76,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6053,
+ "budget_waits": 0,
+ "slot_waits": 497,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 68249668,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51216.396,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078028.333,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066089.677,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 134337593,
+ "cpu_ns": 71105404,
+ "parse_call_ns": 22575073,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541448.462493,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2962.344728,
+ "source_allocations": 83,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5022,
+ "budget_waits": 0,
+ "slot_waits": 495,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 64431294,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 53339.614,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5080292.879,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068765.424,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4504544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 134254523,
+ "cpu_ns": 76196602,
+ "parse_call_ns": 22285338,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2295.795833,
+ "output_byte_seconds": 440394.753415,
+ "parser_byte_seconds": 2927.722098,
+ "source_allocations": 9,
+ "output_allocations": 820,
+ "parser_allocations": 1,
+ "reuses": 7348,
+ "budget_waits": 0,
+ "slot_waits": 485,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 59133245,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 58635.959,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5084371.237,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8075247.27,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2034592,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 134306041,
+ "cpu_ns": 75274107,
+ "parse_call_ns": 22714288,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 341191.973388,
+ "output_byte_seconds": 100297.728905,
+ "parser_byte_seconds": 2980.354846,
+ "source_allocations": 917,
+ "output_allocations": 749,
+ "parser_allocations": 1,
+ "reuses": 4463,
+ "budget_waits": 0,
+ "slot_waits": 478,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 60108647,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 54208.683,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5084673.227,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069796.873,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133817208,
+ "cpu_ns": 69542587,
+ "parse_call_ns": 22437830,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541408.186663,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2945.936502,
+ "source_allocations": 80,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5025,
+ "budget_waits": 0,
+ "slot_waits": 483,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65488224,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52016.168,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5080750.668,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068031.861,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4373248,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5799936,
+ "elapsed_ns": 134597856,
+ "cpu_ns": 77396908,
+ "parse_call_ns": 22833216,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2355.524795,
+ "output_byte_seconds": 440416.150759,
+ "parser_byte_seconds": 2941.859195,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 512,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 58493375,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 59008.762,
+ "latency_p99_upper_ns": 98304
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5086107.088,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8076875.839,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4504544,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 4233264,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 139508137,
+ "cpu_ns": 88332555,
+ "parse_call_ns": 22864596,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 100663296,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2528.253394,
+ "output_byte_seconds": 442384.852596,
+ "parser_byte_seconds": 3002.901193,
+ "source_allocations": 9,
+ "output_allocations": 688,
+ "parser_allocations": 1,
+ "reuses": 7480,
+ "budget_waits": 0,
+ "slot_waits": 372,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51495885,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 66698.854,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5129096.339,
+ "latency_p99_upper_ns": 6815744
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8093643.623,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4833280,
+ "elapsed_ns": 134457305,
+ "cpu_ns": 70251788,
+ "parse_call_ns": 22431999,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541395.863387,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2942.397573,
+ "source_allocations": 87,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5018,
+ "budget_waits": 0,
+ "slot_waits": 495,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 65292089,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 53169.212,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5080238.856,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068047.314,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3211264,
+ "elapsed_ns": 133756102,
+ "cpu_ns": 67373341,
+ "parse_call_ns": 22155214,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2045.927873,
+ "output_byte_seconds": 269868.863264,
+ "parser_byte_seconds": 2910.706656,
+ "source_allocations": 81,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6048,
+ "budget_waits": 0,
+ "slot_waits": 506,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 67548515,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 51135.428,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078670.025,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066898.388,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2371504,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3571712,
+ "elapsed_ns": 135030934,
+ "cpu_ns": 71236281,
+ "parse_call_ns": 22446961,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2100.123381,
+ "output_byte_seconds": 269953.875704,
+ "parser_byte_seconds": 2948.934561,
+ "source_allocations": 94,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 6035,
+ "budget_waits": 0,
+ "slot_waits": 507,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 2048,
+ "sleep_ns": 65033726,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 53626.014,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5087279.412,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070672.959,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 1936144,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 135831514,
+ "cpu_ns": 84355786,
+ "parse_call_ns": 23107923,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 341580.411374,
+ "output_byte_seconds": 100419.005421,
+ "parser_byte_seconds": 3032.899482,
+ "source_allocations": 853,
+ "output_allocations": 676,
+ "parser_allocations": 1,
+ "reuses": 4600,
+ "budget_waits": 0,
+ "slot_waits": 455,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52913091,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 60319.001,
+ "latency_p99_upper_ns": 114688
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5091148.147,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8079928.47,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133667291,
+ "cpu_ns": 68534602,
+ "parse_call_ns": 22264001,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541292.227145,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2921.518156,
+ "source_allocations": 77,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5028,
+ "budget_waits": 0,
+ "slot_waits": 481,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 66216721,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 1,
+ "latency_mean_ns": 52072.538,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 5078370.622,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066280.939,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378784,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3899392,
+ "elapsed_ns": 133407209,
+ "cpu_ns": 54623208,
+ "parse_call_ns": 22433685,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2079.608844,
+ "output_byte_seconds": 270519.575773,
+ "parser_byte_seconds": 2946.904954,
+ "source_allocations": 118,
+ "output_allocations": 838,
+ "parser_allocations": 1,
+ "reuses": 7221,
+ "budget_waits": 0,
+ "slot_waits": 547,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 79664236,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 47700.066,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070062.768,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069584.641,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3751936,
+ "elapsed_ns": 133312135,
+ "cpu_ns": 53364925,
+ "parse_call_ns": 22316231,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2049.372724,
+ "output_byte_seconds": 270524.406644,
+ "parser_byte_seconds": 2928.92106,
+ "source_allocations": 137,
+ "output_allocations": 841,
+ "parser_allocations": 1,
+ "reuses": 6175,
+ "budget_waits": 0,
+ "slot_waits": 552,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 80930688,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46742.189,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068879.809,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069119.599,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3948544,
+ "elapsed_ns": 154001095,
+ "cpu_ns": 65368726,
+ "parse_call_ns": 23437273,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2683.230182,
+ "output_byte_seconds": 276097.966097,
+ "parser_byte_seconds": 3083.783614,
+ "source_allocations": 228,
+ "output_allocations": 746,
+ "parser_allocations": 1,
+ "reuses": 6179,
+ "budget_waits": 0,
+ "slot_waits": 542,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 75659422,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 64443.196,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5134851.331,
+ "latency_p99_upper_ns": 7340032
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8252758.487,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2312896,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 133648283,
+ "cpu_ns": 61986524,
+ "parse_call_ns": 25370210,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2299.022458,
+ "output_byte_seconds": 270612.233717,
+ "parser_byte_seconds": 2983.123314,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 653,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 72630111,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 53967.42,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080263.648,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8075763.615,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2067408,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 133472857,
+ "cpu_ns": 62602975,
+ "parse_call_ns": 23134595,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340709.17918,
+ "output_byte_seconds": 100724.838498,
+ "parser_byte_seconds": 3036.377571,
+ "source_allocations": 923,
+ "output_allocations": 841,
+ "parser_allocations": 1,
+ "reuses": 4365,
+ "budget_waits": 0,
+ "slot_waits": 526,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 71679132,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 48473.289,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5073065.738,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070772.518,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4443056,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4751360,
+ "elapsed_ns": 133297584,
+ "cpu_ns": 55094453,
+ "parse_call_ns": 22718797,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541537.659914,
+ "output_byte_seconds": 577.166247,
+ "parser_byte_seconds": 2982.289653,
+ "source_allocations": 130,
+ "output_allocations": 809,
+ "parser_allocations": 1,
+ "reuses": 5190,
+ "budget_waits": 0,
+ "slot_waits": 541,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 79050000,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 48100.386,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069482.618,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070037.129,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133477288,
+ "cpu_ns": 54372368,
+ "parse_call_ns": 22466675,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541562.393801,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2949.789857,
+ "source_allocations": 80,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5025,
+ "budget_waits": 0,
+ "slot_waits": 554,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 80055686,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46918.51,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069158.581,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070277.888,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3932160,
+ "elapsed_ns": 133312509,
+ "cpu_ns": 53734268,
+ "parse_call_ns": 22533891,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2071.170012,
+ "output_byte_seconds": 270512.249274,
+ "parser_byte_seconds": 2959.58098,
+ "source_allocations": 159,
+ "output_allocations": 828,
+ "parser_allocations": 1,
+ "reuses": 6166,
+ "budget_waits": 0,
+ "slot_waits": 575,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 80473327,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46789.037,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070040.373,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069081.323,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2312896,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 134281084,
+ "cpu_ns": 62190824,
+ "parse_call_ns": 25213500,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2300.277794,
+ "output_byte_seconds": 270647.838041,
+ "parser_byte_seconds": 2975.251132,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 663,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 73016473,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 54287.927,
+ "latency_p99_upper_ns": 98304
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080276.456,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8077074.059,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378784,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3948544,
+ "elapsed_ns": 133395362,
+ "cpu_ns": 55263103,
+ "parse_call_ns": 22335683,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2070.323199,
+ "output_byte_seconds": 270570.958879,
+ "parser_byte_seconds": 2935.679247,
+ "source_allocations": 123,
+ "output_allocations": 825,
+ "parser_allocations": 1,
+ "reuses": 7229,
+ "budget_waits": 0,
+ "slot_waits": 563,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 79157676,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 47428.456,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070071.895,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070912.004,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3522560,
+ "elapsed_ns": 133405307,
+ "cpu_ns": 53873137,
+ "parse_call_ns": 22349414,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2061.271642,
+ "output_byte_seconds": 270527.998952,
+ "parser_byte_seconds": 2936.171471,
+ "source_allocations": 144,
+ "output_allocations": 811,
+ "parser_allocations": 1,
+ "reuses": 6198,
+ "budget_waits": 0,
+ "slot_waits": 551,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 80515381,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46564.507,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069570.9,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069438.264,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 133295478,
+ "cpu_ns": 60929076,
+ "parse_call_ns": 22892803,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340588.424197,
+ "output_byte_seconds": 100730.999866,
+ "parser_byte_seconds": 3007.852808,
+ "source_allocations": 919,
+ "output_allocations": 842,
+ "parser_allocations": 1,
+ "reuses": 4368,
+ "budget_waits": 0,
+ "slot_waits": 524,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 73271182,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 48259.733,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5071843.127,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069717.131,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5390336,
+ "elapsed_ns": 133317978,
+ "cpu_ns": 54530428,
+ "parse_call_ns": 22789187,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541551.170985,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2991.654899,
+ "source_allocations": 72,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5033,
+ "budget_waits": 0,
+ "slot_waits": 541,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 79523636,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 47420.19,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5069779.505,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070214.071,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4443056,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5357568,
+ "elapsed_ns": 133341496,
+ "cpu_ns": 54857945,
+ "parse_call_ns": 22618201,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541518.37496,
+ "output_byte_seconds": 577.265132,
+ "parser_byte_seconds": 2971.205031,
+ "source_allocations": 122,
+ "output_allocations": 835,
+ "parser_allocations": 1,
+ "reuses": 5172,
+ "budget_waits": 0,
+ "slot_waits": 562,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 79396532,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 47550.497,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070242.543,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069675.14,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4443056,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 134650847,
+ "cpu_ns": 58145169,
+ "parse_call_ns": 22801055,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 542663.104532,
+ "output_byte_seconds": 578.298773,
+ "parser_byte_seconds": 2995.063232,
+ "source_allocations": 127,
+ "output_allocations": 804,
+ "parser_allocations": 1,
+ "reuses": 5198,
+ "budget_waits": 0,
+ "slot_waits": 553,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 77457652,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 49310.575,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080294.837,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8086977.866,
+ "latency_p99_upper_ns": 9437184
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378784,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3964928,
+ "elapsed_ns": 133179940,
+ "cpu_ns": 52486508,
+ "parse_call_ns": 22146823,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2028.917653,
+ "output_byte_seconds": 270508.558846,
+ "parser_byte_seconds": 2910.035715,
+ "source_allocations": 119,
+ "output_allocations": 875,
+ "parser_allocations": 1,
+ "reuses": 7183,
+ "budget_waits": 0,
+ "slot_waits": 532,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 81744820,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46179.91,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068139.702,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068218.996,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133254368,
+ "cpu_ns": 52756869,
+ "parse_call_ns": 22242096,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541465.495701,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2919.456949,
+ "source_allocations": 79,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5026,
+ "budget_waits": 0,
+ "slot_waits": 537,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 81620293,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45804.026,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067325.337,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068611.8,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 133273853,
+ "cpu_ns": 59503628,
+ "parse_call_ns": 22579568,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340521.103381,
+ "output_byte_seconds": 100725.988305,
+ "parser_byte_seconds": 2964.439632,
+ "source_allocations": 921,
+ "output_allocations": 839,
+ "parser_allocations": 1,
+ "reuses": 4369,
+ "budget_waits": 0,
+ "slot_waits": 529,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 75001351,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46820.147,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5071087.53,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068767.35,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3293184,
+ "elapsed_ns": 133216315,
+ "cpu_ns": 51631438,
+ "parse_call_ns": 22079426,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2014.496107,
+ "output_byte_seconds": 270449.091989,
+ "parser_byte_seconds": 2901.711431,
+ "source_allocations": 152,
+ "output_allocations": 827,
+ "parser_allocations": 1,
+ "reuses": 6174,
+ "budget_waits": 0,
+ "slot_waits": 543,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 82698735,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45041.785,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068002.393,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8066161.602,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2312896,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3178496,
+ "elapsed_ns": 133362779,
+ "cpu_ns": 58084129,
+ "parse_call_ns": 24178012,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2196.167723,
+ "output_byte_seconds": 270535.919777,
+ "parser_byte_seconds": 2934.024512,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 605,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 76526627,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 50758.917,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5074265.021,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8071772.438,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3751936,
+ "elapsed_ns": 133094723,
+ "cpu_ns": 52669444,
+ "parse_call_ns": 22153975,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2026.350691,
+ "output_byte_seconds": 270487.081841,
+ "parser_byte_seconds": 2910.446252,
+ "source_allocations": 162,
+ "output_allocations": 813,
+ "parser_allocations": 1,
+ "reuses": 6178,
+ "budget_waits": 0,
+ "slot_waits": 529,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 81515465,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46192.459,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067955.414,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067608.796,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6340608,
+ "elapsed_ns": 133282278,
+ "cpu_ns": 59568109,
+ "parse_call_ns": 22558632,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340502.324772,
+ "output_byte_seconds": 100714.490169,
+ "parser_byte_seconds": 2961.00573,
+ "source_allocations": 923,
+ "output_allocations": 826,
+ "parser_allocations": 1,
+ "reuses": 4380,
+ "budget_waits": 0,
+ "slot_waits": 521,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 74934523,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46941.425,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5070856.899,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068200.595,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2312896,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3194880,
+ "elapsed_ns": 133540522,
+ "cpu_ns": 58472614,
+ "parse_call_ns": 24345793,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2208.417867,
+ "output_byte_seconds": 270579.890216,
+ "parser_byte_seconds": 2933.62499,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 602,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 76325826,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 51364.197,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5074603.185,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8073207.582,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133275839,
+ "cpu_ns": 52234245,
+ "parse_call_ns": 22266351,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541367.893955,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2922.935825,
+ "source_allocations": 79,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5026,
+ "budget_waits": 0,
+ "slot_waits": 545,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 82113024,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45842.847,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5066801.978,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067096.868,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3899392,
+ "elapsed_ns": 133064931,
+ "cpu_ns": 52117164,
+ "parse_call_ns": 22057182,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2015.469116,
+ "output_byte_seconds": 270480.700872,
+ "parser_byte_seconds": 2897.68644,
+ "source_allocations": 130,
+ "output_allocations": 842,
+ "parser_allocations": 1,
+ "reuses": 6181,
+ "budget_waits": 0,
+ "slot_waits": 555,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 82111301,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45400.789,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068255.587,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067189.304,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4443056,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5292032,
+ "elapsed_ns": 133337450,
+ "cpu_ns": 53670610,
+ "parse_call_ns": 22263776,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541459.255198,
+ "output_byte_seconds": 577.165832,
+ "parser_byte_seconds": 2922.14622,
+ "source_allocations": 137,
+ "output_allocations": 796,
+ "parser_allocations": 1,
+ "reuses": 5196,
+ "budget_waits": 0,
+ "slot_waits": 551,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 80837357,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46321.397,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068514.702,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8068639.91,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3522560,
+ "elapsed_ns": 134333542,
+ "cpu_ns": 52726291,
+ "parse_call_ns": 22219255,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2039.714059,
+ "output_byte_seconds": 270798.061653,
+ "parser_byte_seconds": 2918.877137,
+ "source_allocations": 140,
+ "output_allocations": 894,
+ "parser_allocations": 1,
+ "reuses": 6119,
+ "budget_waits": 0,
+ "slot_waits": 516,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 82638596,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46056.021,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5218345.888,
+ "latency_p99_upper_ns": 9437184
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8076530.434,
+ "latency_p99_upper_ns": 9437184
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378784,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3948544,
+ "elapsed_ns": 133174357,
+ "cpu_ns": 52057974,
+ "parse_call_ns": 22117835,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2021.284206,
+ "output_byte_seconds": 270501.113842,
+ "parser_byte_seconds": 2905.858494,
+ "source_allocations": 114,
+ "output_allocations": 849,
+ "parser_allocations": 1,
+ "reuses": 7214,
+ "budget_waits": 0,
+ "slot_waits": 548,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 82257586,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45428.889,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068142.38,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067808.96,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2312896,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3178496,
+ "elapsed_ns": 133410638,
+ "cpu_ns": 57999768,
+ "parse_call_ns": 24134627,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2191.645151,
+ "output_byte_seconds": 270510.58659,
+ "parser_byte_seconds": 2926.663567,
+ "source_allocations": 4082,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 603,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 76638749,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 51016.097,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5074074.877,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8071032.382,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3342336,
+ "elapsed_ns": 133213102,
+ "cpu_ns": 52362717,
+ "parse_call_ns": 22103023,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2022.420003,
+ "output_byte_seconds": 270482.639278,
+ "parser_byte_seconds": 2904.168619,
+ "source_allocations": 127,
+ "output_allocations": 855,
+ "parser_allocations": 1,
+ "reuses": 6171,
+ "budget_waits": 0,
+ "slot_waits": 539,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 81964913,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46044.098,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5068262.707,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067371.07,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378784,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107504,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3751936,
+ "elapsed_ns": 133177547,
+ "cpu_ns": 52033688,
+ "parse_call_ns": 22154380,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33669120,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2025.354638,
+ "output_byte_seconds": 270478.813202,
+ "parser_byte_seconds": 2910.934805,
+ "source_allocations": 129,
+ "output_allocations": 851,
+ "parser_allocations": 1,
+ "reuses": 7197,
+ "budget_waits": 0,
+ "slot_waits": 527,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 82109654,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 45825.604,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067937.156,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067321.024,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4435888,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 4767744,
+ "elapsed_ns": 133311566,
+ "cpu_ns": 53725285,
+ "parse_call_ns": 22239925,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541575.408384,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 2920.340305,
+ "source_allocations": 80,
+ "output_allocations": 0,
+ "parser_allocations": 1,
+ "reuses": 5025,
+ "budget_waits": 0,
+ "slot_waits": 555,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 80727666,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46306.509,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067147.548,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8070390.562,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4443056,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 5439488,
+ "elapsed_ns": 134101658,
+ "cpu_ns": 54158047,
+ "parse_call_ns": 22315394,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 541512.874989,
+ "output_byte_seconds": 578.716358,
+ "parser_byte_seconds": 2931.279646,
+ "source_allocations": 161,
+ "output_allocations": 826,
+ "parser_allocations": 1,
+ "reuses": 5142,
+ "budget_waits": 0,
+ "slot_waits": 533,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 81103821,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46533.691,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082538.041,
+ "latency_p99_upper_ns": 6291456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8069591.938,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2378672,
+ "source_peak_bytes": 98400,
+ "output_peak_bytes": 2107392,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 3948544,
+ "elapsed_ns": 133134639,
+ "cpu_ns": 52075173,
+ "parse_call_ns": 22128273,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33611776,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 2026.862393,
+ "output_byte_seconds": 270471.476005,
+ "parser_byte_seconds": 2908.200691,
+ "source_allocations": 122,
+ "output_allocations": 816,
+ "parser_allocations": 1,
+ "reuses": 6215,
+ "budget_waits": 0,
+ "slot_waits": 512,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 82080012,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 46182.627,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5067504.389,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067072.688,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 8388608,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 4730672,
+ "source_peak_bytes": 4230192,
+ "output_peak_bytes": 2100224,
+ "parser_peak_bytes": 131120,
+ "rss_peak_bytes": 6406144,
+ "elapsed_ns": 133118662,
+ "cpu_ns": 59607669,
+ "parse_call_ns": 22648269,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 42083156,
+ "selection_copy_bytes": 33554432,
+ "reader_copy_bytes": 75711296,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 340524.867797,
+ "output_byte_seconds": 100684.088672,
+ "parser_byte_seconds": 2973.798584,
+ "source_allocations": 921,
+ "output_allocations": 855,
+ "parser_allocations": 1,
+ "reuses": 4353,
+ "budget_waits": 0,
+ "slot_waits": 532,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 74562185,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 1,
+ "latency_mean_ns": 47236.674,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5071269.907,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 33554432,
+ "peak_count": 64,
+ "latency_mean_ns": 8067723.707,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1104848,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134798098,
+ "cpu_ns": 52545277,
+ "parse_call_ns": 26282225,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6883.203763,
+ "output_byte_seconds": 1809.304759,
+ "parser_byte_seconds": 10115.296993,
+ "source_allocations": 367,
+ "output_allocations": 948,
+ "parser_allocations": 374,
+ "reuses": 6256,
+ "budget_waits": 0,
+ "slot_waits": 579,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83482902,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47583.467,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081460.678,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8083520.998,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 11312,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 2031616,
+ "elapsed_ns": 134514858,
+ "cpu_ns": 50924568,
+ "parse_call_ns": 26180831,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 1059072,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7475.627393,
+ "output_byte_seconds": 924.635553,
+ "parser_byte_seconds": 10091.334952,
+ "source_allocations": 237,
+ "output_allocations": 96,
+ "parser_allocations": 257,
+ "reuses": 5800,
+ "budget_waits": 0,
+ "slot_waits": 593,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 84806597,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 46212.018,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080764.964,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8080296.584,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 842368,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1949696,
+ "elapsed_ns": 135580728,
+ "cpu_ns": 59055276,
+ "parse_call_ns": 27303180,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 8268.860241,
+ "output_byte_seconds": 1866.643736,
+ "parser_byte_seconds": 10141.702783,
+ "source_allocations": 3849,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 540,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 77683199,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 53763.312,
+ "latency_p99_upper_ns": 163840
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5090947.59,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8093934.847,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134733970,
+ "cpu_ns": 52189389,
+ "parse_call_ns": 26273407,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6865.482399,
+ "output_byte_seconds": 1226.436074,
+ "parser_byte_seconds": 10135.432887,
+ "source_allocations": 365,
+ "output_allocations": 246,
+ "parser_allocations": 368,
+ "reuses": 5942,
+ "budget_waits": 0,
+ "slot_waits": 587,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83766349,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47383.279,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081532.837,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082383.547,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134703694,
+ "cpu_ns": 51981424,
+ "parse_call_ns": 26239241,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6818.11346,
+ "output_byte_seconds": 1220.93584,
+ "parser_byte_seconds": 10109.238408,
+ "source_allocations": 368,
+ "output_allocations": 240,
+ "parser_allocations": 366,
+ "reuses": 5947,
+ "budget_waits": 0,
+ "slot_waits": 592,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83962412,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47186.16,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082027.365,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082717.212,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2096880,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 3360,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3702784,
+ "elapsed_ns": 330325402,
+ "cpu_ns": 56526552,
+ "parse_call_ns": 257818693,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 542057.64214,
+ "output_byte_seconds": 342.456081,
+ "parser_byte_seconds": 10454.037412,
+ "source_allocations": 1653,
+ "output_allocations": 1018,
+ "parser_allocations": 587,
+ "reuses": 2639,
+ "budget_waits": 1256,
+ "slot_waits": 0,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 275134226,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 313916.181,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5359649.404,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 49,
+ "latency_mean_ns": 8345801.06,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097024,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3702784,
+ "elapsed_ns": 517444947,
+ "cpu_ns": 58385263,
+ "parse_call_ns": 414175159,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 866552.611778,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 10646.478365,
+ "source_allocations": 1612,
+ "output_allocations": 0,
+ "parser_allocations": 580,
+ "reuses": 2681,
+ "budget_waits": 1250,
+ "slot_waits": 0,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 460552293,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 496739.613,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5531099.266,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 8547759.071,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 842368,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1916928,
+ "elapsed_ns": 135818181,
+ "cpu_ns": 60130654,
+ "parse_call_ns": 27699522,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 8398.686166,
+ "output_byte_seconds": 1885.555543,
+ "parser_byte_seconds": 10206.603011,
+ "source_allocations": 3849,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 537,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 76838088,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 54782.86,
+ "latency_p99_upper_ns": 180224
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5093567.929,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8096201.349,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 11312,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 2064384,
+ "elapsed_ns": 134627181,
+ "cpu_ns": 51051158,
+ "parse_call_ns": 26242598,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 1059072,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7499.787736,
+ "output_byte_seconds": 924.734083,
+ "parser_byte_seconds": 10090.493068,
+ "source_allocations": 237,
+ "output_allocations": 100,
+ "parser_allocations": 258,
+ "reuses": 5795,
+ "budget_waits": 0,
+ "slot_waits": 587,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 84733901,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 46365.068,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080938.783,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8081319.231,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 134660107,
+ "cpu_ns": 51849496,
+ "parse_call_ns": 26235438,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6785.330268,
+ "output_byte_seconds": 1222.453816,
+ "parser_byte_seconds": 10103.005533,
+ "source_allocations": 366,
+ "output_allocations": 239,
+ "parser_allocations": 366,
+ "reuses": 5950,
+ "budget_waits": 0,
+ "slot_waits": 579,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 84013028,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47133.761,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081549.099,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082113.784,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097024,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 516876187,
+ "cpu_ns": 58189132,
+ "parse_call_ns": 413488109,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 866155.703795,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 10618.392921,
+ "source_allocations": 1617,
+ "output_allocations": 0,
+ "parser_allocations": 581,
+ "reuses": 2675,
+ "budget_waits": 1263,
+ "slot_waits": 0,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 460124695,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 496219.126,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5528237.536,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 8541844.312,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1867776,
+ "elapsed_ns": 134596389,
+ "cpu_ns": 51879163,
+ "parse_call_ns": 26207832,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6795.293198,
+ "output_byte_seconds": 1224.224319,
+ "parser_byte_seconds": 10089.609534,
+ "source_allocations": 369,
+ "output_allocations": 233,
+ "parser_allocations": 365,
+ "reuses": 5954,
+ "budget_waits": 0,
+ "slot_waits": 596,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83947198,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47146.396,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082305.345,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082431.98,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1104848,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134667407,
+ "cpu_ns": 52286009,
+ "parse_call_ns": 26255995,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6830.10163,
+ "output_byte_seconds": 1802.54536,
+ "parser_byte_seconds": 10104.51946,
+ "source_allocations": 370,
+ "output_allocations": 952,
+ "parser_allocations": 375,
+ "reuses": 6248,
+ "budget_waits": 0,
+ "slot_waits": 590,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83595691,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47383.187,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081689.522,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082200.92,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097104,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 3360,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3833856,
+ "elapsed_ns": 330507221,
+ "cpu_ns": 57227425,
+ "parse_call_ns": 258042238,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 542403.396989,
+ "output_byte_seconds": 342.198165,
+ "parser_byte_seconds": 10516.149038,
+ "source_allocations": 1657,
+ "output_allocations": 1018,
+ "parser_allocations": 592,
+ "reuses": 2630,
+ "budget_waits": 1262,
+ "slot_waits": 0,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 274671771,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 314160.033,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5361935.781,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 49,
+ "latency_mean_ns": 8345834.982,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 134805557,
+ "cpu_ns": 52099602,
+ "parse_call_ns": 26201196,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6802.764732,
+ "output_byte_seconds": 1222.5673,
+ "parser_byte_seconds": 10082.699192,
+ "source_allocations": 363,
+ "output_allocations": 241,
+ "parser_allocations": 368,
+ "reuses": 5949,
+ "budget_waits": 0,
+ "slot_waits": 592,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83969655,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47229.56,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5083369.83,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082868.22,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1104736,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 135397301,
+ "cpu_ns": 55535720,
+ "parse_call_ns": 28191073,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7296.683374,
+ "output_byte_seconds": 1825.786254,
+ "parser_byte_seconds": 10851.770961,
+ "source_allocations": 364,
+ "output_allocations": 925,
+ "parser_allocations": 376,
+ "reuses": 6280,
+ "budget_waits": 0,
+ "slot_waits": 556,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 81078620,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 50441.328,
+ "latency_p99_upper_ns": 163840
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5086253.071,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8088040.091,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 11312,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 2048000,
+ "elapsed_ns": 135143135,
+ "cpu_ns": 54181725,
+ "parse_call_ns": 28073539,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 1059072,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7971.142415,
+ "output_byte_seconds": 924.89692,
+ "parser_byte_seconds": 10793.387694,
+ "source_allocations": 237,
+ "output_allocations": 89,
+ "parser_allocations": 259,
+ "reuses": 5805,
+ "budget_waits": 0,
+ "slot_waits": 587,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 82256234,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 49150.131,
+ "latency_p99_upper_ns": 163840
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5084346.661,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8083800.547,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097024,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 519737827,
+ "cpu_ns": 63401151,
+ "parse_call_ns": 410873515,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 869390.688093,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 10874.854354,
+ "source_allocations": 1612,
+ "output_allocations": 0,
+ "parser_allocations": 584,
+ "reuses": 2677,
+ "budget_waits": 1267,
+ "slot_waits": 0,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 457480540,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 498894.016,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5554388.391,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 8572436.932,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 842368,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1933312,
+ "elapsed_ns": 135808674,
+ "cpu_ns": 61310764,
+ "parse_call_ns": 27409732,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 8492.13471,
+ "output_byte_seconds": 1909.35548,
+ "parser_byte_seconds": 10184.015437,
+ "source_allocations": 3849,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 538,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 75774039,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 55750.675,
+ "latency_p99_upper_ns": 196608
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5097561.83,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8097147.871,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2096496,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 3360,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 330655613,
+ "cpu_ns": 57992572,
+ "parse_call_ns": 257126466,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 542286.835871,
+ "output_byte_seconds": 342.201335,
+ "parser_byte_seconds": 10592.82654,
+ "source_allocations": 1620,
+ "output_allocations": 1018,
+ "parser_allocations": 589,
+ "reuses": 2670,
+ "budget_waits": 1246,
+ "slot_waits": 0,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 274045502,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 314214.117,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5361784.028,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 49,
+ "latency_mean_ns": 8345733.162,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 134725602,
+ "cpu_ns": 52125932,
+ "parse_call_ns": 26256537,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6831.305534,
+ "output_byte_seconds": 1226.062002,
+ "parser_byte_seconds": 10092.239062,
+ "source_allocations": 365,
+ "output_allocations": 226,
+ "parser_allocations": 360,
+ "reuses": 5970,
+ "budget_waits": 0,
+ "slot_waits": 576,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83779201,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47423.973,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082508.901,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082650.268,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2096656,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 3360,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 332809762,
+ "cpu_ns": 64506702,
+ "parse_call_ns": 255295188,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 544031.993873,
+ "output_byte_seconds": 348.13532,
+ "parser_byte_seconds": 10927.535411,
+ "source_allocations": 1623,
+ "output_allocations": 1008,
+ "parser_allocations": 583,
+ "reuses": 2683,
+ "budget_waits": 1227,
+ "slot_waits": 0,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 270135277,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 316210.616,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5373501.093,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 49,
+ "latency_mean_ns": 8409239.137,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134646087,
+ "cpu_ns": 51969989,
+ "parse_call_ns": 26192074,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6812.54134,
+ "output_byte_seconds": 1229.637184,
+ "parser_byte_seconds": 10083.25152,
+ "source_allocations": 369,
+ "output_allocations": 241,
+ "parser_allocations": 365,
+ "reuses": 5946,
+ "budget_waits": 0,
+ "slot_waits": 582,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83864700,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47274.193,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082291.09,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8084035.099,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1104848,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1900544,
+ "elapsed_ns": 134732754,
+ "cpu_ns": 52218674,
+ "parse_call_ns": 26241260,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6810.984162,
+ "output_byte_seconds": 1804.529206,
+ "parser_byte_seconds": 10104.502269,
+ "source_allocations": 368,
+ "output_allocations": 949,
+ "parser_allocations": 374,
+ "reuses": 6254,
+ "budget_waits": 0,
+ "slot_waits": 584,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 83719457,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47404.955,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082343.96,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082308.803,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134687032,
+ "cpu_ns": 52085095,
+ "parse_call_ns": 26215409,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6852.502663,
+ "output_byte_seconds": 1223.987439,
+ "parser_byte_seconds": 10100.060122,
+ "source_allocations": 365,
+ "output_allocations": 235,
+ "parser_allocations": 364,
+ "reuses": 5957,
+ "budget_waits": 0,
+ "slot_waits": 585,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83840818,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47354.551,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081713.058,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082095.55,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097072,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 516415971,
+ "cpu_ns": 57490634,
+ "parse_call_ns": 412616864,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 865936.173669,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 10532.202462,
+ "source_allocations": 1624,
+ "output_allocations": 0,
+ "parser_allocations": 582,
+ "reuses": 2667,
+ "budget_waits": 1258,
+ "slot_waits": 0,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 460245677,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 495746.732,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5527499.187,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 8541909.699,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 842368,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1916928,
+ "elapsed_ns": 135708499,
+ "cpu_ns": 59498427,
+ "parse_call_ns": 27293452,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 8320.069469,
+ "output_byte_seconds": 1853.590142,
+ "parser_byte_seconds": 10172.640074,
+ "source_allocations": 3849,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 550,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 77469437,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 53679.489,
+ "latency_p99_upper_ns": 180224
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5093041.554,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8093789.758,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 11312,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 2048000,
+ "elapsed_ns": 134580129,
+ "cpu_ns": 50901202,
+ "parse_call_ns": 26138215,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 1059072,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7468.893211,
+ "output_byte_seconds": 924.833553,
+ "parser_byte_seconds": 10074.589742,
+ "source_allocations": 237,
+ "output_allocations": 99,
+ "parser_allocations": 260,
+ "reuses": 5794,
+ "budget_waits": 0,
+ "slot_waits": 603,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 84894241,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 46199.245,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5080295.214,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082153.254,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2095936,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 3360,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3768320,
+ "elapsed_ns": 330364653,
+ "cpu_ns": 56737666,
+ "parse_call_ns": 257390641,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 57344,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 542129.496495,
+ "output_byte_seconds": 342.3922,
+ "parser_byte_seconds": 10487.947668,
+ "source_allocations": 1626,
+ "output_allocations": 1018,
+ "parser_allocations": 584,
+ "reuses": 2669,
+ "budget_waits": 1234,
+ "slot_waits": 0,
+ "compacted": 1024,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 274961005,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 314000.227,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5359881.678,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 49,
+ "latency_mean_ns": 8345470.393,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134641407,
+ "cpu_ns": 51772899,
+ "parse_call_ns": 26303805,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6823.249522,
+ "output_byte_seconds": 1222.425123,
+ "parser_byte_seconds": 10156.044791,
+ "source_allocations": 363,
+ "output_allocations": 239,
+ "parser_allocations": 367,
+ "reuses": 5952,
+ "budget_waits": 0,
+ "slot_waits": 584,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83930889,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47208.702,
+ "latency_p99_upper_ns": 131072
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081715.549,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8082551.032,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 11312,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 2048000,
+ "elapsed_ns": 134636889,
+ "cpu_ns": 51692325,
+ "parse_call_ns": 26232175,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 1059072,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 7604.090343,
+ "output_byte_seconds": 924.831397,
+ "parser_byte_seconds": 10109.160375,
+ "source_allocations": 237,
+ "output_allocations": 97,
+ "parser_allocations": 259,
+ "reuses": 5797,
+ "budget_waits": 0,
+ "slot_waits": 600,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 84203974,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 46850.104,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5081772.482,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8081990.295,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 2097024,
+ "source_peak_bytes": 2047296,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 3719168,
+ "elapsed_ns": 516507633,
+ "cpu_ns": 56956626,
+ "parse_call_ns": 413462854,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 866066.604394,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 10498.181654,
+ "source_allocations": 1635,
+ "output_allocations": 0,
+ "parser_allocations": 588,
+ "reuses": 2650,
+ "budget_waits": 1258,
+ "slot_waits": 0,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 460890935,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 495819.875,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 5527650.658,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 30,
+ "latency_mean_ns": 8542682.03,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1097792,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 72752,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 134698503,
+ "cpu_ns": 52062419,
+ "parse_call_ns": 26232455,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26814720,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6807.634601,
+ "output_byte_seconds": 1226.698884,
+ "parser_byte_seconds": 10096.010075,
+ "source_allocations": 358,
+ "output_allocations": 229,
+ "parser_allocations": 363,
+ "reuses": 5971,
+ "budget_waits": 0,
+ "slot_waits": 573,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 1024,
+ "sleep_ns": 83820760,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 47338.287,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5082803.919,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8081430.476,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 842368,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1933312,
+ "elapsed_ns": 135617374,
+ "cpu_ns": 59370307,
+ "parse_call_ns": 27370335,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 8306.118105,
+ "output_byte_seconds": 1881.770411,
+ "parser_byte_seconds": 10193.350967,
+ "source_allocations": 3849,
+ "output_allocations": 3072,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 541,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 77447978,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 54118.737,
+ "latency_p99_upper_ns": 180224
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5093193.132,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8094306.969,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1104736,
+ "source_peak_bytes": 393312,
+ "output_peak_bytes": 79920,
+ "parser_peak_bytes": 524336,
+ "rss_peak_bytes": 1884160,
+ "elapsed_ns": 135101765,
+ "cpu_ns": 53612089,
+ "parse_call_ns": 26369173,
+ "accepted": 1024,
+ "emitted": 3072,
+ "input_bytes": 49877076,
+ "selection_copy_bytes": 26872064,
+ "reader_copy_bytes": 114814580,
+ "parser_realloc_copy_bytes": 0,
+ "source_byte_seconds": 6944.794448,
+ "output_byte_seconds": 1822.831558,
+ "parser_byte_seconds": 10130.150831,
+ "source_allocations": 348,
+ "output_allocations": 886,
+ "parser_allocations": 368,
+ "reuses": 6343,
+ "budget_waits": 0,
+ "slot_waits": 561,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 82695691,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 1024,
+ "bytes": 26757376,
+ "peak_count": 1,
+ "latency_mean_ns": 48573.396,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 5083912.79,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 1024,
+ "bytes": 57344,
+ "peak_count": 64,
+ "latency_mean_ns": 8083831.809,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 170672,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66381179,
+ "cpu_ns": 14937944,
+ "parse_call_ns": 10634360,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 191.835816,
+ "output_byte_seconds": 748.822762,
+ "parser_byte_seconds": 436.544508,
+ "source_allocations": 1273,
+ "output_allocations": 1536,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 200,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51858352,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26502.654,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055591.338,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038187.436,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1208192,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2785280,
+ "elapsed_ns": 66395496,
+ "cpu_ns": 14949295,
+ "parse_call_ns": 10748920,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 67632.156584,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 441.340054,
+ "source_allocations": 70,
+ "output_allocations": 0,
+ "parser_allocations": 2,
+ "reuses": 2225,
+ "budget_waits": 0,
+ "slot_waits": 210,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51867983,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26677.738,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055635.91,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040456.355,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66344311,
+ "cpu_ns": 14626628,
+ "parse_call_ns": 10598197,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.993439,
+ "output_byte_seconds": 460.282359,
+ "parser_byte_seconds": 437.832685,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 201,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52108022,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26057.676,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054707.516,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038718.686,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66360126,
+ "cpu_ns": 14610198,
+ "parse_call_ns": 10558947,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.278595,
+ "output_byte_seconds": 460.358957,
+ "parser_byte_seconds": 433.475216,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 210,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52155647,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26056.072,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054720.746,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039527.611,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1209200,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2899968,
+ "elapsed_ns": 66352515,
+ "cpu_ns": 15174956,
+ "parse_call_ns": 10767457,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 28672,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 42522.512719,
+ "output_byte_seconds": 170.992644,
+ "parser_byte_seconds": 444.338525,
+ "source_allocations": 462,
+ "output_allocations": 456,
+ "parser_allocations": 2,
+ "reuses": 1889,
+ "budget_waits": 0,
+ "slot_waits": 203,
+ "compacted": 512,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51584350,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26833.023,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055824.906,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037818.045,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 187312,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66358774,
+ "cpu_ns": 14704746,
+ "parse_call_ns": 10580140,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.401936,
+ "output_byte_seconds": 748.797361,
+ "parser_byte_seconds": 434.190092,
+ "source_allocations": 6,
+ "output_allocations": 546,
+ "parser_allocations": 2,
+ "reuses": 3279,
+ "budget_waits": 0,
+ "slot_waits": 198,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52055904,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26138.373,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054837.756,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038347.354,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "repeat": 0,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66343256,
+ "cpu_ns": 14610428,
+ "parse_call_ns": 10601249,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.005404,
+ "output_byte_seconds": 460.293238,
+ "parser_byte_seconds": 435.304664,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 199,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52113330,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26103.785,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054791.455,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038668.434,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66620533,
+ "cpu_ns": 15009658,
+ "parse_call_ns": 10599246,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.711835,
+ "output_byte_seconds": 461.162485,
+ "parser_byte_seconds": 439.194778,
+ "source_allocations": 6,
+ "output_allocations": 67,
+ "parser_allocations": 2,
+ "reuses": 3246,
+ "budget_waits": 0,
+ "slot_waits": 195,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52089340,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26514.744,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5059599.168,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8052646.494,
+ "latency_p99_upper_ns": 9437184
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 170672,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 69246534,
+ "cpu_ns": 16610834,
+ "parse_call_ns": 11758115,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 215.365911,
+ "output_byte_seconds": 778.347747,
+ "parser_byte_seconds": 481.501477,
+ "source_allocations": 1273,
+ "output_allocations": 1536,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 164,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52395416,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 29861.328,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5481519.523,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8132478.682,
+ "latency_p99_upper_ns": 10485760
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 67338922,
+ "cpu_ns": 15543047,
+ "parse_call_ns": 10965512,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 198.833427,
+ "output_byte_seconds": 461.43294,
+ "parser_byte_seconds": 455.786835,
+ "source_allocations": 6,
+ "output_allocations": 88,
+ "parser_allocations": 2,
+ "reuses": 3225,
+ "budget_waits": 0,
+ "slot_waits": 170,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52096250,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 27620.291,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5405312.287,
+ "latency_p99_upper_ns": 9437184
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8058747.33,
+ "latency_p99_upper_ns": 9437184
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 187312,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66437867,
+ "cpu_ns": 14887131,
+ "parse_call_ns": 10719986,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 192.97609,
+ "output_byte_seconds": 748.927344,
+ "parser_byte_seconds": 442.835871,
+ "source_allocations": 6,
+ "output_allocations": 546,
+ "parser_allocations": 2,
+ "reuses": 3279,
+ "budget_waits": 0,
+ "slot_waits": 206,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51911693,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26502.299,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055229.1,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040517.863,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66341459,
+ "cpu_ns": 14573003,
+ "parse_call_ns": 10555283,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.19959,
+ "output_byte_seconds": 460.262935,
+ "parser_byte_seconds": 433.563583,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 202,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52150322,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26047.523,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054844.742,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037890.609,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1208192,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2801664,
+ "elapsed_ns": 66302663,
+ "cpu_ns": 14680433,
+ "parse_call_ns": 10680579,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 67603.216745,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 441.482243,
+ "source_allocations": 70,
+ "output_allocations": 0,
+ "parser_allocations": 2,
+ "reuses": 2225,
+ "budget_waits": 0,
+ "slot_waits": 203,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52022749,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26241.209,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054887.895,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8036938.547,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "repeat": 1,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1209200,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2916352,
+ "elapsed_ns": 66647996,
+ "cpu_ns": 15645769,
+ "parse_call_ns": 10897093,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 28672,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 42531.184104,
+ "output_byte_seconds": 171.185155,
+ "parser_byte_seconds": 448.382215,
+ "source_allocations": 462,
+ "output_allocations": 456,
+ "parser_allocations": 2,
+ "reuses": 1889,
+ "budget_waits": 0,
+ "slot_waits": 208,
+ "compacted": 512,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51484721,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 27363.605,
+ "latency_p99_upper_ns": 49152
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5056927.043,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8042303.346,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66509552,
+ "cpu_ns": 15439851,
+ "parse_call_ns": 10723161,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 194.692414,
+ "output_byte_seconds": 460.401472,
+ "parser_byte_seconds": 443.814792,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 188,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 51559999,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 27221.904,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5102159.828,
+ "latency_p99_upper_ns": 6291456
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039936.652,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66675868,
+ "cpu_ns": 15617313,
+ "parse_call_ns": 10794500,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 196.368374,
+ "output_byte_seconds": 460.582208,
+ "parser_byte_seconds": 453.168708,
+ "source_allocations": 6,
+ "output_allocations": 72,
+ "parser_allocations": 2,
+ "reuses": 3241,
+ "budget_waits": 0,
+ "slot_waits": 206,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 51576007,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 27391.873,
+ "latency_p99_upper_ns": 45056
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5063401.098,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8043009.266,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66346091,
+ "cpu_ns": 14749114,
+ "parse_call_ns": 10663838,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 191.566293,
+ "output_byte_seconds": 460.387978,
+ "parser_byte_seconds": 441.272197,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 198,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 51956135,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26444.111,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055009.982,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040053.549,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1208192,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2768896,
+ "elapsed_ns": 66340906,
+ "cpu_ns": 14840713,
+ "parse_call_ns": 10710339,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 67628.848076,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 441.911742,
+ "source_allocations": 70,
+ "output_allocations": 0,
+ "parser_allocations": 2,
+ "reuses": 2225,
+ "budget_waits": 0,
+ "slot_waits": 214,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51926596,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26533.881,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055556.934,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040046.408,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 170672,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66367572,
+ "cpu_ns": 14844612,
+ "parse_call_ns": 10626817,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 191.787957,
+ "output_byte_seconds": 748.742987,
+ "parser_byte_seconds": 439.039763,
+ "source_allocations": 1273,
+ "output_allocations": 1536,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 202,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51918865,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26443.496,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055503.67,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037164.848,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1209200,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2916352,
+ "elapsed_ns": 66456221,
+ "cpu_ns": 15237761,
+ "parse_call_ns": 10832907,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 28672,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 42524.965388,
+ "output_byte_seconds": 171.106633,
+ "parser_byte_seconds": 446.50427,
+ "source_allocations": 462,
+ "output_allocations": 456,
+ "parser_allocations": 2,
+ "reuses": 1889,
+ "budget_waits": 0,
+ "slot_waits": 211,
+ "compacted": 512,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51628844,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26894.043,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5056115.033,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040094.787,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "repeat": 2,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 187312,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1818624,
+ "elapsed_ns": 66358054,
+ "cpu_ns": 14786258,
+ "parse_call_ns": 10588699,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.767691,
+ "output_byte_seconds": 748.949984,
+ "parser_byte_seconds": 437.20655,
+ "source_allocations": 6,
+ "output_allocations": 546,
+ "parser_allocations": 2,
+ "reuses": 3279,
+ "budget_waits": 0,
+ "slot_waits": 202,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51982953,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26290.178,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055243.682,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040476.592,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66340017,
+ "cpu_ns": 14641398,
+ "parse_call_ns": 10583202,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.850967,
+ "output_byte_seconds": 460.201756,
+ "parser_byte_seconds": 434.46664,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 200,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52101474,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26126.43,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054896.006,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037126.236,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1208192,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2768896,
+ "elapsed_ns": 66397387,
+ "cpu_ns": 14926280,
+ "parse_call_ns": 10743184,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 67622.063537,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 442.942199,
+ "source_allocations": 70,
+ "output_allocations": 0,
+ "parser_allocations": 2,
+ "reuses": 2225,
+ "budget_waits": 0,
+ "slot_waits": 212,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51935519,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26540.598,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055706.689,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039215.434,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 187312,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66347591,
+ "cpu_ns": 14688841,
+ "parse_call_ns": 10558757,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.237303,
+ "output_byte_seconds": 748.906445,
+ "parser_byte_seconds": 434.052077,
+ "source_allocations": 6,
+ "output_allocations": 546,
+ "parser_allocations": 2,
+ "reuses": 3279,
+ "budget_waits": 0,
+ "slot_waits": 201,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52048363,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26185.322,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054934.725,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039957.693,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1209200,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2916352,
+ "elapsed_ns": 66425702,
+ "cpu_ns": 15126826,
+ "parse_call_ns": 10762572,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 28672,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 42518.234312,
+ "output_byte_seconds": 171.124375,
+ "parser_byte_seconds": 442.813559,
+ "source_allocations": 462,
+ "output_allocations": 456,
+ "parser_allocations": 2,
+ "reuses": 1889,
+ "budget_waits": 0,
+ "slot_waits": 207,
+ "compacted": 512,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51722109,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26699.592,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055311.875,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039588.77,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66342183,
+ "cpu_ns": 14624958,
+ "parse_call_ns": 10558072,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.596919,
+ "output_byte_seconds": 460.250779,
+ "parser_byte_seconds": 436.103934,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 199,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52113950,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26082.711,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054439.891,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037911.916,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 170672,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66421906,
+ "cpu_ns": 14924036,
+ "parse_call_ns": 10733514,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 193.388376,
+ "output_byte_seconds": 748.846289,
+ "parser_byte_seconds": 443.059571,
+ "source_allocations": 1273,
+ "output_allocations": 1536,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 207,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51871512,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26630.812,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055263.076,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039399.533,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "repeat": 3,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66363184,
+ "cpu_ns": 14629240,
+ "parse_call_ns": 10568715,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.501318,
+ "output_byte_seconds": 460.195707,
+ "parser_byte_seconds": 436.121559,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 199,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52142767,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26129.004,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054684.932,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8036606.693,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66354498,
+ "cpu_ns": 14608671,
+ "parse_call_ns": 10552983,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.286265,
+ "output_byte_seconds": 460.245208,
+ "parser_byte_seconds": 433.358809,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 197,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52143565,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26044.074,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054765.459,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037717.471,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 170672,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66440315,
+ "cpu_ns": 15042208,
+ "parse_call_ns": 10714630,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 193.34471,
+ "output_byte_seconds": 749.072578,
+ "parser_byte_seconds": 442.776453,
+ "source_allocations": 1273,
+ "output_allocations": 1536,
+ "parser_allocations": 1024,
+ "reuses": 0,
+ "budget_waits": 0,
+ "slot_waits": 203,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51818059,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26719.596,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055539.021,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8042928.75,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "shared_copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66550686,
+ "cpu_ns": 14565611,
+ "parse_call_ns": 10569760,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 189.196651,
+ "output_byte_seconds": 460.427963,
+ "parser_byte_seconds": 435.936714,
+ "source_allocations": 6,
+ "output_allocations": 70,
+ "parser_allocations": 2,
+ "reuses": 3243,
+ "budget_waits": 0,
+ "slot_waits": 199,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52394259,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26054.17,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054468.873,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8040821.889,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "compact",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1209200,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 7168,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2932736,
+ "elapsed_ns": 66346982,
+ "cpu_ns": 15115580,
+ "parse_call_ns": 10730381,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 28672,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 42539.689103,
+ "output_byte_seconds": 170.963142,
+ "parser_byte_seconds": 440.137993,
+ "source_allocations": 462,
+ "output_allocations": 456,
+ "parser_allocations": 2,
+ "reuses": 1889,
+ "budget_waits": 0,
+ "slot_waits": 200,
+ "compacted": 512,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51642878,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26772.898,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5057876.094,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8039346.365,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "threshold",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 180144,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 7728,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1851392,
+ "elapsed_ns": 66367685,
+ "cpu_ns": 14678765,
+ "parse_call_ns": 10612300,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 290816,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.199351,
+ "output_byte_seconds": 460.290364,
+ "parser_byte_seconds": 438.024028,
+ "source_allocations": 6,
+ "output_allocations": 65,
+ "parser_allocations": 2,
+ "reuses": 3248,
+ "budget_waits": 0,
+ "slot_waits": 200,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 512,
+ "sleep_ns": 52099788,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26178.92,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054797.43,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038471.338,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "borrow",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 1208192,
+ "source_peak_bytes": 1059888,
+ "output_peak_bytes": 0,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 2785280,
+ "elapsed_ns": 66395630,
+ "cpu_ns": 14769876,
+ "parse_call_ns": 10679603,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 0,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 67615.986637,
+ "output_byte_seconds": 0.0,
+ "parser_byte_seconds": 438.40001,
+ "source_allocations": 70,
+ "output_allocations": 0,
+ "parser_allocations": 2,
+ "reuses": 2225,
+ "budget_waits": 0,
+ "slot_waits": 207,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 52035492,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26350.551,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5054965.338,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8038469.066,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "repeat": 4,
+ "status": "ok",
+ "policy": "copy",
+ "parser_version": "0.12.0",
+ "budget_bytes": 2097152,
+ "fixed_bytes": 41728,
+ "peak_reserved_bytes": 187312,
+ "source_peak_bytes": 24672,
+ "output_peak_bytes": 14896,
+ "parser_peak_bytes": 98400,
+ "rss_peak_bytes": 1835008,
+ "elapsed_ns": 66338315,
+ "cpu_ns": 14754424,
+ "parse_call_ns": 10609310,
+ "accepted": 512,
+ "emitted": 1536,
+ "input_bytes": 5259666,
+ "selection_copy_bytes": 319488,
+ "reader_copy_bytes": 6312628,
+ "parser_realloc_copy_bytes": 14086144,
+ "source_byte_seconds": 190.968242,
+ "output_byte_seconds": 748.772024,
+ "parser_byte_seconds": 435.574111,
+ "source_allocations": 6,
+ "output_allocations": 546,
+ "parser_allocations": 2,
+ "reuses": 3279,
+ "budget_waits": 0,
+ "slot_waits": 199,
+ "compacted": 0,
+ "compact_skipped": 0,
+ "dedup_hits": 0,
+ "sleep_ns": 51978025,
+ "live_at_stop_bytes": 0,
+ "unreleased_buffer_bytes": 0,
+ "queues": [
+ {
+ "emitted": 512,
+ "bytes": 262144,
+ "peak_count": 1,
+ "latency_mean_ns": 26285.051,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 5055200.059,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "emitted": 512,
+ "bytes": 28672,
+ "peak_count": 64,
+ "latency_mean_ns": 8037468.172,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ }
+]
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/benchmark.c b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/benchmark.c
new file mode 100644
index 0000000..474bc7f
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/benchmark.c
@@ -0,0 +1,391 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "vendor/yyjson/yyjson.h"
+
+enum { BRANCHES=3, CACHE=16, READ_SIZE=16384, MAX_JSON=1024*1024, HIST=512 };
+enum { SOURCE, OUTPUT, PARSER, KINDS };
+typedef struct Item Item;
+typedef struct Block {
+ size_t capacity, refs;
+ uint64_t since;
+ unsigned kind;
+ Item *views;
+ _Alignas(max_align_t) unsigned char data[];
+} Block;
+struct Item {
+ Block *block;
+ Item *prev, *next;
+ size_t offset, length;
+ uint64_t sequence, start, ready;
+};
+typedef struct Queue {
+ Item *items;
+ size_t head, count, peak;
+ const char *key;
+ uint64_t hold, service, last, emitted, bytes, latency_sum, histogram[HIST];
+} Queue;
+typedef struct Engine {
+ Queue q[BRANCHES];
+ Block *cache[CACHE];
+ unsigned char read_buffer[READ_SIZE];
+ size_t read_at, read_end;
+ size_t budget, fixed, slots, fanout, reserved, active, cached, peak;
+ size_t by_kind[KINDS], peak_kind[KINDS];
+ long double byte_ns[KINDS];
+ uint64_t allocations[KINDS], reuses, accepted, emitted, input_bytes;
+ uint64_t selection_copies, reader_copies, parser_copies, parse_ns;
+ uint64_t budget_waits, slot_waits, compacted, compact_skipped, dedup_hits;
+ uint64_t sleep_ns, elapsed_ns, cpu_ns, cancel_after;
+ unsigned ratio;
+ int pool;
+ const char *policy, *status;
+} Engine;
+static volatile sig_atomic_t stopped;
+static void stop(int sig) { (void)sig; stopped=1; }
+static uint64_t ns(clockid_t clock) {
+ struct timespec t;
+ if (clock_gettime(clock,&t)) abort();
+ return (uint64_t)t.tv_sec*UINT64_C(1000000000)+(uint64_t)t.tv_nsec;
+}
+static size_t rounded(size_t n) { size_t c=64; while(c<n)c*=2; return c; }
+static size_t charge(const Block *b) { return sizeof(*b)+b->capacity; }
+static void check(Engine *e) {
+ assert(e->active+e->cached==e->reserved);
+ assert(e->by_kind[0]+e->by_kind[1]+e->by_kind[2]==e->active);
+ assert(e->fixed+e->reserved<=e->budget);
+ if(e->reserved>e->peak)e->peak=e->reserved;
+ for(unsigned k=0;k<KINDS;++k)if(e->by_kind[k]>e->peak_kind[k])e->peak_kind[k]=e->by_kind[k];
+}
+static void evict(Engine *e,size_t i) {
+ Block *b=e->cache[i]; if(!b)return;
+ assert(!b->refs && !b->views);
+ e->reserved-=charge(b); e->cached-=charge(b); free(b); e->cache[i]=NULL;
+}
+static Block *take(Engine *e,size_t n,unsigned kind) {
+ size_t capacity=rounded(n),need=sizeof(Block)+capacity;
+ Block *b=NULL;
+ if(e->pool)for(size_t i=0;i<CACHE;++i)if(e->cache[i] && e->cache[i]->capacity==capacity) {
+ b=e->cache[i]; e->cache[i]=NULL; e->cached-=need; ++e->reuses; break;
+ }
+ if(!b) {
+ for(size_t i=0;i<CACHE && need>e->budget-e->fixed-e->reserved;++i)evict(e,i);
+ if(need>e->budget-e->fixed-e->reserved)return NULL;
+ b=malloc(need);
+ if(!b){e->status="allocation_failed";return NULL;}
+ b->capacity=capacity; e->reserved+=need; ++e->allocations[kind];
+ }
+ b->kind=kind;b->refs=1;b->views=NULL;b->since=ns(CLOCK_MONOTONIC);
+ e->active+=need;e->by_kind[kind]+=need;check(e);return b;
+}
+static void drop(Engine *e,Block *b) {
+ if(!b)return;
+ assert(b->refs);
+ if(--b->refs)return;
+ assert(!b->views);
+ size_t bytes=charge(b);
+ e->byte_ns[b->kind]+=(long double)bytes*(ns(CLOCK_MONOTONIC)-b->since);
+ e->active-=bytes;e->by_kind[b->kind]-=bytes;
+ if(e->pool && bytes<=e->budget/4-e->cached)for(size_t i=0;i<CACHE;++i)if(!e->cache[i]) {
+ e->cache[i]=b;e->cached+=bytes;check(e);return;
+ }
+ e->reserved-=bytes;free(b);check(e);
+}
+static void attach(Item *item) {
+ Block *b=item->block;
+ item->prev=NULL;item->next=b->views;
+ if(b->views)b->views->prev=item;
+ b->views=item;
+}
+static void detach(Item *item) {
+ if(item->prev)item->prev->next=item->next;else item->block->views=item->next;
+ if(item->next)item->next->prev=item->prev;
+ item->prev=item->next=NULL;
+}
+static void compact(Engine *e,Block *source) {
+ if(strcmp(e->policy,"compact") || source->kind!=SOURCE || source->refs!=1 || !source->views)return;
+ Item *item=source->views;
+ assert(!item->next);
+ if(source->capacity/rounded(item->length)<e->ratio)return;
+ /* Opportunistic only: never block or recurse from a completion callback. */
+ Block *small=take(e,item->length,OUTPUT);
+ if(!small){++e->compact_skipped;return;}
+ memcpy(small->data,source->data+item->offset,item->length);
+ e->selection_copies+=item->length;++e->compacted;
+ detach(item);item->block=small;item->offset=0;attach(item);drop(e,source);
+}
+static uint64_t deadline(Queue *q) {
+ uint64_t ready=q->items[q->head].ready;
+ return ready>q->last+q->service?ready:q->last+q->service;
+}
+static int next_queue(Engine *e) {
+ int selected=-1;uint64_t soon=UINT64_MAX;
+ for(size_t k=0;k<e->fanout;++k)if(e->q[k].count && deadline(&e->q[k])<soon) {
+ selected=(int)k;soon=deadline(&e->q[k]);
+ }
+ return selected;
+}
+static int sleep_to(Engine *e,uint64_t until) {
+ uint64_t start=ns(CLOCK_MONOTONIC),now=start;
+ while(now<until && !stopped) {
+ uint64_t left=until-now;
+ struct timespec t={(time_t)(left/1000000000),(long)(left%1000000000)};
+ if(nanosleep(&t,NULL) && errno!=EINTR){e->status="sleep_failed";return 0;}
+ now=ns(CLOCK_MONOTONIC);
+ }
+ e->sleep_ns+=now-start;return !stopped;
+}
+static unsigned bucket(uint64_t n) {
+ unsigned k=0;for(uint64_t x=n;x>1;x>>=1)++k;
+ return k<3?(unsigned)n:k*8+(unsigned)((n-(UINT64_C(1)<<k))>>(k-3));
+}
+static uint64_t upper(unsigned b) {
+ unsigned k=b/8;
+ if(b<24)return b+1;
+ if(k>=63)return UINT64_MAX;
+ return (UINT64_C(1)<<k)+(uint64_t)(b%8+1)*(UINT64_C(1)<<(k-3));
+}
+static int write_all(Engine *e,const void *data,size_t n) {
+ const unsigned char *p=data;
+ while(n && !stopped) {
+ ssize_t w=write(STDOUT_FILENO,p,n);
+ if(w<0 && errno==EINTR)continue;
+ if(w<=0){e->status="output_failed";return 0;}
+ p+=w;n-=(size_t)w;
+ }
+ return !stopped;
+}
+static int emit(Engine *e) {
+ int k=next_queue(e);assert(k>=0);
+ Queue *q=&e->q[k];Item *item=&q->items[q->head];
+ if(!sleep_to(e,deadline(q)))return 0;
+ unsigned char header[16];
+ for(unsigned i=0;i<4;++i){header[i]=(unsigned char)((unsigned)k>>(8*i));header[4+i]=(unsigned char)(item->length>>(8*i));}
+ for(unsigned i=0;i<8;++i)header[8+i]=(unsigned char)(item->sequence>>(8*i));
+ if(!write_all(e,header,16) || !write_all(e,item->block->data+item->offset,item->length))return 0;
+ uint64_t now=ns(CLOCK_MONOTONIC),latency=now-item->start;
+ q->last=now;q->latency_sum+=latency;++q->histogram[bucket(latency)];
+ ++q->emitted;q->bytes+=item->length;++e->emitted;
+ Block *b=item->block;size_t old_refs=b->refs;
+ detach(item);drop(e,b);item->block=NULL;
+ q->head=(q->head+1)%e->slots;--q->count;
+ if(old_refs>1)compact(e,b);
+ if(e->cancel_after && e->emitted>=e->cancel_after){e->status="cancelled";return 0;}
+ return !strcmp(e->status,"ok");
+}
+static Block *acquire(Engine *e,size_t n,unsigned kind) {
+ for(;;) {
+ Block *b=take(e,n,kind);if(b)return b;
+ if(strcmp(e->status,"ok"))return NULL;
+ if(next_queue(e)<0){e->status="budget_too_small";return NULL;}
+ ++e->budget_waits;if(!emit(e))return NULL;
+ }
+}
+static void *parser_alloc(void *ctx,size_t n) {
+ Block *b=acquire(ctx,n,PARSER);return b?b->data:NULL;
+}
+static Block *from_data(void *p) {return (Block *)((unsigned char *)p-sizeof(Block));}
+static void parser_free(void *ctx,void *p) {if(p)drop(ctx,from_data(p));}
+static void *parser_realloc(void *ctx,void *p,size_t old,size_t n) {
+ if(!p)return parser_alloc(ctx,n);
+ Block *b=from_data(p);assert(b->refs==1 && b->kind==PARSER && old<=b->capacity);
+ if(n<=b->capacity)return p;
+ void *fresh=parser_alloc(ctx,n);if(!fresh)return NULL;
+ memcpy(fresh,p,old);((Engine *)ctx)->parser_copies+=old;parser_free(ctx,p);return fresh;
+}
+/* Bounded NDJSON reader, accepting a final complete JSON without a newline. */
+static Block *read_record(Engine *e,size_t *length) {
+ Block *b=acquire(e,256,SOURCE);if(!b)return NULL;
+ *length=0;
+ for(;;) {
+ if(stopped){drop(e,b);return NULL;}
+ if(e->read_at==e->read_end) {
+ ssize_t got=read(STDIN_FILENO,e->read_buffer,READ_SIZE);
+ if(got<0 && errno==EINTR)continue;
+ if(got<0){e->status="input_failed";drop(e,b);return NULL;}
+ if(!got){if(*length)break;drop(e,b);return NULL;}
+ e->read_at=0;e->read_end=(size_t)got;e->input_bytes+=(uint64_t)got;
+ }
+ unsigned char *p=e->read_buffer+e->read_at;
+ size_t available=e->read_end-e->read_at;
+ unsigned char *newline=memchr(p,'\n',available);
+ size_t amount=newline?(size_t)(newline-p):available;
+ if(amount>MAX_JSON-*length){e->status="record_too_large";drop(e,b);return NULL;}
+ size_t need=*length+amount+YYJSON_PADDING_SIZE;
+ if(need>b->capacity) {
+ Block *larger=acquire(e,need,SOURCE);
+ if(!larger){drop(e,b);return NULL;}
+ memcpy(larger->data,b->data,*length);e->reader_copies+=*length;
+ drop(e,b);b=larger;
+ }
+ memcpy(b->data+*length,p,amount);e->reader_copies+=amount;
+ *length+=amount;e->read_at+=amount+(newline?1:0);
+ if(newline)break;
+ }
+ memset(b->data+*length,0,YYJSON_PADDING_SIZE);return b;
+}
+static int submit(Engine *e,Block *source,size_t length,uint64_t start) {
+ size_t offsets[BRANCHES]={0},lengths[BRANCHES]={0};
+ yyjson_alc alc={parser_alloc,parser_realloc,parser_free,e};
+ yyjson_read_err error;
+ uint64_t before=ns(CLOCK_MONOTONIC);
+ yyjson_doc *doc=yyjson_read_opts((char *)source->data,length,YYJSON_READ_INSITU,&alc,&error);
+ e->parse_ns+=ns(CLOCK_MONOTONIC)-before;
+ if(!doc){if(!strcmp(e->status,"ok"))e->status="invalid_json";drop(e,source);return 0;}
+ yyjson_val *root=yyjson_doc_get_root(doc);
+ int valid=yyjson_is_obj(root);
+ for(size_t k=0;valid && k<e->fanout;++k) {
+ yyjson_val *value=yyjson_obj_get(root,e->q[k].key);
+ const char *str=yyjson_get_str(value);size_t size=yyjson_get_len(value);
+ uintptr_t address=(uintptr_t)str,base=(uintptr_t)source->data;
+ if(!yyjson_is_str(value) || address<base || address-base>length || size>length-(address-base))valid=0;
+ else{offsets[k]=(size_t)(address-base);lengths[k]=size;}
+ }
+ /* Only decoded string offsets/lengths survive. No DOM nodes escape. */
+ yyjson_doc_free(doc);
+ if(!valid){e->status="invalid_schema";drop(e,source);return 0;}
+ Item pending[BRANCHES]={{0}};
+ for(size_t k=0;k<e->fanout;++k) {
+ int copy=!strcmp(e->policy,"copy") || !strcmp(e->policy,"shared_copy") ||
+ (!strcmp(e->policy,"threshold") && source->capacity/rounded(lengths[k])>=e->ratio);
+ int reuse=copy && (!strcmp(e->policy,"shared_copy") || !strcmp(e->policy,"threshold"));
+ Block *b=NULL;size_t offset=offsets[k];
+ if(reuse)for(size_t j=0;j<k;++j)if(offsets[j]==offsets[k] && lengths[j]==lengths[k] && pending[j].block!=source) {
+ b=pending[j].block;++b->refs;offset=0;++e->dedup_hits;break;
+ }
+ if(!b && copy) {
+ b=acquire(e,lengths[k],OUTPUT);
+ if(!b) {
+ for(size_t j=0;j<k;++j)drop(e,pending[j].block);
+ drop(e,source);return 0;
+ }
+ memcpy(b->data,source->data+offset,lengths[k]);e->selection_copies+=lengths[k];offset=0;
+ } else if(!b){b=source;++b->refs;}
+ pending[k]=(Item){.block=b,.offset=offset,.length=lengths[k],.sequence=e->accepted,.start=start};
+ }
+ uint64_t now=ns(CLOCK_MONOTONIC);
+ for(size_t k=0;k<e->fanout;++k) {
+ Queue *q=&e->q[k];assert(q->count<e->slots);
+ Item *item=&q->items[(q->head+q->count)%e->slots];
+ *item=pending[k];item->ready=now+q->hold;attach(item);++q->count;
+ if(q->count>q->peak)q->peak=q->count;
+ }
+ ++e->accepted;drop(e,source);return 1;
+}
+static void run(Engine *e) {
+ while(!stopped && !strcmp(e->status,"ok")) {
+ int k=next_queue(e);
+ if(k>=0 && deadline(&e->q[k])<=ns(CLOCK_MONOTONIC)){if(!emit(e))break;continue;}
+ int full=0;for(size_t j=0;j<e->fanout;++j)if(e->q[j].count==e->slots)full=1;
+ if(full){++e->slot_waits;if(!emit(e))break;continue;}
+ size_t length;uint64_t start=ns(CLOCK_MONOTONIC);
+ Block *source=read_record(e,&length);
+ if(!source) {
+ while(!stopped && !strcmp(e->status,"ok") && next_queue(e)>=0)if(!emit(e))break;
+ break;
+ }
+ if(!submit(e,source,length,start))break;
+ }
+ if(stopped)e->status="cancelled";
+}
+static uint64_t number(const char *s,uint64_t max) {
+ char *end;errno=0;unsigned long long n=strtoull(s,&end,10);
+ if(!*s || *s=='-' || *end || errno || n>max){fprintf(stderr,"invalid number\n");exit(2);}
+ return n;
+}
+static uint64_t rss(void) {
+#if defined(__linux__)
+ FILE *f=fopen("/proc/self/status","r");if(!f)return 0;
+ char line[256];unsigned long long kib=0;
+ while(fgets(line,sizeof(line),f))if(sscanf(line,"VmHWM: %llu kB",&kib)==1)break;
+ fclose(f);return (uint64_t)kib*1024;
+#else
+ return 0;
+#endif
+}
+int main(int argc,char **argv) {
+ _Static_assert(sizeof(Block)==offsetof(Block,data),"aligned block header");
+ Engine storage={0},*e=&storage;
+ e->policy="borrow";e->status="ok";e->slots=64;e->fanout=3;e->budget=8*1024*1024;e->ratio=2;e->pool=1;
+ e->q[0].key="body";e->q[1].key=e->q[2].key="tag";
+ e->q[1].hold=5000000;e->q[2].hold=8000000;
+ for(int i=1;i<argc;i+=2) {
+ if(i+1==argc){fprintf(stderr,"option needs value\n");return 2;}
+ const char *key=argv[i],*value=argv[i+1];
+ if(!strcmp(key,"--policy"))e->policy=value;
+ else if(!strcmp(key,"--budget"))e->budget=(size_t)number(value,1073741824);
+ else if(!strcmp(key,"--slots"))e->slots=(size_t)number(value,4096);
+ else if(!strcmp(key,"--fanout"))e->fanout=(size_t)number(value,BRANCHES);
+ else if(!strcmp(key,"--ratio"))e->ratio=(unsigned)number(value,1024);
+ else if(!strcmp(key,"--pool"))e->pool=(int)number(value,1);
+ else if(!strcmp(key,"--cancel-after"))e->cancel_after=number(value,UINT64_MAX);
+ else {
+ int recognized=0;
+ for(size_t k=0;k<BRANCHES;++k) {
+ char option[32];
+ snprintf(option,sizeof(option),"--key%zu",k);
+ if(!strcmp(key,option)){e->q[k].key=value;recognized=1;}
+ snprintf(option,sizeof(option),"--hold%zu-us",k);
+ if(!strcmp(key,option)){e->q[k].hold=number(value,10000000)*1000;recognized=1;}
+ snprintf(option,sizeof(option),"--service%zu-us",k);
+ if(!strcmp(key,option)){e->q[k].service=number(value,10000000)*1000;recognized=1;}
+ }
+ if(!recognized){fprintf(stderr,"unknown option\n");return 2;}
+ }
+ }
+ if(!e->slots || !e->fanout || e->ratio<2 || (strcmp(e->policy,"borrow") && strcmp(e->policy,"copy") &&
+ strcmp(e->policy,"shared_copy") && strcmp(e->policy,"threshold") && strcmp(e->policy,"compact"))) {
+ fprintf(stderr,"invalid configuration\n");return 2;
+ }
+ e->fixed=sizeof(*e)+e->fanout*e->slots*sizeof(Item);
+ if(e->fixed>e->budget){fprintf(stderr,"budget below metadata\n");return 2;}
+ for(size_t k=0;k<e->fanout;++k) {
+ e->q[k].items=calloc(e->slots,sizeof(Item));
+ if(!e->q[k].items){for(size_t j=0;j<k;++j)free(e->q[j].items);return 2;}
+ }
+ signal(SIGINT,stop);signal(SIGTERM,stop);signal(SIGPIPE,SIG_IGN);
+ uint64_t start=ns(CLOCK_MONOTONIC),cpu=ns(CLOCK_PROCESS_CPUTIME_ID);
+ run(e);
+ size_t live_at_stop=e->active;
+ for(size_t k=0;k<e->fanout;++k) {
+ Queue *q=&e->q[k];
+ while(q->count){Item *item=&q->items[q->head];detach(item);drop(e,item->block);q->head=(q->head+1)%e->slots;--q->count;}
+ }
+ for(size_t i=0;i<CACHE;++i)evict(e,i);
+ assert(!e->active && !e->reserved);
+ e->elapsed_ns=ns(CLOCK_MONOTONIC)-start;e->cpu_ns=ns(CLOCK_PROCESS_CPUTIME_ID)-cpu;
+ fprintf(stderr,"{\"status\":\"%s\",\"policy\":\"%s\",\"parser_version\":\"%s\",\"budget_bytes\":%zu,"
+ "\"fixed_bytes\":%zu,\"peak_reserved_bytes\":%zu,\"source_peak_bytes\":%zu,\"output_peak_bytes\":%zu,"
+ "\"parser_peak_bytes\":%zu,\"rss_peak_bytes\":%" PRIu64 ",\"elapsed_ns\":%" PRIu64 ",\"cpu_ns\":%" PRIu64 ","
+ "\"parse_call_ns\":%" PRIu64 ",\"accepted\":%" PRIu64 ",\"emitted\":%" PRIu64 ",\"input_bytes\":%" PRIu64 ","
+ "\"selection_copy_bytes\":%" PRIu64 ",\"reader_copy_bytes\":%" PRIu64 ",\"parser_realloc_copy_bytes\":%" PRIu64 ","
+ "\"source_byte_seconds\":%.6Lf,\"output_byte_seconds\":%.6Lf,\"parser_byte_seconds\":%.6Lf,"
+ "\"source_allocations\":%" PRIu64 ",\"output_allocations\":%" PRIu64 ",\"parser_allocations\":%" PRIu64 ","
+ "\"reuses\":%" PRIu64 ",\"budget_waits\":%" PRIu64 ",\"slot_waits\":%" PRIu64 ","
+ "\"compacted\":%" PRIu64 ",\"compact_skipped\":%" PRIu64 ",\"dedup_hits\":%" PRIu64 ",\"sleep_ns\":%" PRIu64 ","
+ "\"live_at_stop_bytes\":%zu,\"unreleased_buffer_bytes\":%zu,\"queues\":[",
+ e->status,e->policy,YYJSON_VERSION_STRING,e->budget,e->fixed,e->fixed+e->peak,e->peak_kind[SOURCE],
+ e->peak_kind[OUTPUT],e->peak_kind[PARSER],rss(),e->elapsed_ns,e->cpu_ns,e->parse_ns,e->accepted,e->emitted,
+ e->input_bytes,e->selection_copies,e->reader_copies,e->parser_copies,e->byte_ns[SOURCE]/1e9L,
+ e->byte_ns[OUTPUT]/1e9L,e->byte_ns[PARSER]/1e9L,e->allocations[SOURCE],e->allocations[OUTPUT],
+ e->allocations[PARSER],e->reuses,e->budget_waits,e->slot_waits,e->compacted,e->compact_skipped,
+ e->dedup_hits,e->sleep_ns,live_at_stop,e->reserved);
+ for(size_t k=0;k<e->fanout;++k) {
+ Queue *q=&e->q[k];uint64_t target=q->emitted-q->emitted/100,sum=0,p99=0;
+ for(unsigned b=0;q->emitted && b<HIST;++b){sum+=q->histogram[b];if(sum>=target){p99=upper(b);break;}}
+ fprintf(stderr,"%s{\"emitted\":%" PRIu64 ",\"bytes\":%" PRIu64 ",\"peak_count\":%zu,"
+ "\"latency_mean_ns\":%.3f,\"latency_p99_upper_ns\":%" PRIu64 "}",k?",":"",q->emitted,q->bytes,q->peak,
+ q->emitted?(double)q->latency_sum/q->emitted:0,p99);
+ free(q->items);
+ }
+ fprintf(stderr,"]}\n");return !strcmp(e->status,"ok")?0:!strcmp(e->status,"cancelled")?3:2;
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/plan.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/plan.json
new file mode 100644
index 0000000..60c179b
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/plan.json
@@ -0,0 +1,32 @@
+{
+ "version": 1,
+ "written_before_measurement": true,
+ "seed": 20260923,
+ "repeats": 5,
+ "policies": [
+ {"name": "borrow", "policy": "borrow"},
+ {"name": "copy", "policy": "copy"},
+ {"name": "shared_copy", "policy": "shared_copy"},
+ {"name": "threshold2", "policy": "threshold", "ratio": 2},
+ {"name": "threshold8", "policy": "threshold", "ratio": 8},
+ {"name": "compact", "policy": "compact", "ratio": 2},
+ {"name": "copy_no_pool", "policy": "copy", "pool": 0}
+ ],
+ "cases": [
+ {"name": "one_slow", "shape": "large", "records": 1024, "keys": ["tag"], "hold_us": [8000], "service_us": [0], "budget": 8388608, "slots": 64},
+ {"name": "three_distinct_speeds", "shape": "large", "records": 1024, "keys": ["body", "tag", "tag"], "hold_us": [0, 5000, 8000], "service_us": [0, 0, 0], "budget": 8388608, "slots": 64},
+ {"name": "same_large_field", "shape": "large", "records": 1024, "keys": ["body", "body", "body"], "hold_us": [0, 5000, 8000], "service_us": [0, 0, 0], "budget": 8388608, "slots": 64},
+ {"name": "slow_large_field", "shape": "large", "records": 1024, "keys": ["tag", "tag", "body"], "hold_us": [0, 5000, 8000], "service_us": [0, 0, 0], "budget": 8388608, "slots": 64},
+ {"name": "mixed_tight", "shape": "mixed", "records": 1024, "keys": ["body", "tag", "tag"], "hold_us": [0, 5000, 8000], "service_us": [0, 0, 0], "budget": 2097152, "slots": 64},
+ {"name": "metadata_heavy", "shape": "metadata", "records": 512, "keys": ["body", "tag", "tag"], "hold_us": [0, 5000, 8000], "service_us": [0, 0, 0], "budget": 2097152, "slots": 64}
+ ],
+ "expectations": [
+ "A slow small-field consumer can retain the input after a fast large-field consumer finishes.",
+ "Sharing identical compact copies can remove duplicate per-consumer copies without a new runtime.",
+ "Late compaction may save copied bytes or fail to beat early size-based copying; all remaining owners matter.",
+ "Parser temporary memory and reader growth must be charged, even when retained selections are small.",
+ "No novel-policy advantage or production service SLO is presumed."
+ ],
+ "comparison_rule": "Report all fixed presets; exploratory measurements, no trained/held-out policy or significance claim.",
+ "limits": "Real yyjson parser and actual bytes, but synthetic NDJSON corpus and sink delays, three synchronous consumers in one event loop, no open-loop arrivals, thread races, durable output, or independent parser comparison."
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/run.py b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/run.py
new file mode 100644
index 0000000..e4848bd
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/run.py
@@ -0,0 +1,351 @@
+#!/usr/bin/env python3
+"""Verify and measure yyjson parsing with bounded, differently paced consumers."""
+import argparse
+import csv
+import hashlib
+import json
+import os
+from pathlib import Path
+import platform
+import random
+import shlex
+import signal
+import statistics
+import struct
+import subprocess
+import tempfile
+import time
+
+ROOT = Path(__file__).resolve().parent
+FLAGS = ["-std=c17", "-O2", "-g", "-Wall", "-Wextra", "-Wpedantic", "-Werror"]
+FLAGS += ["-DYYJSON_DISABLE_WRITER=1", "-DYYJSON_DISABLE_UTILS=1", "-DYYJSON_DISABLE_INCR_READER=1"]
+SOURCE_NAMES = ["benchmark.c", "run.py", "plan.json", "vendor/yyjson/UPSTREAM.json",
+ "vendor/yyjson/yyjson.c", "vendor/yyjson/yyjson.h", "vendor/yyjson/LICENSE"]
+
+
+def digest(path):
+ with path.open("rb") as stream:
+ return hashlib.file_digest(stream, "sha256").hexdigest()
+
+
+def dump(path, value):
+ path.write_text(json.dumps(value, indent=2, ensure_ascii=False) + "\n")
+
+
+def first_members(pairs):
+ result = {}
+ for key, value in pairs:
+ result.setdefault(key, value)
+ return result
+
+
+def reference(data, keys):
+ values = [[] for _ in keys]
+ for line in data.splitlines():
+ row = json.loads(line, object_pairs_hook=first_members)
+ if not isinstance(row, dict):
+ raise ValueError("object required")
+ for k, key in enumerate(keys):
+ if not isinstance(row.get(key), str):
+ raise ValueError("string field required")
+ values[k].append(row[key].encode("utf-8"))
+ return values
+
+
+def decode(data, keys, expected, partial=False):
+ at = 0
+ found = [[] for _ in keys]
+ while at < len(data):
+ if len(data) - at < 16:
+ raise AssertionError("incomplete output header")
+ k, length, sequence = struct.unpack_from("<IIQ", data, at)
+ at += 16
+ assert k < len(keys) and sequence == len(found[k])
+ assert length <= len(data) - at
+ found[k].append(data[at:at + length])
+ at += length
+ for k in range(len(keys)):
+ assert found[k] == (expected[k][:len(found[k])] if partial else expected[k])
+ return [len(items) for items in found]
+
+
+def build(cc, output, sanitizer=False):
+ command = [*cc, *FLAGS]
+ if sanitizer:
+ command += ["-O1", "-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
+ command += [str(ROOT / "benchmark.c"), str(ROOT / "vendor/yyjson/yyjson.c"), "-o", str(output)]
+ start = time.monotonic_ns()
+ result = subprocess.run(command, capture_output=True, text=True, check=True)
+ return {"command": command, "stderr": result.stderr, "sha256": digest(output),
+ "size_bytes": output.stat().st_size, "build_wall_ns": time.monotonic_ns() - start}
+
+
+def command(binary, case, policy, *extra):
+ keys = case.get("keys", ["body", "tag", "tag"])
+ holds = case.get("hold_us", [0, 5000, 8000][:len(keys)])
+ services = case.get("service_us", [0] * len(keys))
+ result = [str(binary), "--policy", policy["policy"], "--fanout", str(len(keys)),
+ "--slots", str(case.get("slots", 64)), "--budget", str(case.get("budget", 8388608)),
+ "--pool", str(policy.get("pool", 1)), "--ratio", str(policy.get("ratio", 2))]
+ for k, key in enumerate(keys):
+ result += [f"--key{k}", key, f"--hold{k}-us", str(holds[k]), f"--service{k}-us", str(services[k])]
+ return result + list(extra)
+
+
+def metrics(stderr):
+ try:
+ m = json.loads(stderr)
+ except (ValueError, UnicodeError) as exc:
+ raise AssertionError(f"Expected metrics only, got diagnostics: {stderr!r}") from exc
+ assert m["unreleased_buffer_bytes"] == 0
+ assert m["peak_reserved_bytes"] <= m["budget_bytes"]
+ assert sum(q["emitted"] for q in m["queues"]) == m["emitted"]
+ assert m["parser_version"] == "0.12.0"
+ return m
+
+
+def invoke(binary, case, policy, data, *extra):
+ proc = subprocess.run(command(binary, case, policy, *extra), input=data,
+ capture_output=True, timeout=20)
+ return proc, metrics(proc.stderr)
+
+
+def verify(binary, policies, tmp):
+ checks = []
+ rows = [{"body": "A" * 33000, "tag": "one"},
+ {"body": "한글😀\n\x00\"\\", "tag": ""},
+ {"body": "", "tag": "둘\t\r"},
+ {"body": "z" * 66000, "tag": "three", "meta": [True, None, {"x": -3.5}]}] * 7
+ data = b"".join(json.dumps(row, ensure_ascii=i % 2 == 0).encode() + b"\n" for i, row in enumerate(rows))
+ for policy in policies:
+ for keys in [["tag"], ["body", "tag"], ["body", "tag", "tag"]]:
+ case = {"keys": keys, "hold_us": [500 * k for k in range(len(keys))], "slots": 3}
+ proc, m = invoke(binary, case, policy, data)
+ assert proc.returncode == 0 and m["status"] == "ok", proc.stderr
+ counts = decode(proc.stdout, keys, reference(data, keys))
+ assert counts == [len(rows)] * len(keys) and m["accepted"] == len(rows)
+ assert m["live_at_stop_bytes"] == 0
+ checks.append(f'{policy["name"]}: {len(keys)} consumer(s), UTF-8/escapes/NUL/empty, slot reuse')
+ keys = ["body", "tag", "tag"]
+ for sample in [b"", data.rstrip(b"\n"), b'{"body":"first","body":"second","tag":"x"}\n']:
+ proc, m = invoke(binary, {}, policy, sample)
+ assert proc.returncode == 0 and m["status"] == "ok"
+ decode(proc.stdout, keys, reference(sample, keys))
+ checks.append(f'{policy["name"]}: empty input, final JSON without newline, first duplicate member')
+ malformed = [b'{"body":"x","tag":', b'{"body":"x","tag":"y","extra":[1,]}',
+ b'{"body":"x","tag":3}', b'{"body":"x"}', b'[]',
+ b'{"body":"\xff","tag":"x"}', b'\n',
+ b'{"body":"x","tag":"y"} true']
+ for bad in malformed:
+ proc, m = invoke(binary, {"hold_us": [1000, 2000, 3000]}, policy, data[:data.index(b"\n") + 1] + bad)
+ assert proc.returncode == 2 and m["status"] in {"invalid_json", "invalid_schema"}, proc.stderr
+ checks.append(f'{policy["name"]}: eight invalid JSON/schema cases with retained owners')
+ proc, m = invoke(binary, {}, policy, data, "--cancel-after", "7")
+ assert proc.returncode == 3 and m["status"] == "cancelled" and m["emitted"] == 7
+ counts = decode(proc.stdout, keys, reference(data, keys), partial=True)
+ assert sum(counts) == 7
+ checks.append(f'{policy["name"]}: cancellation preserves each branch prefix and releases all shared owners')
+ # Source can fit; the many JSON nodes require more parser storage than the budget.
+ heavy = json.dumps({"body": "x", "tag": "y", "meta": [0] * 20000}).encode()
+ proc, m = invoke(binary, {"slots": 1, "budget": 160000}, policy, heavy)
+ assert proc.returncode == 2 and m["status"] == "budget_too_small", proc.stderr
+ assert m["accepted"] == 0
+ checks.append(f'{policy["name"]}: parser allocation charged and refused within total budget')
+ # Same decoded field is shared after the document metadata has been freed.
+ sample = json.dumps({"body": "z" * 40000, "tag": "small"}).encode() + b"\n"
+ case = {"keys": ["tag", "tag", "tag"], "hold_us": [0, 1000, 2000]}
+ _, separate = invoke(binary, case, {"policy": "copy"}, sample)
+ proc, shared = invoke(binary, case, {"policy": "shared_copy"}, sample)
+ decode(proc.stdout, case["keys"], reference(sample, case["keys"]))
+ assert separate["selection_copy_bytes"] == 15 and shared["selection_copy_bytes"] == 5
+ assert shared["dedup_hits"] == 2
+ checks.append("identical selections copied once and live until the final consumer")
+ case = {"keys": ["body", "tag"], "hold_us": [0, 3000]}
+ proc, m = invoke(binary, case, {"policy": "compact"}, sample)
+ decode(proc.stdout, case["keys"], reference(sample, case["keys"]))
+ assert m["compacted"] == 1 and m["selection_copy_bytes"] == 5
+ checks.append("last-owner compaction keeps the delayed decoded value valid")
+ proc, m = invoke(binary, {}, policies[0], b'x' * (1024 * 1024 + 1))
+ assert proc.returncode == 2 and m["status"] == "record_too_large"
+ checks.append("overlong NDJSON record refused without leaked source")
+ if Path("/dev/full").exists():
+ with open("/dev/full", "wb") as sink:
+ proc = subprocess.run(command(binary, {}, policies[0]), input=sample,
+ stdout=sink, stderr=subprocess.PIPE, timeout=10)
+ assert proc.returncode == 2 and metrics(proc.stderr)["status"] == "output_failed"
+ checks.append("actual /dev/full failure releases multiple owners")
+ source = tmp / "signal.ndjson"
+ source.write_bytes(sample * 20)
+ with source.open("rb") as inp, open(os.devnull, "wb") as sink:
+ proc = subprocess.Popen(command(binary, {"hold_us": [500000] * 3}, policies[0]),
+ stdin=inp, stdout=sink, stderr=subprocess.PIPE)
+ time.sleep(0.1)
+ proc.send_signal(signal.SIGTERM)
+ _, stderr = proc.communicate(timeout=5)
+ assert proc.returncode == 3 and metrics(stderr)["status"] == "cancelled"
+ checks.append("SIGTERM during delayed fan-out releases all owners")
+ return checks
+
+
+def make_fixture(path, case, seed):
+ rng = random.Random(seed)
+ hashes = [hashlib.sha256() for _ in case["keys"]]
+ sizes = [0] * len(hashes)
+ with path.open("wb") as stream:
+ for seq in range(case["records"]):
+ if case["shape"] == "large":
+ body_size, padding = 32768, 8192
+ elif case["shape"] == "mixed":
+ body_size, padding = rng.choice([(256, 1024), (4096, 16384), (32768, 8192), (65536, 65536)])
+ elif case["shape"] == "metadata":
+ body_size, padding = 512, 512
+ else:
+ raise ValueError(case["shape"])
+ tile = rng.randbytes(128).hex()
+ body = (tile * ((body_size + 255) // 256))[:body_size]
+ tag = f'{seq:08x}-한글-"-\\-\n-\x00-' + tile[:32]
+ row = {"id": seq, "body": body, "tag": tag, "padding": "p" * padding,
+ "meta": list(range(2048)) if case["shape"] == "metadata" else {"ok": True, "n": seq}}
+ encoded = json.dumps(row, ensure_ascii=seq % 2 == 0, separators=(",", ":")).encode("utf-8")
+ stream.write(encoded + b"\n")
+ # Python's independent decoder defines the expected decoded UTF-8 output.
+ decoded = json.loads(encoded)
+ for k, key in enumerate(case["keys"]):
+ selected = decoded[key].encode("utf-8")
+ hashes[k].update(struct.pack("<QI", seq, len(selected)) + selected)
+ sizes[k] += len(selected)
+ return {"case": case["name"], "seed": seed, "records": case["records"], "input_bytes": path.stat().st_size,
+ "input_sha256": digest(path), "keys": case["keys"], "output_bytes_by_branch": sizes,
+ "output_sha256_by_branch": [h.hexdigest() for h in hashes]}
+
+
+def verify_output(path, fixture):
+ count = [0] * len(fixture["keys"])
+ hashes = [hashlib.sha256() for _ in count]
+ sizes = [0] * len(count)
+ with path.open("rb") as stream:
+ while header := stream.read(16):
+ assert len(header) == 16
+ k, n, seq = struct.unpack("<IIQ", header)
+ assert k < len(count) and seq == count[k] and n <= 1024 * 1024
+ data = stream.read(n)
+ assert len(data) == n
+ hashes[k].update(struct.pack("<QI", seq, n) + data)
+ count[k] += 1
+ sizes[k] += n
+ assert count == [fixture["records"]] * len(count)
+ assert sizes == fixture["output_bytes_by_branch"]
+ assert [h.hexdigest() for h in hashes] == fixture["output_sha256_by_branch"]
+
+
+def sample(binary, source, output, case, policy, fixture):
+ with source.open("rb") as inp, output.open("wb") as sink:
+ proc = subprocess.run(command(binary, case, policy), stdin=inp, stdout=sink,
+ stderr=subprocess.PIPE, timeout=30)
+ m = metrics(proc.stderr)
+ assert proc.returncode == 0 and m["status"] == "ok", proc.stderr
+ assert m["accepted"] == case["records"] and m["emitted"] == case["records"] * len(case["keys"])
+ assert m["input_bytes"] == fixture["input_bytes"]
+ assert m["live_at_stop_bytes"] == 0
+ verify_output(output, fixture)
+ return m
+
+
+def summary(rows):
+ keys = ["peak_reserved_bytes", "source_peak_bytes", "output_peak_bytes", "parser_peak_bytes",
+ "rss_peak_bytes", "elapsed_ns", "cpu_ns", "parse_call_ns", "selection_copy_bytes",
+ "reader_copy_bytes", "parser_realloc_copy_bytes", "source_byte_seconds", "budget_waits",
+ "compacted", "dedup_hits"]
+ result = []
+ for case, variant in sorted({(r["case"], r["variant"]) for r in rows}):
+ group = [r for r in rows if (r["case"], r["variant"]) == (case, variant)]
+ item = {"case": case, "variant": variant, "samples": len(group)}
+ for key in keys:
+ values = [r[key] for r in group]
+ item[key] = {"median": statistics.median(values), "min": min(values), "max": max(values)}
+ item["queues"] = [{key: statistics.median(r["queues"][k][key] for r in group)
+ for key in ["peak_count", "latency_mean_ns", "latency_p99_upper_ns"]}
+ for k in range(len(group[0]["queues"]))]
+ result.append(item)
+ return result
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--check-only", action="store_true")
+ parser.add_argument("--output", type=Path)
+ args = parser.parse_args()
+ if not args.check_only and args.output is None:
+ parser.error("provide --check-only or --output NEW_DIRECTORY")
+ if args.output:
+ args.output.mkdir(parents=True, exist_ok=False)
+ upstream = json.loads((ROOT / "vendor/yyjson/UPSTREAM.json").read_text())
+ for name, item in upstream["files"].items():
+ assert digest(ROOT / "vendor/yyjson" / name) == item["sha256"]
+ plan = json.loads((ROOT / "plan.json").read_text())
+ cc = shlex.split(os.environ.get("CC", "cc"))
+ affinity = None
+ if hasattr(os, "sched_getaffinity"):
+ affinity = min(os.sched_getaffinity(0))
+ os.sched_setaffinity(0, {affinity})
+ with tempfile.TemporaryDirectory(prefix="pure-fanout-") as folder:
+ tmp = Path(folder)
+ binary, sanitizer = tmp / "benchmark", tmp / "benchmark-sanitized"
+ print("Building optimized parser and pipeline.", flush=True)
+ builds = [build(cc, binary)]
+ print("Building parser and pipeline with ASan/UBSan (-O1).", flush=True)
+ builds.append(build(cc, sanitizer, True))
+ print("Checking native and instrumented builds.", flush=True)
+ checks = {"native": verify(binary, plan["policies"], tmp),
+ "asan_ubsan": verify(sanitizer, plan["policies"], tmp)}
+ print(f'Verified {sum(map(len, checks.values()))} scenario groups (native + ASan/UBSan).', flush=True)
+ if args.check_only:
+ return
+ sources = {name: digest(ROOT / name) for name in SOURCE_NAMES}
+ environment = {"platform": platform.platform(), "machine": platform.machine(), "python": platform.python_version(),
+ "compiler": subprocess.check_output([*cc, "--version"], text=True), "cpu_affinity": affinity,
+ "builds": builds, "source_sha256": sources, "upstream": upstream,
+ "timing": "I/O, parsing, selection, consumers, instrumentation, cleanup; excludes setup/build/verification",
+ "parse_call_ns": "wall duration inside yyjson_read_opts including allocator backpressure and serviced consumers",
+ "rss": "Linux current-image VmHWM approximate; zero means unavailable on other OSes",
+ "limits": "synthetic closed-loop arrivals/delays; one thread; uncontrolled thermals/power; cached file I/O; no fsync",
+ "started_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())}
+ if Path("/proc/cpuinfo").exists():
+ environment["cpuinfo"] = Path("/proc/cpuinfo").read_text()
+ dump(args.output / "environment.json", environment)
+ dump(args.output / "verification.json", checks)
+ dump(args.output / "plan.json", plan)
+ for name in sources:
+ destination = args.output / "sources" / name
+ destination.parent.mkdir(parents=True, exist_ok=True)
+ destination.write_bytes((ROOT / name).read_bytes())
+ rng, rows, fixtures = random.Random(plan["seed"]), [], []
+ for case in plan["cases"]:
+ source, output = tmp / "input.ndjson", tmp / "branches.bin"
+ info = make_fixture(source, case, plan["seed"])
+ fixtures.append(info)
+ for policy in plan["policies"]:
+ sample(binary, source, output, case, policy, info)
+ for repeat in range(plan["repeats"]):
+ order = list(plan["policies"])
+ rng.shuffle(order)
+ for policy in order:
+ value = sample(binary, source, output, case, policy, info)
+ rows.append({"case": case["name"], "variant": policy["name"], "repeat": repeat, **value})
+ dump(args.output / "raw.json", rows)
+ dump(args.output / "fixtures.json", fixtures)
+ print(f'Completed {case["name"]}: {len(plan["policies"])} variants x {plan["repeats"]} trials.', flush=True)
+ dump(args.output / "summary.json", summary(rows))
+ flat = [{**{k: v for k, v in row.items() if k != "queues"}, "queues": json.dumps(row["queues"])} for row in rows]
+ with (args.output / "raw.csv").open("w") as out:
+ writer = csv.DictWriter(out, fieldnames=list(flat[0]))
+ writer.writeheader()
+ writer.writerows(flat)
+ assert sources == {name: digest(ROOT / name) for name in SOURCE_NAMES}
+ dump(args.output / "complete.json", {"samples": len(rows), "all_branch_outputs_match": True,
+ "finished_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())})
+ print(args.output.resolve())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/LICENSE b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/LICENSE
new file mode 100644
index 0000000..a09bff3
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 YaoYuan <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/UPSTREAM.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/UPSTREAM.json
new file mode 100644
index 0000000..7de2396
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/UPSTREAM.json
@@ -0,0 +1,23 @@
+{
+ "project": "yyjson",
+ "version": "0.12.0",
+ "commit": "8b4a38dc994a110abaec8a400615567bd996105f",
+ "license": "MIT",
+ "files": {
+ "yyjson.c": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/src/yyjson.c",
+ "sha256": "ac2e9bbb2e2d9149d90878d40506a1d624fa0b33c979a11b61075c54782c6d6a",
+ "bytes": 410813
+ },
+ "yyjson.h": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/src/yyjson.h",
+ "sha256": "175867c5493a5df648cec566717fa1c29aa2f6096f5f0cf1efad0b65e1f6d7b3",
+ "bytes": 322407
+ },
+ "LICENSE": {
+ "url": "https://raw.githubusercontent.com/ibireme/yyjson/8b4a38dc994a110abaec8a400615567bd996105f/LICENSE",
+ "sha256": "45e384d3d52c73cba3a64d6e6c25d47cd738cd8a55c30629e3201046eda62947",
+ "bytes": 1084
+ }
+ }
+}
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.c b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.c
new file mode 100644
index 0000000..c16d925
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.c
@@ -0,0 +1,11065 @@
+/*==============================================================================
+ Copyright (c) 2020 YaoYuan <[email protected]>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ *============================================================================*/
+
+#include "yyjson.h"
+#include <math.h> /* for `HUGE_VAL/INFINIY/NAN` macros, no libm required */
+
+
+
+/*==============================================================================
+ * MARK: - Warning Suppress (Private)
+ *============================================================================*/
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunused-function"
+# pragma clang diagnostic ignored "-Wunused-parameter"
+# pragma clang diagnostic ignored "-Wunused-label"
+# pragma clang diagnostic ignored "-Wunused-macros"
+# pragma clang diagnostic ignored "-Wunused-variable"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+# pragma GCC diagnostic ignored "-Wunused-label"
+# pragma GCC diagnostic ignored "-Wunused-macros"
+# pragma GCC diagnostic ignored "-Wunused-variable"
+#elif defined(_MSC_VER)
+# pragma warning(disable:4100) /* unreferenced formal parameter */
+# pragma warning(disable:4101) /* unreferenced variable */
+# pragma warning(disable:4102) /* unreferenced label */
+# pragma warning(disable:4127) /* conditional expression is constant */
+# pragma warning(disable:4706) /* assignment within conditional expression */
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Version (Public)
+ *============================================================================*/
+
+uint32_t yyjson_version(void) {
+ return YYJSON_VERSION_HEX;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Flags (Private)
+ *============================================================================*/
+
+/* msvc intrinsic */
+#if YYJSON_MSC_VER >= 1400
+# include <intrin.h>
+# if defined(_M_AMD64) || defined(_M_ARM64)
+# define MSC_HAS_BIT_SCAN_64 1
+# pragma intrinsic(_BitScanForward64)
+# pragma intrinsic(_BitScanReverse64)
+# else
+# define MSC_HAS_BIT_SCAN_64 0
+# endif
+# if defined(_M_AMD64) || defined(_M_ARM64) || \
+ defined(_M_IX86) || defined(_M_ARM)
+# define MSC_HAS_BIT_SCAN 1
+# pragma intrinsic(_BitScanForward)
+# pragma intrinsic(_BitScanReverse)
+# else
+# define MSC_HAS_BIT_SCAN 0
+# endif
+# if defined(_M_AMD64)
+# define MSC_HAS_UMUL128 1
+# pragma intrinsic(_umul128)
+# else
+# define MSC_HAS_UMUL128 0
+# endif
+#else
+# define MSC_HAS_BIT_SCAN_64 0
+# define MSC_HAS_BIT_SCAN 0
+# define MSC_HAS_UMUL128 0
+#endif
+
+/* gcc builtin */
+#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
+# define GCC_HAS_CLZLL 1
+#else
+# define GCC_HAS_CLZLL 0
+#endif
+
+#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
+# define GCC_HAS_CTZLL 1
+#else
+# define GCC_HAS_CTZLL 0
+#endif
+
+/* int128 type */
+#if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
+ (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER))
+# define YYJSON_HAS_INT128 1
+#else
+# define YYJSON_HAS_INT128 0
+#endif
+
+/* IEEE 754 floating-point binary representation */
+#if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
+# define YYJSON_HAS_IEEE_754 1
+#elif FLT_RADIX == 2 && \
+ FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
+ FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
+ FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
+ DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
+ DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
+ DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
+# define YYJSON_HAS_IEEE_754 1
+#else
+# define YYJSON_HAS_IEEE_754 0
+# undef YYJSON_DISABLE_FAST_FP_CONV
+# define YYJSON_DISABLE_FAST_FP_CONV 1
+#endif
+
+/*
+ Correct rounding in double number computations.
+
+ On the x86 architecture, some compilers may use x87 FPU instructions for
+ floating-point arithmetic. The x87 FPU loads all floating point number as
+ 80-bit double-extended precision internally, then rounds the result to original
+ precision, which may produce inaccurate results. For a more detailed
+ explanation, see the paper: https://arxiv.org/abs/cs/0701192
+
+ Here are some examples of double precision calculation error:
+
+ 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
+ 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
+
+ Here are some examples of compiler flags to generate x87 instructions on x86:
+
+ clang -m32 -mno-sse
+ gcc/icc -m32 -mfpmath=387
+ msvc /arch:SSE or /arch:IA32
+
+ If we are sure that there's no similar error described above, we can define the
+ YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
+ not an accurate detection, it's just try to avoid the error at compile-time.
+ An accurate detection can be done at run-time:
+
+ bool is_double_math_correct(void) {
+ volatile double r = 43683.0;
+ r *= 1e21;
+ return r == 4.3683e25;
+ }
+
+ See also: utils.h in https://github.com/google/double-conversion/
+ */
+#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
+# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+#endif
+
+#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
+# define YYJSON_DOUBLE_MATH_CORRECT 0
+#elif defined(i386) || defined(__i386) || defined(__i386__) || \
+ defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
+ defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
+# if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
+ (defined(__SSE2_MATH__) && __SSE2_MATH__)
+# define YYJSON_DOUBLE_MATH_CORRECT 1
+# else
+# define YYJSON_DOUBLE_MATH_CORRECT 0
+# endif
+#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
+# define YYJSON_DOUBLE_MATH_CORRECT 0
+#else
+# define YYJSON_DOUBLE_MATH_CORRECT 1
+#endif
+
+/*
+ Detect the endianness at compile-time.
+ YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
+ YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
+ */
+#define YYJSON_BIG_ENDIAN 4321
+#define YYJSON_LITTLE_ENDIAN 1234
+
+#if yyjson_has_include(<sys/types.h>)
+# include <sys/types.h> /* POSIX */
+#endif
+#if yyjson_has_include(<endian.h>)
+# include <endian.h> /* Linux */
+#elif yyjson_has_include(<sys/endian.h>)
+# include <sys/endian.h> /* BSD, Android */
+#elif yyjson_has_include(<machine/endian.h>)
+# include <machine/endian.h> /* BSD, Darwin */
+#endif
+
+#if defined(BYTE_ORDER) && BYTE_ORDER
+# if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
+# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
+# elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
+# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
+# endif
+#elif defined(__BYTE_ORDER) && __BYTE_ORDER
+# if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
+# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
+# elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
+# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
+# endif
+#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
+# if defined(__ORDER_BIG_ENDIAN__) && \
+ (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
+# elif defined(__ORDER_LITTLE_ENDIAN__) && \
+ (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
+# endif
+#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
+ defined(__i386) || defined(__i386__) || \
+ defined(_X86_) || defined(__X86__) || \
+ defined(_M_IX86) || defined(__THW_INTEL__) || \
+ defined(__x86_64) || defined(__x86_64__) || \
+ defined(__amd64) || defined(__amd64__) || \
+ defined(_M_AMD64) || defined(_M_X64) || \
+ defined(_M_ARM) || defined(_M_ARM64) || \
+ defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
+ defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
+ defined(__EMSCRIPTEN__) || defined(__wasm__) || \
+ defined(__loongarch__)
+# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
+#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
+ defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
+ defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
+ defined(__or1k__) || defined(__OR1K__)
+# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
+#else
+# define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
+#endif
+
+/*
+ This macro controls how yyjson handles unaligned memory accesses.
+
+ By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
+ to optimize the code and emit unaligned memory access instructions when
+ supported by the target architecture.
+
+ However, on some older compilers or architectures where `memcpy()` is not
+ well-optimized and may result in unnecessary function calls, defining this
+ macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
+ access, which can potentially improve performance.
+
+ An example of the generated assembly code for ARM can be found here:
+ https://godbolt.org/z/334jjhxPT
+
+ This flag is already enabled for common architectures in the following code,
+ so manual configuration is usually unnecessary. If unsure, you can check the
+ generated assembly or run benchmarks to make an informed decision.
+ */
+#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+# if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
+ defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
+# elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
+ (defined(__GNUC__) || defined(__clang__)) && \
+ (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
+# elif defined(__sparc) || defined(__sparc__)
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
+# elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
+# elif defined(__m68k__) || defined(M68000)
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
+# else
+# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
+# endif
+#endif
+
+/*
+ Estimated initial ratio of the JSON data (data_size / value_count).
+ For example:
+
+ data: {"id":12345678,"name":"Harry"}
+ data_size: 30
+ value_count: 5
+ ratio: 6
+
+ yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
+ JSON, the ratios below are used to determine the initial memory size.
+
+ A too large ratio will waste memory, and a too small ratio will cause multiple
+ memory growths and degrade performance. Currently, these ratios are generated
+ with some commonly used JSON datasets.
+ */
+#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
+#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
+#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
+#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
+
+/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
+#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
+#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
+#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
+#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
+
+/* The minimum size of the dynamic allocator's chunk. */
+#define YYJSON_ALC_DYN_MIN_SIZE 0x1000
+
+/* Default value for compile-time options. */
+#ifndef YYJSON_DISABLE_READER
+#define YYJSON_DISABLE_READER 0
+#endif
+#ifndef YYJSON_DISABLE_WRITER
+#define YYJSON_DISABLE_WRITER 0
+#endif
+#ifndef YYJSON_DISABLE_INCR_READER
+#define YYJSON_DISABLE_INCR_READER 0
+#endif
+#ifndef YYJSON_DISABLE_UTILS
+#define YYJSON_DISABLE_UTILS 0
+#endif
+#ifndef YYJSON_DISABLE_FAST_FP_CONV
+#define YYJSON_DISABLE_FAST_FP_CONV 0
+#endif
+#ifndef YYJSON_DISABLE_NON_STANDARD
+#define YYJSON_DISABLE_NON_STANDARD 0
+#endif
+#ifndef YYJSON_DISABLE_UTF8_VALIDATION
+#define YYJSON_DISABLE_UTF8_VALIDATION 0
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Macros (Private)
+ *============================================================================*/
+
+/* Macros used for loop unrolling and other purpose. */
+#define repeat2(x) { x x }
+#define repeat4(x) { x x x x }
+#define repeat8(x) { x x x x x x x x }
+#define repeat16(x) { x x x x x x x x x x x x x x x x }
+
+#define repeat2_incr(x) { x(0) x(1) }
+#define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
+#define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
+#define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
+ x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
+#define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
+ x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
+ x(17) x(18) }
+
+/* Macros used to provide branch prediction information for compiler. */
+#undef likely
+#define likely(x) yyjson_likely(x)
+#undef unlikely
+#define unlikely(x) yyjson_unlikely(x)
+
+/* Macros used to provide inline information for compiler. */
+#undef static_inline
+#define static_inline static yyjson_inline
+#undef static_noinline
+#define static_noinline static yyjson_noinline
+
+/* Macros for min and max. */
+#undef yyjson_min
+#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
+#undef yyjson_max
+#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
+
+/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
+#undef U64
+#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
+#undef U32
+#define U32(hi) ((u32)(hi##UL))
+
+/* Used to cast away (remove) const qualifier. */
+#define constcast(type) (type)(void *)(size_t)(const void *)
+
+/*
+ Compiler barriers for single variables.
+
+ These macros inform GCC that a read or write access to the given memory
+ location will occur, preventing certain compiler optimizations or reordering
+ around the access to 'val'. They do not emit any actual instructions.
+
+ This is useful when GCC's default optimization strategies are suboptimal and
+ precise control over memory access patterns is required.
+ These barriers are not needed when using Clang or MSVC.
+ */
+#if YYJSON_IS_REAL_GCC
+# define gcc_load_barrier(val) __asm__ volatile(""::"m"(val))
+# define gcc_store_barrier(val) __asm__ volatile("":"=m"(val))
+# define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val))
+#else
+# define gcc_load_barrier(val)
+# define gcc_store_barrier(val)
+# define gcc_full_barrier(val)
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Constants (Private)
+ *============================================================================*/
+
+/* Common error messages. */
+#define MSG_FOPEN "failed to open file"
+#define MSG_FREAD "failed to read file"
+#define MSG_FWRITE "failed to write file"
+#define MSG_FCLOSE "failed to close file"
+#define MSG_MALLOC "failed to allocate memory"
+#define MSG_CHAR_T "invalid literal, expected 'true'"
+#define MSG_CHAR_F "invalid literal, expected 'false'"
+#define MSG_CHAR_N "invalid literal, expected 'null'"
+#define MSG_CHAR "unexpected character, expected a JSON value"
+#define MSG_ARR_END "unexpected character, expected ',' or ']'"
+#define MSG_OBJ_KEY "unexpected character, expected a string key"
+#define MSG_OBJ_SEP "unexpected character, expected ':' after key"
+#define MSG_OBJ_END "unexpected character, expected ',' or '}'"
+#define MSG_GARBAGE "unexpected content after document"
+#define MSG_NOT_END "unexpected end of data"
+#define MSG_COMMENT "unclosed multiline comment"
+#define MSG_COMMA "trailing comma is not allowed"
+#define MSG_NAN_INF "nan or inf number is not allowed"
+#define MSG_ERR_TYPE "invalid JSON value type"
+#define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported"
+#define MSG_ERR_UTF8 "invalid utf-8 encoding in string"
+#define MSG_ERR_UTF16 "UTF-16 encoding is not supported"
+#define MSG_ERR_UTF32 "UTF-32 encoding is not supported"
+
+/* U64 constant values */
+#undef U64_MAX
+#define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
+#undef I64_MAX
+#define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
+#undef USIZE_MAX
+#define USIZE_MAX ((usize)(~(usize)0))
+
+/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
+#undef U32_SAFE_DIG
+#define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
+#undef U64_SAFE_DIG
+#define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
+#undef USIZE_SAFE_DIG
+#define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
+
+/* Inf bits (positive) */
+#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
+
+/* NaN bits (quiet NaN, no payload, no sign) */
+#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
+#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
+#else
+#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
+#endif
+
+/* maximum significant digits count in decimal when reading double number */
+#define F64_MAX_DEC_DIG 768
+
+/* maximum decimal power of double number (1.7976931348623157e308) */
+#define F64_MAX_DEC_EXP 308
+
+/* minimum decimal power of double number (4.9406564584124654e-324) */
+#define F64_MIN_DEC_EXP (-324)
+
+/* maximum binary power of double number */
+#define F64_MAX_BIN_EXP 1024
+
+/* minimum binary power of double number */
+#define F64_MIN_BIN_EXP (-1021)
+
+/* float/double number bits */
+#define F32_BITS 32
+#define F64_BITS 64
+
+/* float/double number exponent part bits */
+#define F32_EXP_BITS 8
+#define F64_EXP_BITS 11
+
+/* float/double number significand part bits */
+#define F32_SIG_BITS 23
+#define F64_SIG_BITS 52
+
+/* float/double number significand part bits (with 1 hidden bit) */
+#define F32_SIG_FULL_BITS 24
+#define F64_SIG_FULL_BITS 53
+
+/* float/double number significand bit mask */
+#define F32_SIG_MASK U32(0x007FFFFF)
+#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
+
+/* float/double number exponent bit mask */
+#define F32_EXP_MASK U32(0x7F800000)
+#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
+
+/* float/double number exponent bias */
+#define F32_EXP_BIAS 127
+#define F64_EXP_BIAS 1023
+
+/* float/double number significant digits count in decimal */
+#define F32_DEC_DIG 9
+#define F64_DEC_DIG 17
+
+/* buffer length required for float/double number writer */
+#define FP_BUF_LEN 40
+
+/* maximum length of a number in incremental parsing */
+#define INCR_NUM_MAX_LEN 1024
+
+
+
+/*==============================================================================
+ * MARK: - Types (Private)
+ *============================================================================*/
+
+/** Type define for primitive types. */
+typedef float f32;
+typedef double f64;
+typedef int8_t i8;
+typedef uint8_t u8;
+typedef int16_t i16;
+typedef uint16_t u16;
+typedef int32_t i32;
+typedef uint32_t u32;
+typedef int64_t i64;
+typedef uint64_t u64;
+typedef size_t usize;
+
+/** 128-bit integer, used by floating-point number reader and writer. */
+#if YYJSON_HAS_INT128
+__extension__ typedef __int128 i128;
+__extension__ typedef unsigned __int128 u128;
+#endif
+
+/** 16/32/64-bit vector */
+typedef struct v16 { char c[2]; } v16;
+typedef struct v32 { char c[4]; } v32;
+typedef struct v64 { char c[8]; } v64;
+
+/** 16/32/64-bit vector union */
+typedef union v16_uni { v16 v; u16 u; } v16_uni;
+typedef union v32_uni { v32 v; u32 u; } v32_uni;
+typedef union v64_uni { v64 v; u64 u; } v64_uni;
+
+
+
+/*==============================================================================
+ * MARK: - Load/Store Utils (Private)
+ *============================================================================*/
+
+#define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
+#define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
+#define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
+
+/** Same as `memcpy(dst, src, 2)`, no overlap. */
+static_inline void byte_copy_2(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(dst, src, 2);
+#else
+ repeat2_incr(byte_move_idx)
+#endif
+}
+
+/** Same as `memcpy(dst, src, 4)`, no overlap. */
+static_inline void byte_copy_4(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(dst, src, 4);
+#else
+ repeat4_incr(byte_move_idx)
+#endif
+}
+
+/** Same as `memcpy(dst, src, 8)`, no overlap. */
+static_inline void byte_copy_8(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(dst, src, 8);
+#else
+ repeat8_incr(byte_move_idx)
+#endif
+}
+
+/** Same as `memcpy(dst, src, 16)`, no overlap. */
+static_inline void byte_copy_16(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(dst, src, 16);
+#else
+ repeat16_incr(byte_move_idx)
+#endif
+}
+
+/** Same as `memmove(dst, src, 2)`, allows overlap. */
+static_inline void byte_move_2(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ u16 tmp;
+ memcpy(&tmp, src, 2);
+ memcpy(dst, &tmp, 2);
+#else
+ char tmp[2];
+ repeat2_incr(byte_move_src)
+ repeat2_incr(byte_move_dst)
+#endif
+}
+
+/** Same as `memmove(dst, src, 4)`, allows overlap. */
+static_inline void byte_move_4(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ u32 tmp;
+ memcpy(&tmp, src, 4);
+ memcpy(dst, &tmp, 4);
+#else
+ char tmp[4];
+ repeat4_incr(byte_move_src)
+ repeat4_incr(byte_move_dst)
+#endif
+}
+
+/** Same as `memmove(dst, src, 8)`, allows overlap. */
+static_inline void byte_move_8(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ u64 tmp;
+ memcpy(&tmp, src, 8);
+ memcpy(dst, &tmp, 8);
+#else
+ char tmp[8];
+ repeat8_incr(byte_move_src)
+ repeat8_incr(byte_move_dst)
+#endif
+}
+
+/** Same as `memmove(dst, src, 16)`, allows overlap. */
+static_inline void byte_move_16(void *dst, const void *src) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ char *pdst = (char *)dst;
+ const char *psrc = (const char *)src;
+ u64 tmp1, tmp2;
+ memcpy(&tmp1, psrc, 8);
+ memcpy(&tmp2, psrc + 8, 8);
+ memcpy(pdst, &tmp1, 8);
+ memcpy(pdst + 8, &tmp2, 8);
+#else
+ char tmp[16];
+ repeat16_incr(byte_move_src)
+ repeat16_incr(byte_move_dst)
+#endif
+}
+
+/** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
+static_inline void byte_move_forward(void *dst, void *src, usize n) {
+ char *d = (char *)dst, *s = (char *)src;
+ n += (n % 2); /* round up to even */
+ if (n == 16) { byte_move_16(d, s); return; }
+ if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
+ if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
+ if (n >= 2) { byte_move_2(d, s); }
+}
+
+/** Same as `memcmp(buf, pat, 2) == 0`. */
+static_inline bool byte_match_2(void *buf, const char *pat) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ v16_uni u1, u2;
+ memcpy(&u1, buf, 2);
+ memcpy(&u2, pat, 2);
+ return u1.u == u2.u;
+#else
+ return ((char *)buf)[0] == ((const char *)pat)[0] &&
+ ((char *)buf)[1] == ((const char *)pat)[1];
+#endif
+}
+
+/** Same as `memcmp(buf, pat, 4) == 0`. */
+static_inline bool byte_match_4(void *buf, const char *pat) {
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ v32_uni u1, u2;
+ memcpy(&u1, buf, 4);
+ memcpy(&u2, pat, 4);
+ return u1.u == u2.u;
+#else
+ return ((char *)buf)[0] == ((const char *)pat)[0] &&
+ ((char *)buf)[1] == ((const char *)pat)[1] &&
+ ((char *)buf)[2] == ((const char *)pat)[2] &&
+ ((char *)buf)[3] == ((const char *)pat)[3];
+#endif
+}
+
+/** Loads 2 bytes from `src` as a u16 (native-endian). */
+static_inline u16 byte_load_2(const void *src) {
+ v16_uni uni;
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(&uni, src, 2);
+#else
+ uni.v.c[0] = ((const char *)src)[0];
+ uni.v.c[1] = ((const char *)src)[1];
+#endif
+ return uni.u;
+}
+
+/** Loads 3 bytes from `src` as a u32 (native-endian). */
+static_inline u32 byte_load_3(const void *src) {
+ v32_uni uni;
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(&uni, src, 2);
+ uni.v.c[2] = ((const char *)src)[2];
+ uni.v.c[3] = 0;
+#else
+ uni.v.c[0] = ((const char *)src)[0];
+ uni.v.c[1] = ((const char *)src)[1];
+ uni.v.c[2] = ((const char *)src)[2];
+ uni.v.c[3] = 0;
+#endif
+ return uni.u;
+}
+
+/** Loads 4 bytes from `src` as a u32 (native-endian). */
+static_inline u32 byte_load_4(const void *src) {
+ v32_uni uni;
+#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+ memcpy(&uni, src, 4);
+#else
+ uni.v.c[0] = ((const char *)src)[0];
+ uni.v.c[1] = ((const char *)src)[1];
+ uni.v.c[2] = ((const char *)src)[2];
+ uni.v.c[3] = ((const char *)src)[3];
+#endif
+ return uni.u;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Character Utils (Private)
+ * These lookup tables were generated by `misc/make_tables.c`.
+ *============================================================================*/
+
+/* char_table1 */
+#define CHAR_TYPE_ASCII (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */
+#define CHAR_TYPE_ASCII_SQ (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */
+#define CHAR_TYPE_SPACE (1 << 2) /* Whitespace: [ \t\n\r] */
+#define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
+#define CHAR_TYPE_NUM (1 << 4) /* Number: [.-+0-9] */
+#define CHAR_TYPE_COMMENT (1 << 5) /* Comment: [/] */
+
+/* char_table2 */
+#define CHAR_TYPE_EOL (1 << 0) /* End of line: [\r\n] */
+#define CHAR_TYPE_EOL_EXT (1 << 1) /* End of line: [\r\n], JSON5 */
+#define CHAR_TYPE_ID_START (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */
+#define CHAR_TYPE_ID_NEXT (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */
+#define CHAR_TYPE_ID_ASCII (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
+
+/* char_table3 */
+#define CHAR_TYPE_SIGN (1 << 0) /* [-+] */
+#define CHAR_TYPE_DIGIT (1 << 1) /* [0-9] */
+#define CHAR_TYPE_NONZERO (1 << 2) /* [1-9] */
+#define CHAR_TYPE_EXP (1 << 3) /* [eE] */
+#define CHAR_TYPE_DOT (1 << 4) /* [.] */
+
+static const u8 char_table1[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
+ 0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
+ 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 char_table2[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
+ 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
+};
+
+static const u8 char_table3[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00,
+ 0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/** Match a whitespace: [ \t\n\r]. */
+static_inline bool char_is_space(u8 c) {
+ return !!(char_table1[c] & CHAR_TYPE_SPACE);
+}
+
+/** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
+static_inline bool char_is_space_ext(u8 c) {
+ return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT);
+}
+
+/** Match a JSON number: [.-+0-9]. */
+static_inline bool char_is_num(u8 c) {
+ return !!(char_table1[c] & CHAR_TYPE_NUM);
+}
+
+/** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */
+static_inline bool char_is_ascii_skip(u8 c) {
+ return !!(char_table1[c] & CHAR_TYPE_ASCII);
+}
+
+/** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */
+static_inline bool char_is_ascii_skip_sq(u8 c) {
+ return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ);
+}
+
+/** Match a trivia character: extended whitespace or comment. */
+static_inline bool char_is_trivia(u8 c) {
+ return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT));
+}
+
+/** Match a line end character: [\r\n]. */
+static_inline bool char_is_eol(u8 c) {
+ return !!(char_table2[c] & CHAR_TYPE_EOL);
+}
+
+/** Match an extended line end character: [\r\n], JSON5 line terminator. */
+static_inline bool char_is_eol_ext(u8 c) {
+ return !!(char_table2[c] & CHAR_TYPE_EOL_EXT);
+}
+
+/** Match an identifier name start: [_$A-Za-z\], U+0080+. */
+static_inline bool char_is_id_start(u8 c) {
+ return !!(char_table2[c] & CHAR_TYPE_ID_START);
+}
+
+/** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */
+static_inline bool char_is_id_next(u8 c) {
+ return !!(char_table2[c] & CHAR_TYPE_ID_NEXT);
+}
+
+/** Match an identifier name ASCII: [_$A-Za-z0-9]. */
+static_inline bool char_is_id_ascii(u8 c) {
+ return !!(char_table2[c] & CHAR_TYPE_ID_ASCII);
+}
+
+/** Match a sign: [+-] */
+static_inline bool char_is_sign(u8 d) {
+ return !!(char_table3[d] & CHAR_TYPE_SIGN);
+}
+
+/** Match a none-zero digit: [1-9] */
+static_inline bool char_is_nonzero(u8 d) {
+ return !!(char_table3[d] & CHAR_TYPE_NONZERO);
+}
+
+/** Match a digit: [0-9] */
+static_inline bool char_is_digit(u8 d) {
+ return !!(char_table3[d] & CHAR_TYPE_DIGIT);
+}
+
+/** Match an exponent sign: [eE]. */
+static_inline bool char_is_exp(u8 d) {
+ return !!(char_table3[d] & CHAR_TYPE_EXP);
+}
+
+/** Match a floating point indicator: [.eE]. */
+static_inline bool char_is_fp(u8 d) {
+ return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
+}
+
+/** Match a digit or floating point indicator: [0-9.eE]. */
+static_inline bool char_is_digit_or_fp(u8 d) {
+ return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT |
+ CHAR_TYPE_EXP));
+}
+
+/** Match a JSON container: `{` or `[`. */
+static_inline bool char_is_ctn(u8 c) {
+ return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
+}
+
+/** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
+static_inline u8 char_to_lower(u8 c) {
+ return c | 0x20;
+}
+
+/** Match UTF-8 byte order mask. */
+static_inline bool is_utf8_bom(const u8 *cur) {
+ return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
+}
+
+/** Match UTF-16 byte order mask. */
+static_inline bool is_utf16_bom(const u8 *cur) {
+ return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
+ byte_load_2(cur) == byte_load_2("\xFF\xFE");
+}
+
+/** Match UTF-32 byte order mask, need length check to avoid zero padding. */
+static_inline bool is_utf32_bom(const u8 *cur) {
+ return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
+ byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
+}
+
+/** Get the extended line end length. Used with `char_is_eol_ext`. */
+static_inline usize ext_eol_len(const u8 *cur) {
+ if (cur[0] < 0x80) return 1;
+ if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
+ return 0;
+}
+
+/** Get the extended whitespace length. Used with `char_is_space_ext`. */
+static_inline usize ext_space_len(const u8 *cur) {
+ if (cur[0] < 0x80) {
+ return 1;
+ } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
+ return 2;
+ } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
+ if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
+ if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
+ } else {
+ u32 uni = byte_load_3(cur);
+ if (uni == byte_load_3("\xE1\x9A\x80") ||
+ uni == byte_load_3("\xE2\x81\x9F") ||
+ uni == byte_load_3("\xE3\x80\x80") ||
+ uni == byte_load_3("\xEF\xBB\xBF")) return 3;
+ }
+ return 0;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Hex Character Reader (Private)
+ * This function is used by JSON reader to read escaped characters.
+ *============================================================================*/
+
+/**
+ This table is used to convert 4 hex character sequence to a number.
+ A valid hex character [0-9A-Fa-f] will mapped to it's raw number [0x00, 0x0F],
+ an invalid hex character will mapped to [0xF0].
+ (generate with misc/make_tables.c)
+ */
+static const u8 hex_conv_table[256] = {
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
+};
+
+/** Load 4 hex characters to `u16`, return true on valid input. */
+static_inline bool hex_load_4(const u8 *src, u16 *dst) {
+ u16 c0 = hex_conv_table[src[0]];
+ u16 c1 = hex_conv_table[src[1]];
+ u16 c2 = hex_conv_table[src[2]];
+ u16 c3 = hex_conv_table[src[3]];
+ u16 t0 = (u16)((c0 << 8) | c2);
+ u16 t1 = (u16)((c1 << 8) | c3);
+ *dst = (u16)((t0 << 4) | t1);
+ return ((t0 | t1) & (u16)0xF0F0) == 0;
+}
+
+/** Load 2 hex characters to `u8`, return true on valid input. */
+static_inline bool hex_load_2(const u8 *src, u8 *dst) {
+ u8 c0 = hex_conv_table[src[0]];
+ u8 c1 = hex_conv_table[src[1]];
+ *dst = (u8)((c0 << 4) | c1);
+ return ((c0 | c1) & 0xF0) == 0;
+}
+
+/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
+static_inline bool char_is_hex(u8 c) {
+ return hex_conv_table[c] != 0xF0;
+}
+
+
+
+/*==============================================================================
+ * MARK: - UTF8 Validation (Private)
+ * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
+ * Validation is performed using a 4-byte mask and pattern-based approach,
+ * which requires the input data to be padded with four zero bytes at the end.
+ *============================================================================*/
+
+/* Macro for concatenating four u8 into a u32 and keeping the byte order. */
+#if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
+# define utf8_seq_def(name, a, b, c, d) \
+ static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
+# define utf8_seq(name) utf8_seq_##name
+#elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
+# define utf8_seq_def(name, a, b, c, d) \
+ static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
+# define utf8_seq(name) utf8_seq_##name
+#else
+# define utf8_seq_def(name, a, b, c, d) \
+ static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
+# define utf8_seq(name) utf8_uni_##name.u
+#endif
+
+/*
+ 1-byte sequence (U+0000 to U+007F)
+ bit min [.......0] (U+0000)
+ bit max [.1111111] (U+007F)
+ bit mask [x.......] (80)
+ bit pattern [0.......] (00)
+ */
+utf8_seq_def(b1_mask, 80, 00, 00, 00)
+utf8_seq_def(b1_patt, 00, 00, 00, 00)
+#define is_utf8_seq1(uni) ( \
+ ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
+
+/*
+ 2-byte sequence (U+0080 to U+07FF)
+ bit min [......10 ..000000] (U+0080)
+ bit max [...11111 ..111111] (U+07FF)
+ bit mask [xxx..... xx......] (E0 C0)
+ bit pattern [110..... 10......] (C0 80)
+ bit require [...xxxx. ........] (1E 00)
+ */
+utf8_seq_def(b2_mask, E0, C0, 00, 00)
+utf8_seq_def(b2_patt, C0, 80, 00, 00)
+utf8_seq_def(b2_requ, 1E, 00, 00, 00)
+#define is_utf8_seq2(uni) ( \
+ ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
+ ((uni & utf8_seq(b2_requ))) )
+
+/*
+ 3-byte sequence (U+0800 to U+FFFF)
+ bit min [........ ..100000 ..000000] (U+0800)
+ bit max [....1111 ..111111 ..111111] (U+FFFF)
+ bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
+ bit pattern [1110.... 10...... 10......] (E0 80 80)
+ bit require [....xxxx ..x..... ........] (0F 20 00)
+
+ 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
+ bit min [....1101 ..100000 ..000000] (U+D800)
+ bit max [....1101 ..111111 ..111111] (U+DFFF)
+ bit mask [....xxxx ..x..... ........] (0F 20 00)
+ bit pattern [....1101 ..1..... ........] (0D 20 00)
+ */
+utf8_seq_def(b3_mask, F0, C0, C0, 00)
+utf8_seq_def(b3_patt, E0, 80, 80, 00)
+utf8_seq_def(b3_requ, 0F, 20, 00, 00)
+utf8_seq_def(b3_erro, 0D, 20, 00, 00)
+#define is_utf8_seq3(uni) ( \
+ ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
+ ((tmp = (uni & utf8_seq(b3_requ)))) && \
+ ((tmp != utf8_seq(b3_erro))) )
+
+/*
+ 4-byte sequence (U+10000 to U+10FFFF)
+ bit min [........ ...10000 ..000000 ..000000] (U+10000)
+ bit max [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
+ bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
+ bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
+ bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
+ bit require 1 [.....x.. ........ ........ ........] (04 00 00 00)
+ bit require 2 [......xx ..xx.... ........ ........] (03 30 00 00)
+ */
+utf8_seq_def(b4_mask, F8, C0, C0, C0)
+utf8_seq_def(b4_patt, F0, 80, 80, 80)
+utf8_seq_def(b4_requ, 07, 30, 00, 00)
+utf8_seq_def(b4_req1, 04, 00, 00, 00)
+utf8_seq_def(b4_req2, 03, 30, 00, 00)
+#define is_utf8_seq4(uni) ( \
+ ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
+ ((tmp = (uni & utf8_seq(b4_requ)))) && \
+ ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
+
+
+
+/*==============================================================================
+ * MARK: - Power10 Lookup Table (Private)
+ * These data are used by the floating-point number reader and writer.
+ *============================================================================*/
+
+#if !YYJSON_DISABLE_FAST_FP_CONV
+
+/** Maximum pow10 exponent that can be represented exactly as a float64. */
+#define F64_POW10_MAX_EXACT_EXP 22
+
+/** Cached pow10 table. */
+static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
+ 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
+};
+
+/** Maximum pow10 exponent that can be represented exactly as a uint64. */
+#define U64_POW10_MAX_EXACT_EXP 19
+
+/** Table: [ 10^0, ..., 10^19 ] (generate with misc/make_tables.c) */
+static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
+ U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
+ U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
+ U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
+ U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
+ U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
+ U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
+ U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
+ U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
+ U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
+ U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
+};
+
+/** Minimum decimal exponent in pow10_sig_table. */
+#define POW10_SIG_TABLE_MIN_EXP -343
+
+/** Maximum decimal exponent in pow10_sig_table. */
+#define POW10_SIG_TABLE_MAX_EXP 324
+
+/** Minimum exact decimal exponent in pow10_sig_table */
+#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
+
+/** Maximum exact decimal exponent in pow10_sig_table */
+#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
+
+/** Normalized significant 128 bits of pow10, no rounded up (size: 10.4KB).
+ This lookup table is used by both the double number reader and writer.
+ (generate with misc/make_tables.c) */
+static const u64 pow10_sig_table[] = {
+ U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
+ U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
+ U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
+ U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
+ U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
+ U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
+ U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
+ U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
+ U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
+ U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
+ U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
+ U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
+ U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
+ U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
+ U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
+ U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
+ U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
+ U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
+ U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
+ U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
+ U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
+ U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
+ U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
+ U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
+ U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
+ U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
+ U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
+ U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
+ U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
+ U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
+ U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
+ U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
+ U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
+ U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
+ U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
+ U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
+ U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
+ U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
+ U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
+ U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
+ U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
+ U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
+ U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
+ U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
+ U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
+ U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
+ U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
+ U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
+ U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
+ U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
+ U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
+ U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
+ U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
+ U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
+ U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
+ U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
+ U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
+ U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
+ U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
+ U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
+ U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
+ U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
+ U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
+ U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
+ U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
+ U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
+ U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
+ U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
+ U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
+ U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
+ U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
+ U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
+ U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
+ U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
+ U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
+ U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
+ U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
+ U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
+ U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
+ U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
+ U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
+ U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
+ U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
+ U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
+ U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
+ U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
+ U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
+ U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
+ U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
+ U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
+ U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
+ U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
+ U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
+ U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
+ U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
+ U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
+ U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
+ U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
+ U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
+ U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
+ U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
+ U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
+ U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
+ U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
+ U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
+ U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
+ U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
+ U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
+ U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
+ U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
+ U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
+ U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
+ U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
+ U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
+ U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
+ U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
+ U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
+ U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
+ U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
+ U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
+ U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
+ U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
+ U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
+ U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
+ U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
+ U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
+ U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
+ U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
+ U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
+ U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
+ U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
+ U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
+ U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
+ U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
+ U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
+ U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
+ U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
+ U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
+ U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
+ U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
+ U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
+ U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
+ U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
+ U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
+ U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
+ U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
+ U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
+ U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
+ U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
+ U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
+ U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
+ U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
+ U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
+ U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
+ U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
+ U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
+ U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
+ U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
+ U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
+ U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
+ U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
+ U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
+ U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
+ U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
+ U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
+ U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
+ U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
+ U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
+ U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
+ U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
+ U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
+ U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
+ U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
+ U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
+ U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
+ U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
+ U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
+ U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
+ U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
+ U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
+ U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
+ U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
+ U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
+ U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
+ U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
+ U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
+ U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
+ U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
+ U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
+ U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
+ U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
+ U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
+ U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
+ U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
+ U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
+ U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
+ U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
+ U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
+ U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
+ U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
+ U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
+ U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
+ U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
+ U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
+ U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
+ U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
+ U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
+ U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
+ U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
+ U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
+ U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
+ U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
+ U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
+ U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
+ U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
+ U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
+ U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
+ U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
+ U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
+ U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
+ U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
+ U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
+ U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
+ U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
+ U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
+ U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
+ U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
+ U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
+ U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
+ U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
+ U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
+ U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
+ U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
+ U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
+ U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
+ U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
+ U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
+ U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
+ U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
+ U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
+ U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
+ U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
+ U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
+ U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
+ U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
+ U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
+ U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
+ U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
+ U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
+ U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
+ U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
+ U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
+ U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
+ U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
+ U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
+ U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
+ U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
+ U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
+ U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
+ U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
+ U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
+ U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
+ U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
+ U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
+ U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
+ U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
+ U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
+ U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
+ U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
+ U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
+ U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
+ U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
+ U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
+ U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
+ U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
+ U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
+ U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
+ U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
+ U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
+ U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
+ U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
+ U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
+ U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
+ U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
+ U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
+ U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
+ U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
+ U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
+ U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
+ U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
+ U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
+ U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
+ U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
+ U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
+ U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
+ U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
+ U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
+ U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
+ U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
+ U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
+ U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
+ U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
+ U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
+ U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
+ U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
+ U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
+ U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
+ U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
+ U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
+ U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
+ U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
+ U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
+ U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
+ U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
+ U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
+ U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
+ U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
+ U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
+ U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
+ U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
+ U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
+ U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
+ U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
+ U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
+ U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
+ U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
+ U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
+ U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
+ U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
+ U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
+ U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
+ U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
+ U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
+ U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
+ U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
+ U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
+ U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
+ U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
+ U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
+ U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
+ U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
+ U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
+ U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
+ U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
+ U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
+ U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
+ U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
+ U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
+ U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
+ U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
+ U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
+ U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
+ U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
+ U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
+ U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
+ U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
+ U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
+ U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
+ U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
+ U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
+ U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
+ U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
+ U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
+ U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
+ U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
+ U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
+ U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
+ U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
+ U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
+ U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
+ U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
+ U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
+ U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
+ U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
+ U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
+ U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
+ U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
+ U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
+ U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
+ U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
+ U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
+ U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
+ U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
+ U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
+ U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
+ U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
+ U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
+ U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
+ U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
+ U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
+ U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
+ U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
+ U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
+ U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
+ U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
+ U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
+ U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
+ U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
+ U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
+ U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
+ U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
+ U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
+ U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
+ U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
+ U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
+ U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
+ U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
+ U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
+ U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
+ U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
+ U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
+ U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
+ U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
+ U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
+ U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
+ U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
+ U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
+ U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
+ U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
+ U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
+ U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
+ U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
+ U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
+ U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
+ U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
+ U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
+ U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
+ U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
+ U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
+ U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
+ U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
+ U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
+ U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
+ U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
+ U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
+ U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
+ U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
+ U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
+ U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
+ U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
+ U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
+ U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
+ U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
+ U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
+ U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
+ U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
+ U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
+ U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
+ U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
+ U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
+ U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
+ U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
+ U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
+ U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
+ U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
+ U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
+ U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
+ U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
+ U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
+ U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
+ U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
+ U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
+ U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
+ U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
+ U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
+ U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
+ U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
+ U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
+ U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
+ U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
+ U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
+ U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
+ U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
+ U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
+ U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
+ U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
+ U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
+ U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
+ U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
+ U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
+ U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
+ U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
+ U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
+ U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
+ U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
+ U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
+ U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
+ U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
+ U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
+ U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
+ U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
+ U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
+ U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
+ U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
+ U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
+ U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
+ U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
+ U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
+ U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
+ U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
+ U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
+ U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
+ U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
+ U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
+ U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
+ U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
+ U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
+ U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
+ U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
+ U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
+ U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
+ U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
+ U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
+ U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
+ U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
+ U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
+ U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
+ U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
+ U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
+ U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
+ U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
+ U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
+ U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
+ U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
+ U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
+ U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
+ U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
+ U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
+ U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
+ U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
+ U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
+ U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
+ U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
+ U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
+ U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
+ U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
+ U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
+ U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
+ U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
+ U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
+ U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
+ U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
+ U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
+ U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
+ U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
+ U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
+ U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
+ U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
+ U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
+ U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
+ U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
+ U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
+ U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
+ U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
+ U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
+ U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
+ U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
+ U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
+ U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
+ U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
+ U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
+ U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
+ U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
+ U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
+ U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
+ U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
+ U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
+ U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
+ U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
+ U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
+ U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
+ U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
+ U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
+ U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
+ U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
+ U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
+ U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
+ U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
+ U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
+ U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
+ U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
+ U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
+ U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
+ U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
+ U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
+ U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
+ U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
+ U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
+ U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
+ U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
+ U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
+ U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
+ U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
+ U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
+ U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
+ U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
+ U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
+ U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
+ U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
+ U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
+ U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
+ U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
+ U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
+ U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
+ U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
+ U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
+ U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
+ U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
+ U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
+ U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
+ U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
+ U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
+ U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
+ U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
+ U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
+ U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
+ U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
+ U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
+ U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
+ U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
+ U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
+ U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
+ U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
+ U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
+ U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
+ U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
+ U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
+ U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
+ U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
+ U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
+ U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
+ U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
+ U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
+ U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
+ U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
+ U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
+ U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
+ U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
+ U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
+ U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
+ U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
+ U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
+ U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
+ U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
+ U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
+ U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
+ U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
+ U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
+ U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
+ U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
+ U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
+ U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
+ U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
+ U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
+ U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
+ U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
+ U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
+ U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
+ U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
+ U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
+ U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
+ U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
+ U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
+ U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
+ U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
+ U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
+ U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
+ U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
+};
+
+/**
+ Get the cached pow10 value from `pow10_sig_table`.
+ @param exp10 The exponent of pow(10, e). This value must in range
+ `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
+ @param hi The highest 64 bits of pow(10, e).
+ @param lo The lower 64 bits after `hi`.
+ */
+static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
+ i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
+ *hi = pow10_sig_table[idx * 2];
+ *lo = pow10_sig_table[idx * 2 + 1];
+}
+
+/**
+ Get the exponent (base 2) for highest 64 bits significand in `pow10_sig_table`.
+ */
+static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
+ /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
+ /* = floor(e * log2(10) - 63) */
+ *exp2 = (exp10 * 217706 - 4128768) >> 16;
+}
+
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Number and Bit Utils (Private)
+ *============================================================================*/
+
+/** Convert bits to double. */
+static_inline f64 f64_from_bits(u64 u) {
+ f64 f;
+ memcpy(&f, &u, sizeof(u));
+ return f;
+}
+
+/** Convert double to bits. */
+static_inline u64 f64_to_bits(f64 f) {
+ u64 u;
+ memcpy(&u, &f, sizeof(u));
+ return u;
+}
+
+/** Convert double to bits. */
+static_inline u32 f32_to_bits(f32 f) {
+ u32 u;
+ memcpy(&u, &f, sizeof(u));
+ return u;
+}
+
+/** Get 'infinity' bits with sign. */
+static_inline u64 f64_bits_inf(bool sign) {
+#if YYJSON_HAS_IEEE_754
+ return F64_BITS_INF | ((u64)sign << 63);
+#elif defined(INFINITY)
+ return f64_to_bits(sign ? -INFINITY : INFINITY);
+#else
+ return f64_to_bits(sign ? -HUGE_VAL : HUGE_VAL);
+#endif
+}
+
+/** Get 'nan' bits with sign. */
+static_inline u64 f64_bits_nan(bool sign) {
+#if YYJSON_HAS_IEEE_754
+ return F64_BITS_NAN | ((u64)sign << 63);
+#elif defined(NAN)
+ return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
+#else
+ return f64_to_bits((sign ? -0.0 : 0.0) / 0.0);
+#endif
+}
+
+/** Casting double to float, allow overflow. */
+#if yyjson_has_attribute(no_sanitize)
+__attribute__((no_sanitize("undefined")))
+#elif yyjson_gcc_available(4, 9, 0)
+__attribute__((__no_sanitize_undefined__))
+#endif
+static_inline f32 f64_to_f32(f64 val) {
+ return (f32)val;
+}
+
+/** Returns the number of leading 0-bits in value (input should not be 0). */
+static_inline u32 u64_lz_bits(u64 v) {
+#if GCC_HAS_CLZLL
+ return (u32)__builtin_clzll(v);
+#elif MSC_HAS_BIT_SCAN_64
+ unsigned long r;
+ _BitScanReverse64(&r, v);
+ return (u32)63 - (u32)r;
+#elif MSC_HAS_BIT_SCAN
+ unsigned long hi, lo;
+ bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
+ _BitScanReverse(&lo, (u32)v);
+ hi |= 32;
+ return (u32)63 - (u32)(hi_set ? hi : lo);
+#else
+ /* branchless, use De Bruijn sequence */
+ /* see: https://www.chessprogramming.org/BitScan */
+ const u8 table[64] = {
+ 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
+ 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
+ 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
+ 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
+ };
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v |= v >> 32;
+ return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
+#endif
+}
+
+/** Returns the number of trailing 0-bits in value (input should not be 0). */
+static_inline u32 u64_tz_bits(u64 v) {
+#if GCC_HAS_CTZLL
+ return (u32)__builtin_ctzll(v);
+#elif MSC_HAS_BIT_SCAN_64
+ unsigned long r;
+ _BitScanForward64(&r, v);
+ return (u32)r;
+#elif MSC_HAS_BIT_SCAN
+ unsigned long lo, hi;
+ bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
+ _BitScanForward(&hi, (u32)(v >> 32));
+ hi += 32;
+ return lo_set ? lo : hi;
+#else
+ /* branchless, use De Bruijn sequence */
+ /* see: https://www.chessprogramming.org/BitScan */
+ const u8 table[64] = {
+ 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
+ 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
+ 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
+ 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
+ };
+ return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
+#endif
+}
+
+/** Multiplies two 64-bit unsigned integers (a * b),
+ returns the 128-bit result as 'hi' and 'lo'. */
+static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
+#if YYJSON_HAS_INT128
+ u128 m = (u128)a * b;
+ *hi = (u64)(m >> 64);
+ *lo = (u64)(m);
+#elif MSC_HAS_UMUL128
+ *lo = _umul128(a, b, hi);
+#else
+ u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
+ u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
+ u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
+ u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
+ u64 m0 = p01 + (p00 >> 32);
+ u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
+ u64 m1 = p10 + m00;
+ u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
+ *hi = p11 + m01 + m11;
+ *lo = ((u64)m10 << 32) | (u32)p00;
+#endif
+}
+
+/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
+ returns the 128-bit result as 'hi' and 'lo'. */
+static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
+#if YYJSON_HAS_INT128
+ u128 m = (u128)a * b + c;
+ *hi = (u64)(m >> 64);
+ *lo = (u64)(m);
+#else
+ u64 h, l, t;
+ u128_mul(a, b, &h, &l);
+ t = l + c;
+ h += (u64)(((t < l) | (t < c)));
+ *hi = h;
+ *lo = t;
+#endif
+}
+
+
+
+/*==============================================================================
+ * MARK: - File Utils (Private)
+ * These functions are used to read and write JSON files.
+ *============================================================================*/
+
+#define YYJSON_FOPEN_E
+#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2, 7)
+# undef YYJSON_FOPEN_E
+# define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
+# endif
+#endif
+
+static_inline FILE *fopen_safe(const char *path, const char *mode) {
+#if YYJSON_MSC_VER >= 1400
+ FILE *file = NULL;
+ if (fopen_s(&file, path, mode) != 0) return NULL;
+ return file;
+#else
+ return fopen(path, mode);
+#endif
+}
+
+static_inline FILE *fopen_readonly(const char *path) {
+ return fopen_safe(path, "rb" YYJSON_FOPEN_E);
+}
+
+static_inline FILE *fopen_writeonly(const char *path) {
+ return fopen_safe(path, "wb" YYJSON_FOPEN_E);
+}
+
+static_inline usize fread_safe(void *buf, usize size, FILE *file) {
+#if YYJSON_MSC_VER >= 1400
+ return fread_s(buf, size, 1, size, file);
+#else
+ return fread(buf, 1, size, file);
+#endif
+}
+
+
+
+/*==============================================================================
+ * MARK: - Size Utils (Private)
+ * These functions are used for memory allocation.
+ *============================================================================*/
+
+/** Returns whether the size is overflow after increment. */
+static_inline bool size_add_is_overflow(usize size, usize add) {
+ return size > (size + add);
+}
+
+/** Returns whether the size is power of 2 (size should not be 0). */
+static_inline bool size_is_pow2(usize size) {
+ return (size & (size - 1)) == 0;
+}
+
+/** Align size upwards (may overflow). */
+static_inline usize size_align_up(usize size, usize align) {
+ if (size_is_pow2(align)) {
+ return (size + (align - 1)) & ~(align - 1);
+ } else {
+ return size + align - (size + align - 1) % align - 1;
+ }
+}
+
+/** Align size downwards. */
+static_inline usize size_align_down(usize size, usize align) {
+ if (size_is_pow2(align)) {
+ return size & ~(align - 1);
+ } else {
+ return size - (size % align);
+ }
+}
+
+/** Align address upwards (may overflow). */
+static_inline void *mem_align_up(void *mem, usize align) {
+ usize size;
+ memcpy(&size, &mem, sizeof(usize));
+ size = size_align_up(size, align);
+ memcpy(&mem, &size, sizeof(usize));
+ return mem;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Default Memory Allocator (Private)
+ * This is a simple libc memory allocator wrapper.
+ *============================================================================*/
+
+static void *default_malloc(void *ctx, usize size) {
+ return malloc(size);
+}
+
+static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
+ return realloc(ptr, size);
+}
+
+static void default_free(void *ctx, void *ptr) {
+ free(ptr);
+}
+
+static const yyjson_alc YYJSON_DEFAULT_ALC = {
+ default_malloc, default_realloc, default_free, NULL
+};
+
+
+
+/*==============================================================================
+ * MARK: - Null Memory Allocator (Private)
+ * This allocator is just a placeholder to ensure that the internal
+ * malloc/realloc/free function pointers are not null.
+ *============================================================================*/
+
+static void *null_malloc(void *ctx, usize size) {
+ return NULL;
+}
+
+static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
+ return NULL;
+}
+
+static void null_free(void *ctx, void *ptr) {
+ return;
+}
+
+static const yyjson_alc YYJSON_NULL_ALC = {
+ null_malloc, null_realloc, null_free, NULL
+};
+
+
+
+/*==============================================================================
+ * MARK: - Pool Memory Allocator (Public)
+ * This allocator is initialized with a fixed-size buffer.
+ * The buffer is split into multiple memory chunks for memory allocation.
+ *============================================================================*/
+
+/** memory chunk header */
+typedef struct pool_chunk {
+ usize size; /* chunk memory size, include chunk header */
+ struct pool_chunk *next; /* linked list, nullable */
+ /* char mem[]; flexible array member */
+} pool_chunk;
+
+/** allocator ctx header */
+typedef struct pool_ctx {
+ usize size; /* total memory size, include ctx header */
+ pool_chunk *free_list; /* linked list, nullable */
+ /* pool_chunk chunks[]; flexible array member */
+} pool_ctx;
+
+/** align up the input size to chunk size */
+static_inline void pool_size_align(usize *size) {
+ *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
+}
+
+static void *pool_malloc(void *ctx_ptr, usize size) {
+ /* assert(size != 0) */
+ pool_ctx *ctx = (pool_ctx *)ctx_ptr;
+ pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
+
+ if (unlikely(size >= ctx->size)) return NULL;
+ pool_size_align(&size);
+
+ while (cur) {
+ if (cur->size < size) {
+ /* not enough space, try next chunk */
+ prev = cur;
+ cur = cur->next;
+ continue;
+ }
+ if (cur->size >= size + sizeof(pool_chunk) * 2) {
+ /* too much space, split this chunk */
+ next = (pool_chunk *)(void *)((u8 *)cur + size);
+ next->size = cur->size - size;
+ next->next = cur->next;
+ cur->size = size;
+ } else {
+ /* just enough space, use whole chunk */
+ next = cur->next;
+ }
+ if (prev) prev->next = next;
+ else ctx->free_list = next;
+ return (void *)(cur + 1);
+ }
+ return NULL;
+}
+
+static void pool_free(void *ctx_ptr, void *ptr) {
+ /* assert(ptr != NULL) */
+ pool_ctx *ctx = (pool_ctx *)ctx_ptr;
+ pool_chunk *cur = ((pool_chunk *)ptr) - 1;
+ pool_chunk *prev = NULL, *next = ctx->free_list;
+
+ while (next && next < cur) {
+ prev = next;
+ next = next->next;
+ }
+ if (prev) prev->next = cur;
+ else ctx->free_list = cur;
+ cur->next = next;
+
+ if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
+ /* merge cur to higher chunk */
+ cur->size += next->size;
+ cur->next = next->next;
+ }
+ if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
+ /* merge cur to lower chunk */
+ prev->size += cur->size;
+ prev->next = cur->next;
+ }
+}
+
+static void *pool_realloc(void *ctx_ptr, void *ptr,
+ usize old_size, usize size) {
+ /* assert(ptr != NULL && size != 0 && old_size < size) */
+ pool_ctx *ctx = (pool_ctx *)ctx_ptr;
+ pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
+
+ /* check size */
+ if (unlikely(size >= ctx->size)) return NULL;
+ pool_size_align(&old_size);
+ pool_size_align(&size);
+ if (unlikely(old_size == size)) return ptr;
+
+ /* find next and prev chunk */
+ prev = NULL;
+ next = ctx->free_list;
+ while (next && next < cur) {
+ prev = next;
+ next = next->next;
+ }
+
+ if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
+ /* merge to higher chunk if they are contiguous */
+ usize free_size = cur->size + next->size - size;
+ if (free_size > sizeof(pool_chunk) * 2) {
+ tmp = (pool_chunk *)(void *)((u8 *)cur + size);
+ if (prev) prev->next = tmp;
+ else ctx->free_list = tmp;
+ tmp->next = next->next;
+ tmp->size = free_size;
+ cur->size = size;
+ } else {
+ if (prev) prev->next = next->next;
+ else ctx->free_list = next->next;
+ cur->size += next->size;
+ }
+ return ptr;
+ } else {
+ /* fallback to malloc and memcpy */
+ void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
+ if (new_ptr) {
+ memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
+ pool_free(ctx_ptr, ptr);
+ }
+ return new_ptr;
+ }
+}
+
+bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
+ pool_chunk *chunk;
+ pool_ctx *ctx;
+
+ if (unlikely(!alc)) return false;
+ *alc = YYJSON_NULL_ALC;
+ if (size < sizeof(pool_ctx) * 4) return false;
+ ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
+ if (unlikely(!ctx)) return false;
+ size -= (usize)((u8 *)ctx - (u8 *)buf);
+ size = size_align_down(size, sizeof(pool_ctx));
+
+ chunk = (pool_chunk *)(ctx + 1);
+ chunk->size = size - sizeof(pool_ctx);
+ chunk->next = NULL;
+ ctx->size = size;
+ ctx->free_list = chunk;
+
+ alc->malloc = pool_malloc;
+ alc->realloc = pool_realloc;
+ alc->free = pool_free;
+ alc->ctx = (void *)ctx;
+ return true;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Dynamic Memory Allocator (Public)
+ * This allocator allocates memory on demand and does not immediately release
+ * unused memory. Instead, it places the unused memory into a freelist for
+ * potential reuse in the future. It is only when the entire allocator is
+ * destroyed that all previously allocated memory is released at once.
+ *============================================================================*/
+
+/** memory chunk header */
+typedef struct dyn_chunk {
+ usize size; /* chunk size, include header */
+ struct dyn_chunk *next;
+ /* char mem[]; flexible array member */
+} dyn_chunk;
+
+/** allocator ctx header */
+typedef struct {
+ dyn_chunk free_list; /* dummy header, sorted from small to large */
+ dyn_chunk used_list; /* dummy header */
+} dyn_ctx;
+
+/** align up the input size to chunk size */
+static_inline bool dyn_size_align(usize *size) {
+ usize alc_size = *size + sizeof(dyn_chunk);
+ alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
+ if (unlikely(alc_size < *size)) return false; /* overflow */
+ *size = alc_size;
+ return true;
+}
+
+/** remove a chunk from list (the chunk must already be in the list) */
+static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
+ dyn_chunk *prev = list, *cur;
+ for (cur = prev->next; cur; cur = cur->next) {
+ if (cur == chunk) {
+ prev->next = cur->next;
+ cur->next = NULL;
+ return;
+ }
+ prev = cur;
+ }
+}
+
+/** add a chunk to list header (the chunk must not be in the list) */
+static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
+ chunk->next = list->next;
+ list->next = chunk;
+}
+
+static void *dyn_malloc(void *ctx_ptr, usize size) {
+ /* assert(size != 0) */
+ const yyjson_alc def = YYJSON_DEFAULT_ALC;
+ dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
+ dyn_chunk *chunk, *prev;
+ if (unlikely(!dyn_size_align(&size))) return NULL;
+
+ /* freelist is empty, create new chunk */
+ if (!ctx->free_list.next) {
+ chunk = (dyn_chunk *)def.malloc(def.ctx, size);
+ if (unlikely(!chunk)) return NULL;
+ chunk->size = size;
+ chunk->next = NULL;
+ dyn_chunk_list_add(&ctx->used_list, chunk);
+ return (void *)(chunk + 1);
+ }
+
+ /* find a large enough chunk, or resize the largest chunk */
+ prev = &ctx->free_list;
+ while (true) {
+ chunk = prev->next;
+ if (chunk->size >= size) { /* enough size, reuse this chunk */
+ prev->next = chunk->next;
+ dyn_chunk_list_add(&ctx->used_list, chunk);
+ return (void *)(chunk + 1);
+ }
+ if (!chunk->next) { /* resize the largest chunk */
+ chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
+ if (unlikely(!chunk)) return NULL;
+ prev->next = NULL;
+ chunk->size = size;
+ dyn_chunk_list_add(&ctx->used_list, chunk);
+ return (void *)(chunk + 1);
+ }
+ prev = chunk;
+ }
+}
+
+static void *dyn_realloc(void *ctx_ptr, void *ptr,
+ usize old_size, usize size) {
+ /* assert(ptr != NULL && size != 0 && old_size < size) */
+ const yyjson_alc def = YYJSON_DEFAULT_ALC;
+ dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
+ dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
+ if (unlikely(!dyn_size_align(&size))) return NULL;
+ if (chunk->size >= size) return ptr;
+
+ dyn_chunk_list_remove(&ctx->used_list, chunk);
+ new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
+ if (likely(new_chunk)) {
+ new_chunk->size = size;
+ chunk = new_chunk;
+ }
+ dyn_chunk_list_add(&ctx->used_list, chunk);
+ return new_chunk ? (void *)(new_chunk + 1) : NULL;
+}
+
+static void dyn_free(void *ctx_ptr, void *ptr) {
+ /* assert(ptr != NULL) */
+ dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
+ dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
+
+ dyn_chunk_list_remove(&ctx->used_list, chunk);
+ for (prev = &ctx->free_list; prev; prev = prev->next) {
+ if (!prev->next || prev->next->size >= chunk->size) {
+ chunk->next = prev->next;
+ prev->next = chunk;
+ break;
+ }
+ }
+}
+
+yyjson_alc *yyjson_alc_dyn_new(void) {
+ const yyjson_alc def = YYJSON_DEFAULT_ALC;
+ usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
+ yyjson_alc *alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
+ dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
+ if (unlikely(!alc)) return NULL;
+ alc->malloc = dyn_malloc;
+ alc->realloc = dyn_realloc;
+ alc->free = dyn_free;
+ alc->ctx = alc + 1;
+ memset(ctx, 0, sizeof(*ctx));
+ return alc;
+}
+
+void yyjson_alc_dyn_free(yyjson_alc *alc) {
+ const yyjson_alc def = YYJSON_DEFAULT_ALC;
+ dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
+ dyn_chunk *chunk, *next;
+ if (unlikely(!alc)) return;
+ for (chunk = ctx->free_list.next; chunk; chunk = next) {
+ next = chunk->next;
+ def.free(def.ctx, chunk);
+ }
+ for (chunk = ctx->used_list.next; chunk; chunk = next) {
+ next = chunk->next;
+ def.free(def.ctx, chunk);
+ }
+ def.free(def.ctx, alc);
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Struct Utils (Public)
+ * These functions are used for creating, copying, releasing, and comparing
+ * JSON documents and values. They are widely used throughout this library.
+ *============================================================================*/
+
+static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
+ yyjson_alc *alc) {
+ yyjson_str_chunk *chunk = pool->chunks, *next;
+ while (chunk) {
+ next = chunk->next;
+ alc->free(alc->ctx, chunk);
+ chunk = next;
+ }
+}
+
+static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
+ yyjson_alc *alc) {
+ yyjson_val_chunk *chunk = pool->chunks, *next;
+ while (chunk) {
+ next = chunk->next;
+ alc->free(alc->ctx, chunk);
+ chunk = next;
+ }
+}
+
+bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
+ const yyjson_alc *alc, usize len) {
+ yyjson_str_chunk *chunk;
+ usize size, max_len;
+
+ /* create a new chunk */
+ max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
+ if (unlikely(len > max_len)) return false;
+ size = len + sizeof(yyjson_str_chunk);
+ size = yyjson_max(pool->chunk_size, size);
+ chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
+ if (unlikely(!chunk)) return false;
+
+ /* insert the new chunk as the head of the linked list */
+ chunk->next = pool->chunks;
+ chunk->chunk_size = size;
+ pool->chunks = chunk;
+ pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
+ pool->end = (char *)chunk + size;
+
+ /* the next chunk is twice the size of the current one */
+ size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
+ if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
+ pool->chunk_size = size;
+ return true;
+}
+
+bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
+ const yyjson_alc *alc, usize count) {
+ yyjson_val_chunk *chunk;
+ usize size, max_count;
+
+ /* create a new chunk */
+ max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
+ if (unlikely(count > max_count)) return false;
+ size = (count + 1) * sizeof(yyjson_mut_val);
+ size = yyjson_max(pool->chunk_size, size);
+ chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
+ if (unlikely(!chunk)) return false;
+
+ /* insert the new chunk as the head of the linked list */
+ chunk->next = pool->chunks;
+ chunk->chunk_size = size;
+ pool->chunks = chunk;
+ pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
+ pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
+
+ /* the next chunk is twice the size of the current one */
+ size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
+ if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
+ pool->chunk_size = size;
+ return true;
+}
+
+bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
+ usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
+ if (!doc || !len || len > max_size) return false;
+ doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
+ return true;
+}
+
+bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
+ usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
+ if (!doc || !count || count > max_count) return false;
+ doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
+ return true;
+}
+
+void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
+ if (doc) {
+ yyjson_alc alc = doc->alc;
+ memset(&doc->alc, 0, sizeof(alc));
+ unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
+ unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
+ alc.free(alc.ctx, doc);
+ }
+}
+
+yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
+ yyjson_mut_doc *doc;
+ if (!alc) alc = &YYJSON_DEFAULT_ALC;
+ doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
+ if (!doc) return NULL;
+ memset(doc, 0, sizeof(yyjson_mut_doc));
+
+ doc->alc = *alc;
+ doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
+ doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
+ doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
+ doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
+ return doc;
+}
+
+yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc) {
+ yyjson_mut_doc *m_doc;
+ yyjson_mut_val *m_val;
+
+ if (!doc || !doc->root) return NULL;
+ m_doc = yyjson_mut_doc_new(alc);
+ if (!m_doc) return NULL;
+ m_val = yyjson_val_mut_copy(m_doc, doc->root);
+ if (!m_val) {
+ yyjson_mut_doc_free(m_doc);
+ return NULL;
+ }
+ yyjson_mut_doc_set_root(m_doc, m_val);
+ return m_doc;
+}
+
+yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc,
+ const yyjson_alc *alc) {
+ yyjson_mut_doc *m_doc;
+ yyjson_mut_val *m_val;
+
+ if (!doc) return NULL;
+ if (!doc->root) return yyjson_mut_doc_new(alc);
+
+ m_doc = yyjson_mut_doc_new(alc);
+ if (!m_doc) return NULL;
+ m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
+ if (!m_val) {
+ yyjson_mut_doc_free(m_doc);
+ return NULL;
+ }
+ yyjson_mut_doc_set_root(m_doc, m_val);
+ return m_doc;
+}
+
+yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
+ yyjson_val *i_vals) {
+ /*
+ The immutable object or array stores all sub-values in a contiguous memory,
+ We copy them to another contiguous memory as mutable values,
+ then reconnect the mutable values with the original relationship.
+ */
+ usize i_vals_len;
+ yyjson_mut_val *m_vals, *m_val;
+ yyjson_val *i_val, *i_end;
+
+ if (!m_doc || !i_vals) return NULL;
+ i_end = unsafe_yyjson_get_next(i_vals);
+ i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
+ m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
+ if (!m_vals) return NULL;
+ i_val = i_vals;
+ m_val = m_vals;
+
+ for (; i_val < i_end; i_val++, m_val++) {
+ yyjson_type type = unsafe_yyjson_get_type(i_val);
+ m_val->tag = i_val->tag;
+ m_val->uni.u64 = i_val->uni.u64;
+ if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
+ const char *str = i_val->uni.str;
+ usize str_len = unsafe_yyjson_get_len(i_val);
+ m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
+ if (!m_val->uni.str) return NULL;
+ } else if (type == YYJSON_TYPE_ARR) {
+ usize len = unsafe_yyjson_get_len(i_val);
+ if (len > 0) {
+ yyjson_val *ii_val = i_val + 1, *ii_next;
+ yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
+ while (len-- > 1) {
+ ii_next = unsafe_yyjson_get_next(ii_val);
+ mm_next = mm_val + (ii_next - ii_val);
+ mm_val->next = mm_next;
+ ii_val = ii_next;
+ mm_val = mm_next;
+ }
+ mm_val->next = mm_ctn + 1;
+ mm_ctn->uni.ptr = mm_val;
+ }
+ } else if (type == YYJSON_TYPE_OBJ) {
+ usize len = unsafe_yyjson_get_len(i_val);
+ if (len > 0) {
+ yyjson_val *ii_key = i_val + 1, *ii_nextkey;
+ yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
+ yyjson_mut_val *mm_nextkey;
+ while (len-- > 1) {
+ ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
+ mm_nextkey = mm_key + (ii_nextkey - ii_key);
+ mm_key->next = mm_key + 1;
+ mm_key->next->next = mm_nextkey;
+ ii_key = ii_nextkey;
+ mm_key = mm_nextkey;
+ }
+ mm_key->next = mm_key + 1;
+ mm_key->next->next = mm_ctn + 1;
+ mm_ctn->uni.ptr = mm_key;
+ }
+ }
+ }
+ return m_vals;
+}
+
+static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc,
+ yyjson_mut_val *m_vals) {
+ /*
+ The mutable object or array stores all sub-values in a circular linked
+ list, so we can traverse them in the same loop. The traversal starts from
+ the last item, continues with the first item in a list, and ends with the
+ second to last item, which needs to be linked to the last item to close the
+ circle.
+ */
+ yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
+ if (unlikely(!m_val)) return NULL;
+ m_val->tag = m_vals->tag;
+
+ switch (unsafe_yyjson_get_type(m_vals)) {
+ case YYJSON_TYPE_OBJ:
+ case YYJSON_TYPE_ARR:
+ if (unsafe_yyjson_get_len(m_vals) > 0) {
+ yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
+ yyjson_mut_val *next = last->next, *prev;
+ prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
+ if (!prev) return NULL;
+ m_val->uni.ptr = (void *)prev;
+ while (next != last) {
+ prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
+ if (!prev->next) return NULL;
+ prev = prev->next;
+ next = next->next;
+ }
+ prev->next = (yyjson_mut_val *)m_val->uni.ptr;
+ }
+ break;
+ case YYJSON_TYPE_RAW:
+ case YYJSON_TYPE_STR: {
+ const char *str = m_vals->uni.str;
+ usize str_len = unsafe_yyjson_get_len(m_vals);
+ m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
+ if (!m_val->uni.str) return NULL;
+ break;
+ }
+ default:
+ m_val->uni = m_vals->uni;
+ break;
+ }
+ return m_val;
+}
+
+yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
+ yyjson_mut_val *val) {
+ if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
+ return NULL;
+}
+
+/* Count the number of values and the total length of the strings. */
+static void yyjson_mut_stat(yyjson_mut_val *val,
+ usize *val_sum, usize *str_sum) {
+ yyjson_type type = unsafe_yyjson_get_type(val);
+ *val_sum += 1;
+ if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
+ yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
+ usize len = unsafe_yyjson_get_len(val), i;
+ len <<= (u8)(type == YYJSON_TYPE_OBJ);
+ *val_sum += len;
+ for (i = 0; i < len; i++) {
+ yyjson_type stype = unsafe_yyjson_get_type(child);
+ if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
+ *str_sum += unsafe_yyjson_get_len(child) + 1;
+ } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
+ yyjson_mut_stat(child, val_sum, str_sum);
+ *val_sum -= 1;
+ }
+ child = child->next;
+ }
+ } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
+ *str_sum += unsafe_yyjson_get_len(val) + 1;
+ }
+}
+
+/* Copy mutable values to immutable value pool. */
+static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
+ yyjson_mut_val *mval) {
+ yyjson_val *val = *val_ptr;
+ yyjson_type type = unsafe_yyjson_get_type(mval);
+ if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
+ yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
+ usize len = unsafe_yyjson_get_len(mval), i;
+ usize val_sum = 1;
+ if (type == YYJSON_TYPE_OBJ) {
+ if (len) child = child->next->next;
+ len <<= 1;
+ } else {
+ if (len) child = child->next;
+ }
+ *val_ptr = val + 1;
+ for (i = 0; i < len; i++) {
+ val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
+ child = child->next;
+ }
+ val->tag = mval->tag;
+ val->uni.ofs = val_sum * sizeof(yyjson_val);
+ return val_sum;
+ } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
+ char *buf = *buf_ptr;
+ usize len = unsafe_yyjson_get_len(mval);
+ memcpy((void *)buf, (const void *)mval->uni.str, len);
+ buf[len] = '\0';
+ val->tag = mval->tag;
+ val->uni.str = buf;
+ *val_ptr = val + 1;
+ *buf_ptr = buf + len + 1;
+ return 1;
+ } else {
+ val->tag = mval->tag;
+ val->uni = mval->uni;
+ *val_ptr = val + 1;
+ return 1;
+ }
+}
+
+yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *mdoc,
+ const yyjson_alc *alc) {
+ if (!mdoc) return NULL;
+ return yyjson_mut_val_imut_copy(mdoc->root, alc);
+}
+
+yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *mval,
+ const yyjson_alc *alc) {
+ usize val_num = 0, str_sum = 0, hdr_size, buf_size;
+ yyjson_doc *doc = NULL;
+ yyjson_val *val_hdr = NULL;
+
+ /* This value should be NULL here. Setting a non-null value suppresses
+ warning from the clang analyzer. */
+ char *str_hdr = (char *)(void *)&str_sum;
+ if (!mval) return NULL;
+ if (!alc) alc = &YYJSON_DEFAULT_ALC;
+
+ /* traverse the input value to get pool size */
+ yyjson_mut_stat(mval, &val_num, &str_sum);
+
+ /* create doc and val pool */
+ hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
+ buf_size = hdr_size + val_num * sizeof(yyjson_val);
+ doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
+ if (!doc) return NULL;
+ memset(doc, 0, sizeof(yyjson_doc));
+ val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
+ doc->root = val_hdr;
+ doc->alc = *alc;
+
+ /* create str pool */
+ if (str_sum > 0) {
+ str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
+ doc->str_pool = str_hdr;
+ if (!str_hdr) {
+ alc->free(alc->ctx, (void *)doc);
+ return NULL;
+ }
+ }
+
+ /* copy vals and strs */
+ doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
+ doc->dat_read = str_sum + 1;
+ return doc;
+}
+
+static_inline bool unsafe_yyjson_num_equals(void *lhs, void *rhs) {
+ yyjson_val_uni *luni = &((yyjson_val *)lhs)->uni;
+ yyjson_val_uni *runi = &((yyjson_val *)rhs)->uni;
+ yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
+ yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
+ if (lt == rt) return luni->u64 == runi->u64;
+ if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
+ return luni->i64 >= 0 && luni->u64 == runi->u64;
+ }
+ if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
+ return runi->i64 >= 0 && luni->u64 == runi->u64;
+ }
+ return false;
+}
+
+static_inline bool unsafe_yyjson_str_equals(void *lhs, void *rhs) {
+ usize len = unsafe_yyjson_get_len(lhs);
+ if (len != unsafe_yyjson_get_len(rhs)) return false;
+ return !memcmp(unsafe_yyjson_get_str(lhs),
+ unsafe_yyjson_get_str(rhs), len);
+}
+
+bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) {
+ yyjson_type type = unsafe_yyjson_get_type(lhs);
+ if (type != unsafe_yyjson_get_type(rhs)) return false;
+
+ switch (type) {
+ case YYJSON_TYPE_OBJ: {
+ usize len = unsafe_yyjson_get_len(lhs);
+ if (len != unsafe_yyjson_get_len(rhs)) return false;
+ if (len > 0) {
+ yyjson_obj_iter iter;
+ yyjson_obj_iter_init(rhs, &iter);
+ lhs = unsafe_yyjson_get_first(lhs);
+ while (len-- > 0) {
+ rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
+ unsafe_yyjson_get_len(lhs));
+ if (!rhs) return false;
+ if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
+ lhs = unsafe_yyjson_get_next(lhs + 1);
+ }
+ }
+ /* yyjson allows duplicate keys, so the check may be inaccurate */
+ return true;
+ }
+
+ case YYJSON_TYPE_ARR: {
+ usize len = unsafe_yyjson_get_len(lhs);
+ if (len != unsafe_yyjson_get_len(rhs)) return false;
+ if (len > 0) {
+ lhs = unsafe_yyjson_get_first(lhs);
+ rhs = unsafe_yyjson_get_first(rhs);
+ while (len-- > 0) {
+ if (!unsafe_yyjson_equals(lhs, rhs)) return false;
+ lhs = unsafe_yyjson_get_next(lhs);
+ rhs = unsafe_yyjson_get_next(rhs);
+ }
+ }
+ return true;
+ }
+
+ case YYJSON_TYPE_NUM:
+ return unsafe_yyjson_num_equals(lhs, rhs);
+
+ case YYJSON_TYPE_RAW:
+ case YYJSON_TYPE_STR:
+ return unsafe_yyjson_str_equals(lhs, rhs);
+
+ case YYJSON_TYPE_NULL:
+ case YYJSON_TYPE_BOOL:
+ return lhs->tag == rhs->tag;
+
+ default:
+ return false;
+ }
+}
+
+bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, yyjson_mut_val *rhs) {
+ yyjson_type type = unsafe_yyjson_get_type(lhs);
+ if (type != unsafe_yyjson_get_type(rhs)) return false;
+
+ switch (type) {
+ case YYJSON_TYPE_OBJ: {
+ usize len = unsafe_yyjson_get_len(lhs);
+ if (len != unsafe_yyjson_get_len(rhs)) return false;
+ if (len > 0) {
+ yyjson_mut_obj_iter iter;
+ yyjson_mut_obj_iter_init(rhs, &iter);
+ lhs = (yyjson_mut_val *)lhs->uni.ptr;
+ while (len-- > 0) {
+ rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
+ unsafe_yyjson_get_len(lhs));
+ if (!rhs) return false;
+ if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
+ lhs = lhs->next->next;
+ }
+ }
+ /* yyjson allows duplicate keys, so the check may be inaccurate */
+ return true;
+ }
+
+ case YYJSON_TYPE_ARR: {
+ usize len = unsafe_yyjson_get_len(lhs);
+ if (len != unsafe_yyjson_get_len(rhs)) return false;
+ if (len > 0) {
+ lhs = (yyjson_mut_val *)lhs->uni.ptr;
+ rhs = (yyjson_mut_val *)rhs->uni.ptr;
+ while (len-- > 0) {
+ if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
+ lhs = lhs->next;
+ rhs = rhs->next;
+ }
+ }
+ return true;
+ }
+
+ case YYJSON_TYPE_NUM:
+ return unsafe_yyjson_num_equals(lhs, rhs);
+
+ case YYJSON_TYPE_RAW:
+ case YYJSON_TYPE_STR:
+ return unsafe_yyjson_str_equals(lhs, rhs);
+
+ case YYJSON_TYPE_NULL:
+ case YYJSON_TYPE_BOOL:
+ return lhs->tag == rhs->tag;
+
+ default:
+ return false;
+ }
+}
+
+bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
+ size_t *line, size_t *col, size_t *chr) {
+ usize line_sum = 0, line_pos = 0, chr_sum = 0;
+ const u8 *cur = (const u8 *)str;
+ const u8 *end = cur + pos;
+
+ if (!str || pos > len) {
+ if (line) *line = 0;
+ if (col) *col = 0;
+ if (chr) *chr = 0;
+ return false;
+ }
+
+ if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
+ while (cur < end) {
+ u8 c = *cur;
+ chr_sum += 1;
+ if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
+ if (c == '\n') {
+ line_sum += 1;
+ line_pos = chr_sum;
+ }
+ cur += 1;
+ }
+ else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
+ else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
+ else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
+ else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
+ else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
+ }
+ if (line) *line = line_sum + 1;
+ if (col) *col = chr_sum - line_pos + 1;
+ if (chr) *chr = chr_sum;
+ return true;
+}
+
+
+
+#if !YYJSON_DISABLE_READER /* reader begin */
+
+/* Check read flag, avoids `always false` warning when disabled. */
+#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
+#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
+#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
+ YYJSON_READ_ALLOW_EXT_WHITESPACE)
+static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
+ bool non_standard) {
+#if YYJSON_DISABLE_NON_STANDARD
+ if (non_standard) return false;
+#endif
+ return (flg & chk) != 0;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Reader Utils (Private)
+ * These functions are used by JSON reader to read literals and comments.
+ *============================================================================*/
+
+/** Read `true` literal, `*ptr[0]` should be `t`. */
+static_inline bool read_true(u8 **ptr, yyjson_val *val) {
+ u8 *cur = *ptr;
+ if (likely(byte_match_4(cur, "true"))) {
+ val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
+ *ptr = cur + 4;
+ return true;
+ }
+ return false;
+}
+
+/** Read `false` literal, `*ptr[0]` should be `f`. */
+static_inline bool read_false(u8 **ptr, yyjson_val *val) {
+ u8 *cur = *ptr;
+ if (likely(byte_match_4(cur + 1, "alse"))) {
+ val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
+ *ptr = cur + 5;
+ return true;
+ }
+ return false;
+}
+
+/** Read `null` literal, `*ptr[0]` should be `n`. */
+static_inline bool read_null(u8 **ptr, yyjson_val *val) {
+ u8 *cur = *ptr;
+ if (likely(byte_match_4(cur, "null"))) {
+ val->tag = YYJSON_TYPE_NULL;
+ *ptr = cur + 4;
+ return true;
+ }
+ return false;
+}
+
+/** Read `Inf` or `Infinity` literal (ignoring case). */
+static_inline bool read_inf(u8 **ptr, u8 **pre,
+ yyjson_read_flag flg, yyjson_val *val) {
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+ bool sign = (*cur == '-');
+ if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
+ cur += char_is_sign(*cur);
+ if (char_to_lower(cur[0]) == 'i' &&
+ char_to_lower(cur[1]) == 'n' &&
+ char_to_lower(cur[2]) == 'f') {
+ if (char_to_lower(cur[3]) == 'i') {
+ if (char_to_lower(cur[4]) == 'n' &&
+ char_to_lower(cur[5]) == 'i' &&
+ char_to_lower(cur[6]) == 't' &&
+ char_to_lower(cur[7]) == 'y') {
+ cur += 8;
+ } else {
+ return false;
+ }
+ } else {
+ cur += 3;
+ }
+ *end = cur;
+ if (has_flg(NUMBER_AS_RAW)) {
+ **pre = '\0'; /* add null-terminator for previous raw string */
+ *pre = cur; /* save end position for current raw string */
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
+ val->uni.str = (const char *)hdr;
+ } else {
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
+ val->uni.u64 = f64_bits_inf(sign);
+ }
+ return true;
+ }
+ return false;
+}
+
+/** Read `NaN` literal (ignoring case). */
+static_inline bool read_nan(u8 **ptr, u8 **pre,
+ yyjson_read_flag flg, yyjson_val *val) {
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+ bool sign = (*cur == '-');
+ if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
+ cur += char_is_sign(*cur);
+ if (char_to_lower(cur[0]) == 'n' &&
+ char_to_lower(cur[1]) == 'a' &&
+ char_to_lower(cur[2]) == 'n') {
+ cur += 3;
+ *end = cur;
+ if (has_flg(NUMBER_AS_RAW)) {
+ **pre = '\0'; /* add null-terminator for previous raw string */
+ *pre = cur; /* save end position for current raw string */
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
+ val->uni.str = (const char *)hdr;
+ } else {
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
+ val->uni.u64 = f64_bits_nan(sign);
+ }
+ return true;
+ }
+ return false;
+}
+
+/** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
+static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre,
+ yyjson_read_flag flg, yyjson_val *val) {
+ if (read_inf(ptr, pre, flg, val)) return true;
+ if (read_nan(ptr, pre, flg, val)) return true;
+ return false;
+}
+
+/** Read a JSON number as raw string. */
+static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+#define return_err(_pos, _msg) do { \
+ *msg = _msg; *end = _pos; return false; \
+} while (false)
+
+#define return_raw() do { \
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
+ val->uni.str = (const char *)hdr; \
+ **pre = '\0'; *pre = cur; *end = cur; return true; \
+} while (false)
+
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+
+ /* skip sign */
+ cur += (*cur == '-');
+
+ /* read first digit, check leading zero */
+ while (unlikely(!char_is_digit(*cur))) {
+ if (has_allow(EXT_NUMBER)) {
+ if (*cur == '+' && cur == hdr) { /* leading `+` sign */
+ cur++;
+ continue;
+ }
+ if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
+ goto read_double;
+ }
+ }
+ if (has_allow(INF_AND_NAN)) {
+ if (read_inf_or_nan(ptr, pre, flg, val)) return true;
+ }
+ return_err(cur, "no digit after sign");
+ }
+
+ /* read integral part */
+ if (*cur == '0') {
+ cur++;
+ if (unlikely(char_is_digit(*cur))) {
+ return_err(cur - 1, "number with leading zero is not allowed");
+ }
+ if (!char_is_fp(*cur)) {
+ if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
+ if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
+ while(char_is_hex(*cur)) cur++;
+ }
+ return_raw();
+ }
+ } else {
+ while (char_is_digit(*cur)) cur++;
+ if (!char_is_fp(*cur)) return_raw();
+ }
+
+read_double:
+ /* read fraction part */
+ if (*cur == '.') {
+ cur++;
+ if (!char_is_digit(*cur)) {
+ if (has_allow(EXT_NUMBER)) {
+ if (!char_is_exp(*cur)) return_raw();
+ } else {
+ return_err(cur, "no digit after decimal point");
+ }
+ }
+ while (char_is_digit(*cur)) cur++;
+ }
+
+ /* read exponent part */
+ if (char_is_exp(*cur)) {
+ cur += 1 + char_is_sign(cur[1]);
+ if (!char_is_digit(*cur++)) {
+ return_err(cur, "no digit after exponent sign");
+ }
+ while (char_is_digit(*cur)) cur++;
+ }
+
+ return_raw();
+
+#undef return_err
+#undef return_raw
+}
+
+/** Read a hex number. */
+static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+ u64 sig = 0, i = 0;
+ bool sign;
+
+ /* skip sign and '0x' */
+ sign = (*cur == '-');
+ cur += (*cur == '-' || *cur == '+') + 2;
+
+ /* read hex */
+ for(; i < 16; i++) {
+ u8 c = hex_conv_table[cur[i]];
+ if (c == 0xF0) break;
+ sig <<= 4;
+ sig |= c;
+ }
+
+ /* check error */
+ if (unlikely(i == 0)) {
+ *msg = "invalid hex number";
+ return false;
+ }
+
+ /* check overflow */
+ if (unlikely(i == 16)) {
+ if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
+ if (!has_flg(BIGNUM_AS_RAW)) {
+ *msg = "hex number overflow";
+ return false;
+ }
+ cur += 16;
+ while (char_is_hex(*cur)) cur++;
+ **pre = '\0';
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
+ val->uni.str = (const char *)hdr;
+ *pre = cur; *end = cur;
+ return true;
+ }
+ }
+
+ val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
+ val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
+ *end = cur + i;
+ return true;
+}
+
+/**
+ Skip trivia (whitespace and comments).
+ This function should be used only when `char_is_trivia()` returns true.
+ @param ptr (inout) Input current position, output end position.
+ @param eof JSON end position.
+ @param flg JSON read flags.
+ @return true if at least one character was skipped.
+ false if no characters were skipped,
+ or if a multi-line comment is unterminated;
+ in the latter case, `ptr` will be set to `eof`.
+ */
+static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) {
+ u8 *hdr = *ptr, *cur = *ptr;
+ usize len;
+
+ while (cur < eof) {
+ u8 *loop_begin = cur;
+
+ /* skip standard whitespace */
+ while(char_is_space(*cur)) cur++;
+
+ /* skip extended whitespace */
+ if (has_allow(EXT_WHITESPACE)) {
+ while (char_is_space_ext(*cur)) {
+ cur += (len = ext_space_len(cur));
+ if (!len) break;
+ }
+ }
+
+ /* skip comment, do not validate encoding */
+ if (has_allow(COMMENTS) && cur[0] == '/') {
+ if (cur[1] == '/') { /* single-line comment */
+ cur += 2;
+ if (has_allow(EXT_WHITESPACE)) {
+ while (cur < eof) {
+ if (char_is_eol_ext(*cur)) {
+ cur += (len = ext_eol_len(cur));
+ if (len) break;
+ }
+ cur++;
+ }
+ } else {
+ while (cur < eof && !char_is_eol(*cur)) cur++;
+ }
+ } else if (cur[1] == '*') { /* multi-line comment */
+ cur += 2;
+ while (!byte_match_2(cur, "*/") && cur < eof) cur++;
+ if (cur == eof) {
+ *ptr = eof;
+ return false; /* unclosed comment */
+ }
+ cur += 2;
+ }
+ }
+ if (cur == loop_begin) break;
+ }
+ *ptr = cur;
+ return cur > hdr;
+}
+
+/**
+ Check truncated UTF-8 character.
+ Return true if `cur` starts a valid UTF-8 sequence that is truncated.
+ */
+static bool is_truncated_utf8(u8 *cur, u8 *eof) {
+ u8 c0, c1, c2;
+ usize len = (usize)(eof - cur);
+ if (cur >= eof || len >= 4) return false;
+ c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
+ /* 1-byte UTF-8, not truncated */
+ if (c0 < 0x80) return false;
+ if (len == 1) {
+ /* 2-byte UTF-8, truncated */
+ if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
+ /* 3-byte UTF-8, truncated */
+ if ((c0 & 0xF0) == 0xE0) return true;
+ /* 4-byte UTF-8, truncated */
+ if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
+ } else if (len == 2) {
+ /* 3-byte UTF-8, truncated */
+ if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
+ u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
+ return 0x01 <= t && t != 0x1B;
+ }
+ /* 4-byte UTF-8, truncated */
+ if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
+ u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
+ return 0x01 <= t && t <= 0x10;
+ }
+ } else if (len == 3) {
+ /* 4 bytes UTF-8, truncated */
+ if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
+ u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
+ return 0x01 <= t && t <= 0x10;
+ }
+ }
+ return false;
+}
+
+/**
+ Check truncated string.
+ Returns true if `cur` match `str` but is truncated.
+ The `str` should be lowercase ASCII letters.
+ */
+static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
+ bool case_sensitive) {
+ usize len = strlen(str);
+ if (cur + len <= eof || eof <= cur) return false;
+ if (case_sensitive) {
+ return memcmp(cur, str, (usize)(eof - cur)) == 0;
+ }
+ for (; cur < eof; cur++, str++) {
+ if (char_to_lower(*cur) != *(const u8 *)str) return false;
+ }
+ return true;
+}
+
+/**
+ Check truncated JSON on parsing errors.
+ Returns true if the input is valid but truncated.
+ */
+static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof,
+ yyjson_read_code code,
+ yyjson_read_flag flg) {
+ if (cur >= eof) return true;
+ if (code == YYJSON_READ_ERROR_LITERAL) {
+ if (is_truncated_str(cur, eof, "true", true) ||
+ is_truncated_str(cur, eof, "false", true) ||
+ is_truncated_str(cur, eof, "null", true)) {
+ return true;
+ }
+ }
+ if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
+ code == YYJSON_READ_ERROR_INVALID_NUMBER ||
+ code == YYJSON_READ_ERROR_LITERAL) {
+ if (has_allow(INF_AND_NAN)) {
+ if (*cur == '-') cur++;
+ if (is_truncated_str(cur, eof, "infinity", false) ||
+ is_truncated_str(cur, eof, "nan", false)) {
+ return true;
+ }
+ }
+ }
+ if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
+ if (has_allow(INF_AND_NAN)) {
+ if (hdr + 3 <= cur &&
+ is_truncated_str(cur - 3, eof, "infinity", false)) {
+ return true; /* e.g. infin would be read as inf + in */
+ }
+ }
+ }
+ if (code == YYJSON_READ_ERROR_INVALID_STRING) {
+ usize len = (usize)(eof - cur);
+
+ /* unicode escape sequence */
+ if (*cur == '\\') {
+ if (len == 1) return true;
+ if (len <= 5) {
+ if (*++cur != 'u') return false;
+ for (++cur; cur < eof; cur++) {
+ if (!char_is_hex(*cur)) return false;
+ }
+ return true;
+ } else if (len <= 11) {
+ /* incomplete surrogate pair? */
+ u16 hi;
+ if (*++cur != 'u') return false;
+ if (!hex_load_4(++cur, &hi)) return false;
+ if ((hi & 0xF800) != 0xD800) return false;
+ cur += 4;
+ if (cur >= eof) return true;
+ /* valid low surrogate is DC00...DFFF */
+ if (*cur != '\\') return false;
+ if (++cur >= eof) return true;
+ if (*cur != 'u') return false;
+ if (++cur >= eof) return true;
+ if (*cur != 'd' && *cur != 'D') return false;
+ if (++cur >= eof) return true;
+ if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
+ return false;
+ if (++cur >= eof) return true;
+ if (!char_is_hex(*cur)) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /* 2 to 4 bytes UTF-8 */
+ if (is_truncated_utf8(cur, eof)) {
+ return true;
+ }
+ }
+ if (has_allow(COMMENTS)) {
+ if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
+ /* unclosed multiline comment */
+ return true;
+ }
+ if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
+ *cur == '/' && cur + 1 == eof) {
+ /* truncated beginning of comment */
+ return true;
+ }
+ }
+ if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
+ has_allow(BOM)) {
+ /* truncated UTF-8 BOM */
+ usize len = (usize)(eof - cur);
+ if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
+
+/*==============================================================================
+ * MARK: - BigInt For Floating Point Number Reader (Private)
+ *
+ * The bigint algorithm is used by floating-point number reader to get correctly
+ * rounded result for numbers with lots of digits. This part of code is rarely
+ * used for common numbers.
+ *============================================================================*/
+
+/** Unsigned arbitrarily large integer */
+typedef struct bigint {
+ u32 used; /* used chunks count, should not be 0 */
+ u64 bits[64]; /* chunks (58 is enough here) */
+} bigint;
+
+/**
+ Evaluate 'big += val'.
+ @param big A big number (can be 0).
+ @param val An unsigned integer (can be 0).
+ */
+static_inline void bigint_add_u64(bigint *big, u64 val) {
+ u32 idx, max;
+ u64 num = big->bits[0];
+ u64 add = num + val;
+ big->bits[0] = add;
+ if (likely((add >= num) || (add >= val))) return;
+ for ((void)(idx = 1), max = big->used; idx < max; idx++) {
+ if (likely(big->bits[idx] != U64_MAX)) {
+ big->bits[idx] += 1;
+ return;
+ }
+ big->bits[idx] = 0;
+ }
+ big->bits[big->used++] = 1;
+}
+
+/**
+ Evaluate 'big *= val'.
+ @param big A big number (can be 0).
+ @param val An unsigned integer (cannot be 0).
+ */
+static_inline void bigint_mul_u64(bigint *big, u64 val) {
+ u32 idx = 0, max = big->used;
+ u64 hi, lo, carry = 0;
+ for (; idx < max; idx++) {
+ if (big->bits[idx]) break;
+ }
+ for (; idx < max; idx++) {
+ u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
+ big->bits[idx] = lo;
+ carry = hi;
+ }
+ if (carry) big->bits[big->used++] = carry;
+}
+
+/**
+ Evaluate 'big *= 2^exp'.
+ @param big A big number (can be 0).
+ @param exp An exponent integer (can be 0).
+ */
+static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
+ u32 shft = exp % 64;
+ u32 move = exp / 64;
+ u32 idx = big->used;
+ if (unlikely(shft == 0)) {
+ for (; idx > 0; idx--) {
+ big->bits[idx + move - 1] = big->bits[idx - 1];
+ }
+ big->used += move;
+ while (move) big->bits[--move] = 0;
+ } else {
+ big->bits[idx] = 0;
+ for (; idx > 0; idx--) {
+ u64 num = big->bits[idx] << shft;
+ num |= big->bits[idx - 1] >> (64 - shft);
+ big->bits[idx + move] = num;
+ }
+ big->bits[move] = big->bits[0] << shft;
+ big->used += move + (big->bits[big->used + move] > 0);
+ while (move) big->bits[--move] = 0;
+ }
+}
+
+/**
+ Evaluate 'big *= 10^exp'.
+ @param big A big number (can be 0).
+ @param exp An exponent integer (cannot be 0).
+ */
+static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
+ for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
+ bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
+ }
+ if (exp) {
+ bigint_mul_u64(big, u64_pow10_table[exp]);
+ }
+}
+
+/**
+ Compare two bigint.
+ @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
+ */
+static_inline i32 bigint_cmp(bigint *a, bigint *b) {
+ u32 idx = a->used;
+ if (a->used < b->used) return -1;
+ if (a->used > b->used) return +1;
+ while (idx-- > 0) {
+ u64 av = a->bits[idx];
+ u64 bv = b->bits[idx];
+ if (av < bv) return -1;
+ if (av > bv) return +1;
+ }
+ return 0;
+}
+
+/**
+ Evaluate 'big = val'.
+ @param big A big number (can be 0).
+ @param val An unsigned integer (can be 0).
+ */
+static_inline void bigint_set_u64(bigint *big, u64 val) {
+ big->used = 1;
+ big->bits[0] = val;
+}
+
+/** Set a bigint with floating point number string. */
+static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
+ u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
+
+ if (unlikely(!sig_cut)) {
+ /* no digit cut, set significant part only */
+ bigint_set_u64(big, sig);
+ return;
+
+ } else {
+ /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
+ u8 *hdr = sig_cut;
+ u8 *cur = hdr;
+ u32 len = 0;
+ u64 val = 0;
+ bool dig_big_cut = false;
+ bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
+ u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
+
+ sig -= (*sig_cut >= '5'); /* sig was rounded before */
+ if (dig_len_total > F64_MAX_DEC_DIG) {
+ dig_big_cut = true;
+ sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
+ sig_end -= (dot_pos + 1 == sig_end);
+ dig_len_total = (F64_MAX_DEC_DIG + 1);
+ }
+ *exp -= (i32)dig_len_total - U64_SAFE_DIG;
+
+ big->used = 1;
+ big->bits[0] = sig;
+ while (cur < sig_end) {
+ if (likely(cur != dot_pos)) {
+ val = val * 10 + (u8)(*cur++ - '0');
+ len++;
+ if (unlikely(cur == sig_end && dig_big_cut)) {
+ /* The last digit must be non-zero, */
+ /* set it to '1' for correct rounding. */
+ val = val - (val % 10) + 1;
+ }
+ if (len == U64_SAFE_DIG || cur == sig_end) {
+ bigint_mul_pow10(big, (i32)len);
+ bigint_add_u64(big, val);
+ val = 0;
+ len = 0;
+ }
+ } else {
+ cur++;
+ }
+ }
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - Diy Floating Point (Private)
+ *============================================================================*/
+
+/** "Do It Yourself Floating Point" struct. */
+typedef struct diy_fp {
+ u64 sig; /* significand */
+ i32 exp; /* exponent, base 2 */
+ i32 pad; /* padding, useless */
+} diy_fp;
+
+/** Get cached rounded diy_fp with pow(10, e) The input value must in range
+ [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
+static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
+ diy_fp fp;
+ u64 sig_ext;
+ pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
+ pow10_table_get_exp(exp10, &fp.exp);
+ fp.sig += (sig_ext >> 63);
+ return fp;
+}
+
+/** Returns fp * fp2. */
+static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
+ u64 hi, lo;
+ u128_mul(fp.sig, fp2.sig, &hi, &lo);
+ fp.sig = hi + (lo >> 63);
+ fp.exp += fp2.exp + 64;
+ return fp;
+}
+
+/** Convert diy_fp to IEEE-754 raw value. */
+static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
+ u64 sig = fp.sig;
+ i32 exp = fp.exp;
+ u32 lz_bits;
+ if (unlikely(fp.sig == 0)) return 0;
+
+ lz_bits = u64_lz_bits(sig);
+ sig <<= lz_bits;
+ sig >>= F64_BITS - F64_SIG_FULL_BITS;
+ exp -= (i32)lz_bits;
+ exp += F64_BITS - F64_SIG_FULL_BITS;
+ exp += F64_SIG_BITS;
+
+ if (unlikely(exp >= F64_MAX_BIN_EXP)) {
+ /* overflow */
+ return F64_BITS_INF;
+ } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
+ /* normal */
+ exp += F64_EXP_BIAS;
+ return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
+ } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
+ /* subnormal */
+ return sig >> (F64_MIN_BIN_EXP - exp - 1);
+ } else {
+ /* underflow */
+ return 0;
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - Number Reader (Private)
+ *============================================================================*/
+
+/**
+ Read a JSON number.
+
+ 1. This function assume that the floating-point number is in IEEE-754 format.
+ 2. This function support uint64/int64/double number. If an integer number
+ cannot fit in uint64/int64, it will returns as a double number. If a double
+ number is infinite, the return value is based on flag.
+ 3. This function (with inline attribute) may generate a lot of instructions.
+ */
+static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+#define return_err(_pos, _msg) do { \
+ *msg = _msg; \
+ *end = _pos; \
+ return false; \
+} while (false)
+
+#define return_0() do { \
+ val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
+ val->uni.u64 = 0; \
+ *end = cur; return true; \
+} while (false)
+
+#define return_i64(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
+ val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_f64(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
+ val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_f64_bin(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
+ val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_inf() do { \
+ if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
+ if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
+ else return_err(hdr, "number is infinity when parsed as double"); \
+} while (false)
+
+#define return_raw() do { \
+ **pre = '\0'; /* add null-terminator for previous raw string */ \
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
+ val->uni.str = (const char *)hdr; \
+ *pre = cur; *end = cur; return true; \
+} while (false)
+
+ u8 *sig_cut = NULL; /* significant part cutting position for long number */
+ u8 *sig_end = NULL; /* significant part ending position */
+ u8 *dot_pos = NULL; /* decimal point position */
+
+ u64 sig = 0; /* significant part of the number */
+ i32 exp = 0; /* exponent part of the number */
+
+ bool exp_sign; /* temporary exponent sign from literal part */
+ i64 exp_sig = 0; /* temporary exponent number from significant part */
+ i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
+ u64 num; /* temporary number for reading */
+ u8 *tmp; /* temporary cursor for reading */
+
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+ bool sign;
+
+ /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
+ if (has_flg(NUMBER_AS_RAW)) {
+ return read_num_raw(ptr, pre, flg, val, msg);
+ }
+
+ sign = (*hdr == '-');
+ cur += sign;
+
+ /* begin with a leading zero or non-digit */
+ while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
+ if (unlikely(*cur != '0')) { /* non-digit char */
+ if (has_allow(EXT_NUMBER)) {
+ if (*cur == '+' && cur == hdr) { /* leading `+` sign */
+ cur++;
+ continue;
+ }
+ if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
+ goto leading_dot;
+ }
+ }
+ if (has_allow(INF_AND_NAN)) {
+ if (read_inf_or_nan(ptr, pre, flg, val)) return true;
+ }
+ return_err(cur, "no digit after sign");
+ }
+ /* begin with 0 */
+ if (likely(!char_is_digit_or_fp(*++cur))) {
+ if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
+ return read_num_hex(ptr, pre, flg, val, msg);
+ }
+ return_0();
+ }
+ if (likely(*cur == '.')) {
+leading_dot:
+ dot_pos = cur++;
+ if (unlikely(!char_is_digit(*cur))) {
+ if (has_allow(EXT_NUMBER)) {
+ if (char_is_exp(*cur)) {
+ goto digi_exp_more;
+ } else {
+ return_f64_bin(0);
+ }
+ }
+ return_err(cur, "no digit after decimal point");
+ }
+ while (unlikely(*cur == '0')) cur++;
+ if (likely(char_is_digit(*cur))) {
+ /* first non-zero digit after decimal point */
+ sig = (u64)(*cur - '0'); /* read first digit */
+ cur--;
+ goto digi_frac_1; /* continue read fraction part */
+ }
+ }
+ if (unlikely(char_is_digit(*cur))) {
+ return_err(cur - 1, "number with leading zero is not allowed");
+ }
+ if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
+ cur += (usize)1 + char_is_sign(cur[1]);
+ if (unlikely(!char_is_digit(*cur))) {
+ return_err(cur, "no digit after exponent sign");
+ }
+ while (char_is_digit(*++cur));
+ }
+ return_f64_bin(0);
+ }
+
+ /* begin with non-zero digit */
+ sig = (u64)(*cur - '0');
+
+ /*
+ Read integral part, same as the following code.
+
+ for (int i = 1; i <= 18; i++) {
+ num = cur[i] - '0';
+ if (num <= 9) sig = num + sig * 10;
+ else goto digi_sepr_i;
+ }
+ */
+#define expr_intg(i) \
+ if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
+ else { goto digi_sepr_##i; }
+ repeat_in_1_18(expr_intg)
+#undef expr_intg
+
+
+ cur += 19; /* skip continuous 19 digits */
+ if (!char_is_digit_or_fp(*cur)) {
+ /* this number is an integer consisting of 19 digits */
+ if (sign && (sig > ((u64)1 << 63))) { /* overflow */
+ if (has_flg(BIGNUM_AS_RAW)) return_raw();
+ return_f64(unsafe_yyjson_u64_to_f64(sig));
+ }
+ return_i64(sig);
+ }
+ goto digi_intg_more; /* read more digits in integral part */
+
+
+ /* process first non-digit character */
+#define expr_sepr(i) \
+ digi_sepr_##i: \
+ if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
+ dot_pos = cur + i; \
+ if (likely(cur[i] == '.')) goto digi_frac_##i; \
+ cur += i; sig_end = cur; goto digi_exp_more;
+ repeat_in_1_18(expr_sepr)
+#undef expr_sepr
+
+
+ /* read fraction part */
+#define expr_frac(i) \
+ digi_frac_##i: \
+ if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
+ sig = num + sig * 10; \
+ else { goto digi_stop_##i; }
+ repeat_in_1_18(expr_frac)
+#undef expr_frac
+
+ cur += 20; /* skip 19 digits and 1 decimal point */
+ if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
+ goto digi_frac_more; /* read more digits in fraction part */
+
+
+ /* significant part end */
+#define expr_stop(i) \
+ digi_stop_##i: \
+ cur += i + 1; \
+ goto digi_frac_end;
+ repeat_in_1_18(expr_stop)
+#undef expr_stop
+
+
+ /* read more digits in integral part */
+digi_intg_more:
+ if (char_is_digit(*cur)) {
+ if (!char_is_digit_or_fp(cur[1])) {
+ /* this number is an integer consisting of 20 digits */
+ num = (u64)(*cur - '0');
+ if ((sig < (U64_MAX / 10)) ||
+ (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
+ sig = num + sig * 10;
+ cur++;
+ /* convert to double if overflow */
+ if (sign) {
+ if (has_flg(BIGNUM_AS_RAW)) return_raw();
+ return_f64(unsafe_yyjson_u64_to_f64(sig));
+ }
+ return_i64(sig);
+ }
+ }
+ }
+
+ if (char_is_exp(*cur)) {
+ dot_pos = cur;
+ goto digi_exp_more;
+ }
+
+ if (*cur == '.') {
+ dot_pos = cur++;
+ if (unlikely(!char_is_digit(*cur))) {
+ if (has_allow(EXT_NUMBER)) {
+ goto digi_frac_end;
+ }
+ return_err(cur, "no digit after decimal point");
+ }
+ }
+
+
+ /* read more digits in fraction part */
+digi_frac_more:
+ sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
+ sig += (*cur >= '5'); /* round */
+ while (char_is_digit(*++cur));
+ if (!dot_pos) {
+ if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
+ return_raw(); /* it's a large integer */
+ }
+ dot_pos = cur;
+ if (*cur == '.') {
+ if (unlikely(!char_is_digit(*++cur))) {
+ if (!has_allow(EXT_NUMBER)) {
+ return_err(cur, "no digit after decimal point");
+ }
+ }
+ while (char_is_digit(*cur)) cur++;
+ }
+ }
+ exp_sig = (i64)(dot_pos - sig_cut);
+ exp_sig += (dot_pos < sig_cut);
+
+ /* ignore trailing zeros */
+ tmp = cur - 1;
+ while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
+ if (tmp < sig_cut) {
+ sig_cut = NULL;
+ } else {
+ sig_end = cur;
+ }
+
+ if (char_is_exp(*cur)) goto digi_exp_more;
+ goto digi_exp_finish;
+
+
+ /* fraction part end */
+digi_frac_end:
+ if (unlikely(dot_pos + 1 == cur)) {
+ if (!has_allow(EXT_NUMBER)) {
+ return_err(cur, "no digit after decimal point");
+ }
+ }
+ sig_end = cur;
+ exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
+ if (likely(!char_is_exp(*cur))) {
+ if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
+ return_f64_bin(0); /* underflow */
+ }
+ exp = (i32)exp_sig;
+ goto digi_finish;
+ } else {
+ goto digi_exp_more;
+ }
+
+
+ /* read exponent part */
+digi_exp_more:
+ exp_sign = (*++cur == '-');
+ cur += char_is_sign(*cur);
+ if (unlikely(!char_is_digit(*cur))) {
+ return_err(cur, "no digit after exponent sign");
+ }
+ while (*cur == '0') cur++;
+
+ /* read exponent literal */
+ tmp = cur;
+ while (char_is_digit(*cur)) {
+ exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
+ }
+ if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
+ if (exp_sign) {
+ return_f64_bin(0); /* underflow */
+ } else {
+ return_inf(); /* overflow */
+ }
+ }
+ exp_sig += exp_sign ? -exp_lit : exp_lit;
+
+
+ /* validate exponent value */
+digi_exp_finish:
+ if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
+ return_f64_bin(0); /* underflow */
+ }
+ if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
+ return_inf(); /* overflow */
+ }
+ exp = (i32)exp_sig;
+
+
+ /* all digit read finished */
+digi_finish:
+
+ /*
+ Fast path 1:
+
+ 1. The floating-point number calculation should be accurate, see the
+ comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
+ 2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
+ 3. The input of floating point number calculation does not lose precision,
+ which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
+
+ We don't check all available inputs here, because that would make the code
+ more complicated, and not friendly to branch predictor.
+ */
+#if YYJSON_DOUBLE_MATH_CORRECT
+ if (sig < ((u64)1 << 53) &&
+ exp >= -F64_POW10_MAX_EXACT_EXP &&
+ exp <= +F64_POW10_MAX_EXACT_EXP) {
+ f64 dbl = (f64)sig;
+ if (exp < 0) {
+ dbl /= f64_pow10_table[-exp];
+ } else {
+ dbl *= f64_pow10_table[+exp];
+ }
+ return_f64(dbl);
+ }
+#endif
+
+ /*
+ Fast path 2:
+
+ To keep it simple, we only accept normal number here,
+ let the slow path to handle subnormal and infinity number.
+ */
+ if (likely(!sig_cut &&
+ exp > -F64_MAX_DEC_EXP + 1 &&
+ exp < +F64_MAX_DEC_EXP - 20)) {
+ /*
+ The result value is exactly equal to (sig * 10^exp),
+ the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
+
+ The sig2 can be an infinite length number, only the highest 128 bits
+ is cached in the pow10_sig_table.
+
+ Now we have these bits:
+ sig1 (normalized 64bit) : aaaaaaaa
+ sig2 (higher 64bit) : bbbbbbbb
+ sig2_ext (lower 64bit) : cccccccc
+ sig2_cut (extra unknown bits) : dddddddddddd....
+
+ And the calculation process is:
+ ----------------------------------------
+ aaaaaaaa *
+ bbbbbbbbccccccccdddddddddddd....
+ ----------------------------------------
+ abababababababab +
+ acacacacacacacac +
+ adadadadadadadadadad....
+ ----------------------------------------
+ [hi____][lo____] +
+ [hi2___][lo2___] +
+ [unknown___________....]
+ ----------------------------------------
+
+ The addition with carry may affect higher bits, but if there is a 0
+ in higher bits, the bits higher than 0 will not be affected.
+
+ `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
+ value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
+
+ `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
+ the highest significant 53 bits of `hi` is needed. If there is a 0
+ in the lower bits of `hi`, then all the following bits can be dropped.
+
+ To convert the result to IEEE-754 double number, we need to perform
+ correct rounding:
+ 1. if bit 54 is 0, round down,
+ 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
+ 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
+ as the extra bits is unknown, this case will not be handled here.
+ */
+
+ u64 raw;
+ u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
+ i32 exp2;
+ u32 lz;
+ bool exact = false, carry, round_up;
+
+ /* convert (10^exp) to (sig2 * 2^exp2) */
+ pow10_table_get_sig(exp, &sig2, &sig2_ext);
+ pow10_table_get_exp(exp, &exp2);
+
+ /* normalize and multiply */
+ lz = u64_lz_bits(sig);
+ sig1 = sig << lz;
+ exp2 -= (i32)lz;
+ u128_mul(sig1, sig2, &hi, &lo);
+
+ /*
+ The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
+ To get normalized value, `hi` should be shifted to the left by 0 or 1.
+
+ The highest significant 53 bits is used by IEEE-754 double number,
+ and the bit 54 is used to detect rounding direction.
+
+ The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
+ */
+ bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
+ if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
+ /*
+ (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
+ The `bits` is not zero, so we don't need to check `round to even`
+ case. The `bits` contains bit `0`, so we can drop the extra bits
+ after `0`.
+ */
+ exact = true;
+
+ } else {
+ /*
+ (bits == 0 || bits == 0x1FF)
+ The `bits` is filled with all `0` or all `1`, so we need to check
+ lower bits with another 64-bit multiplication.
+ */
+ u128_mul(sig1, sig2_ext, &hi2, &lo2);
+
+ add = lo + hi2;
+ if (add + 1 > (u64)1) {
+ /*
+ (add != 0 && add != U64_MAX) => (add + 1 > 1)
+ The `add` is not zero, so we don't need to check `round to
+ even` case. The `add` contains bit `0`, so we can drop the
+ extra bits after `0`. The `hi` cannot be U64_MAX, so it will
+ not overflow.
+ */
+ carry = add < lo || add < hi2;
+ hi += carry;
+ exact = true;
+ }
+ }
+
+ if (exact) {
+ /* normalize */
+ lz = hi < ((u64)1 << 63);
+ hi <<= lz;
+ exp2 -= (i32)lz;
+ exp2 += 64;
+
+ /* test the bit 54 and get rounding direction */
+ round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
+ hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
+
+ /* test overflow */
+ if (hi < ((u64)1 << (64 - 54))) {
+ hi = ((u64)1 << 63);
+ exp2 += 1;
+ }
+
+ /* This is a normal number, convert it to IEEE-754 format. */
+ hi >>= F64_BITS - F64_SIG_FULL_BITS;
+ exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
+ exp2 += F64_EXP_BIAS;
+ raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
+ return_f64_bin(raw);
+ }
+ }
+
+ /*
+ Slow path: read double number exactly with diyfp.
+ 1. Use cached diyfp to get an approximation value.
+ 2. Use bigcomp to check the approximation value if needed.
+
+ This algorithm refers to google's double-conversion project:
+ https://github.com/google/double-conversion
+ */
+ {
+ const i32 ERR_ULP_LOG = 3;
+ const i32 ERR_ULP = 1 << ERR_ULP_LOG;
+ const i32 ERR_CACHED_POW = ERR_ULP / 2;
+ const i32 ERR_MUL_FIXED = ERR_ULP / 2;
+ const i32 DIY_SIG_BITS = 64;
+ const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
+ const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
+
+ u64 fp_err;
+ u32 bits;
+ i32 order_of_magnitude;
+ i32 effective_significand_size;
+ i32 precision_digits_count;
+ u64 precision_bits;
+ u64 half_way;
+
+ u64 raw;
+ diy_fp fp, fp_upper;
+ bigint big_full, big_comp;
+ i32 cmp;
+
+ fp.sig = sig;
+ fp.exp = 0;
+ fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
+
+ /* normalize */
+ bits = u64_lz_bits(fp.sig);
+ fp.sig <<= bits;
+ fp.exp -= (i32)bits;
+ fp_err <<= bits;
+
+ /* multiply and add error */
+ fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
+ fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
+
+ /* normalize */
+ bits = u64_lz_bits(fp.sig);
+ fp.sig <<= bits;
+ fp.exp -= (i32)bits;
+ fp_err <<= bits;
+
+ /* effective significand */
+ order_of_magnitude = DIY_SIG_BITS + fp.exp;
+ if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
+ effective_significand_size = F64_SIG_FULL_BITS;
+ } else if (order_of_magnitude <= EXP_SUBNORMAL) {
+ effective_significand_size = 0;
+ } else {
+ effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
+ }
+
+ /* precision digits count */
+ precision_digits_count = DIY_SIG_BITS - effective_significand_size;
+ if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
+ i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
+ fp.sig >>= shr;
+ fp.exp += shr;
+ fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
+ precision_digits_count -= shr;
+ }
+
+ /* half way */
+ precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
+ precision_bits *= (u32)ERR_ULP;
+ half_way = (u64)1 << (precision_digits_count - 1);
+ half_way *= (u32)ERR_ULP;
+
+ /* rounding */
+ fp.sig >>= precision_digits_count;
+ fp.sig += (precision_bits >= half_way + fp_err);
+ fp.exp += precision_digits_count;
+
+ /* get IEEE double raw value */
+ raw = diy_fp_to_ieee_raw(fp);
+ if (unlikely(raw == F64_BITS_INF)) return_inf();
+ if (likely(precision_bits <= half_way - fp_err ||
+ precision_bits >= half_way + fp_err)) {
+ return_f64_bin(raw); /* number is accurate */
+ }
+ /* now the number is the correct value, or the next lower value */
+
+ /* upper boundary */
+ if (raw & F64_EXP_MASK) {
+ fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
+ fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
+ } else {
+ fp_upper.sig = (raw & F64_SIG_MASK);
+ fp_upper.exp = 1;
+ }
+ fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
+ fp_upper.sig <<= 1;
+ fp_upper.exp -= 1;
+ fp_upper.sig += 1; /* add half ulp */
+
+ /* compare with bigint */
+ bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
+ bigint_set_u64(&big_comp, fp_upper.sig);
+ if (exp >= 0) {
+ bigint_mul_pow10(&big_full, +exp);
+ } else {
+ bigint_mul_pow10(&big_comp, -exp);
+ }
+ if (fp_upper.exp > 0) {
+ bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
+ } else {
+ bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
+ }
+ cmp = bigint_cmp(&big_full, &big_comp);
+ if (likely(cmp != 0)) {
+ /* round down or round up */
+ raw += (cmp > 0);
+ } else {
+ /* falls midway, round to even */
+ raw += (raw & 1);
+ }
+
+ if (unlikely(raw == F64_BITS_INF)) return_inf();
+ return_f64_bin(raw);
+ }
+
+#undef return_err
+#undef return_inf
+#undef return_0
+#undef return_i64
+#undef return_f64
+#undef return_f64_bin
+#undef return_raw
+}
+
+
+
+#else /* FP_READER */
+
+/**
+ Read a JSON number.
+ This is a fallback function if the custom number reader is disabled.
+ This function use libc's strtod() to read floating-point number.
+ */
+static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+#define return_err(_pos, _msg) do { \
+ *msg = _msg; \
+ *end = _pos; \
+ return false; \
+} while (false)
+
+#define return_0() do { \
+ val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
+ val->uni.u64 = 0; \
+ *end = cur; return true; \
+} while (false)
+
+#define return_i64(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
+ val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_f64(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
+ val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_f64_bin(_v) do { \
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
+ val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
+ *end = cur; return true; \
+} while (false)
+
+#define return_inf() do { \
+ if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
+ if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
+ else return_err(hdr, "number is infinity when parsed as double"); \
+} while (false)
+
+#define return_raw() do { \
+ val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
+ val->uni.str = (const char *)hdr; \
+ **pre = '\0'; *pre = cur; *end = cur; return true; \
+} while (false)
+
+ u64 sig, num;
+ u8 *hdr = *ptr;
+ u8 *cur = *ptr;
+ u8 **end = ptr;
+ u8 *dot = NULL;
+ u8 *f64_end = NULL;
+ bool sign;
+
+ /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
+ if (has_flg(NUMBER_AS_RAW)) {
+ return read_num_raw(ptr, pre, flg, val, msg);
+ }
+
+ sign = (*hdr == '-');
+ cur += sign;
+ sig = (u8)(*cur - '0');
+
+ /* read first digit, check leading zero */
+ while (unlikely(!char_is_digit(*cur))) {
+ if (has_allow(EXT_NUMBER)) {
+ if (*cur == '+' && cur == hdr) { /* leading `+` sign */
+ cur++;
+ sig = (u8)(*cur - '0');
+ continue;
+ }
+ if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
+ goto read_double; /* e.g. '.123' */
+ }
+ }
+ if (has_allow(INF_AND_NAN)) {
+ if (read_inf_or_nan(ptr, pre, flg, val)) return true;
+ }
+ return_err(cur, "no digit after sign");
+ }
+ if (*cur == '0') {
+ cur++;
+ if (unlikely(char_is_digit(*cur))) {
+ return_err(cur - 1, "number with leading zero is not allowed");
+ }
+ if (!char_is_fp(*cur)) {
+ if (has_allow(EXT_NUMBER) &&
+ (*cur == 'x' || *cur == 'X')) { /* hex integer */
+ return read_num_hex(ptr, pre, flg, val, msg);
+ }
+ return_0();
+ }
+ goto read_double;
+ }
+
+ /* read continuous digits, up to 19 characters */
+#define expr_intg(i) \
+ if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
+ else { cur += i; goto intg_end; }
+ repeat_in_1_18(expr_intg)
+#undef expr_intg
+
+ /* here are 19 continuous digits, skip them */
+ cur += 19;
+ if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
+ /* this number is an integer consisting of 20 digits */
+ num = (u8)(*cur - '0');
+ if ((sig < (U64_MAX / 10)) ||
+ (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
+ sig = num + sig * 10;
+ cur++;
+ if (sign) {
+ if (has_flg(BIGNUM_AS_RAW)) return_raw();
+ return_f64(unsafe_yyjson_u64_to_f64(sig));
+ }
+ return_i64(sig);
+ }
+ }
+
+intg_end:
+ /* continuous digits ended */
+ if (!char_is_digit_or_fp(*cur)) {
+ /* this number is an integer consisting of 1 to 19 digits */
+ if (sign && (sig > ((u64)1 << 63))) {
+ if (has_flg(BIGNUM_AS_RAW)) return_raw();
+ return_f64(unsafe_yyjson_u64_to_f64(sig));
+ }
+ return_i64(sig);
+ }
+
+read_double:
+ /* this number should be read as double */
+ while (char_is_digit(*cur)) cur++;
+ if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
+ return_raw(); /* it's a large integer */
+ }
+ while (*cur == '.') {
+ /* skip fraction part */
+ dot = cur;
+ cur++;
+ if (!char_is_digit(*cur)) {
+ if (has_allow(EXT_NUMBER)) {
+ break;
+ } else {
+ return_err(cur, "no digit after decimal point");
+ }
+ }
+ cur++;
+ while (char_is_digit(*cur)) cur++;
+ break;
+ }
+ if (char_is_exp(*cur)) {
+ /* skip exponent part */
+ cur += 1 + char_is_sign(cur[1]);
+ if (!char_is_digit(*cur)) {
+ return_err(cur, "no digit after exponent sign");
+ }
+ cur++;
+ while (char_is_digit(*cur)) cur++;
+ }
+
+ /*
+ libc's strtod() is used to parse the floating-point number.
+
+ Note that the decimal point character used by strtod() is locale-dependent,
+ and the rounding direction may affected by fesetround().
+
+ For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
+ decimal point, while other locales use ',' as the decimal point.
+
+ Here strtod() is called twice for different locales, but if another thread
+ happens calls setlocale() between two strtod(), parsing may still fail.
+ */
+ val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
+ if (unlikely(f64_end != cur)) {
+ /* replace '.' with ',' for locale */
+ bool cut = (*cur == ',');
+ if (cut) *cur = ' ';
+ if (dot) *dot = ',';
+ val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
+ /* restore ',' to '.' */
+ if (cut) *cur = ',';
+ if (dot) *dot = '.';
+ if (unlikely(f64_end != cur)) {
+ return_err(hdr, "strtod() failed to parse the number");
+ }
+ }
+ if (unlikely(val->uni.f64 >= HUGE_VAL || val->uni.f64 <= -HUGE_VAL)) {
+ return_inf();
+ }
+ val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
+ *end = cur;
+ return true;
+
+#undef return_err
+#undef return_0
+#undef return_i64
+#undef return_f64
+#undef return_f64_bin
+#undef return_inf
+#undef return_raw
+}
+
+#endif /* FP_READER */
+
+
+
+/*==============================================================================
+ * MARK: - String Reader (Private)
+ *============================================================================*/
+
+/** Read unicode escape sequence. */
+static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
+#define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
+
+ u8 *src = *src_ptr;
+ u8 *dst = *dst_ptr;
+ u16 hi, lo;
+ u32 uni;
+
+ src += 2; /* skip `\u` */
+ if (unlikely(!hex_load_4(src, &hi))) {
+ return_err(src - 2, "invalid escaped sequence in string");
+ }
+ src += 4; /* skip hex */
+ if (likely((hi & 0xF800) != 0xD800)) {
+ /* a BMP character */
+ if (hi >= 0x800) {
+ *dst++ = (u8)(0xE0 | (hi >> 12));
+ *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
+ *dst++ = (u8)(0x80 | (hi & 0x3F));
+ } else if (hi >= 0x80) {
+ *dst++ = (u8)(0xC0 | (hi >> 6));
+ *dst++ = (u8)(0x80 | (hi & 0x3F));
+ } else {
+ *dst++ = (u8)hi;
+ }
+ } else {
+ /* a non-BMP character, represented as a surrogate pair */
+ if (unlikely((hi & 0xFC00) != 0xD800)) {
+ return_err(src - 6, "invalid high surrogate in string");
+ }
+ if (unlikely(!byte_match_2(src, "\\u"))) {
+ return_err(src - 6, "no low surrogate in string");
+ }
+ if (unlikely(!hex_load_4(src + 2, &lo))) {
+ return_err(src - 6, "invalid escape in string");
+ }
+ if (unlikely((lo & 0xFC00) != 0xDC00)) {
+ return_err(src - 6, "invalid low surrogate in string");
+ }
+ uni = ((((u32)hi - 0xD800) << 10) |
+ ((u32)lo - 0xDC00)) + 0x10000;
+ *dst++ = (u8)(0xF0 | (uni >> 18));
+ *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
+ *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
+ *dst++ = (u8)(0x80 | (uni & 0x3F));
+ src += 6;
+ }
+ *src_ptr = src;
+ *dst_ptr = dst;
+ return true;
+#undef return_err
+}
+
+/**
+ Read a JSON string.
+ @param quo The quote character (single quote or double quote).
+ @param ptr The head pointer of string before quote (inout).
+ @param eof JSON end position.
+ @param flg JSON read flag.
+ @param val The string value to be written.
+ @param msg The error message pointer.
+ @param con Continuation for incremental parsing.
+ @return Whether success.
+ */
+static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg, u8 *con[2]) {
+ /*
+ GCC may sometimes load variables into registers too early, causing
+ unnecessary instructions and performance degradation. This inline assembly
+ serves as a hint to GCC: 'This variable will be modified, so avoid loading
+ it too early.' Other compilers like MSVC, Clang, and ICC can generate the
+ expected instructions without needing this hint.
+
+ Check out this example: https://godbolt.org/z/YG6a5W5Ec
+ */
+#define return_err(_end, _msg) do { \
+ *msg = _msg; \
+ *end = _end; \
+ if (con) { con[0] = _end; con[1] = dst; } \
+ return false; \
+} while (false)
+
+ u8 *hdr = *ptr + 1;
+ u8 **end = ptr;
+ u8 *src = hdr, *dst = NULL, *pos;
+ u16 hi, lo;
+ u32 uni, tmp;
+
+ /* Resume incremental parsing. */
+ if (con && unlikely(con[0])) {
+ src = con[0];
+ dst = con[1];
+ if (dst) goto copy_ascii;
+ }
+
+skip_ascii:
+ /*
+ Most strings have no escaped characters, so we can jump them quickly.
+
+ We want to make loop unrolling, as shown in the following code. Some
+ compiler may not generate instructions as expected, so we rewrite it with
+ explicit goto statements. We hope the compiler can generate instructions
+ like this: https://godbolt.org/z/8vjsYq
+
+ while (true) repeat16({
+ if (likely((char_is_ascii_skip(*src)))) src++;
+ else break;
+ })
+ */
+ if (quo == '"') {
+#define expr_jump(i) \
+ if (likely(char_is_ascii_skip(src[i]))) {} \
+ else goto skip_ascii_stop##i;
+
+#define expr_stop(i) \
+ skip_ascii_stop##i: \
+ src += i; \
+ goto skip_ascii_end;
+
+ repeat16_incr(expr_jump)
+ src += 16;
+ goto skip_ascii;
+ repeat16_incr(expr_stop)
+
+#undef expr_jump
+#undef expr_stop
+ } else {
+#define expr_jump(i) \
+ if (likely(char_is_ascii_skip_sq(src[i]))) {} \
+ else goto skip_ascii_stop_sq##i;
+
+#define expr_stop(i) \
+ skip_ascii_stop_sq##i: \
+ src += i; \
+ goto skip_ascii_end;
+
+ repeat16_incr(expr_jump)
+ src += 16;
+ goto skip_ascii;
+ repeat16_incr(expr_stop)
+
+#undef expr_jump
+#undef expr_stop
+ }
+
+skip_ascii_end:
+ gcc_store_barrier(*src);
+ if (likely(*src == quo)) {
+ val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
+ (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
+ val->uni.str = (const char *)hdr;
+ *src = '\0';
+ *end = src + 1;
+ if (con) con[0] = con[1] = NULL;
+ return true;
+ }
+
+skip_utf8:
+ if (*src & 0x80) { /* non-ASCII character */
+ /*
+ Non-ASCII character appears here, which means that the text is likely
+ to be written in non-English or emoticons. According to some common
+ data set statistics, byte sequences of the same length may appear
+ consecutively. We process the byte sequences of the same length in each
+ loop, which is more friendly to branch prediction.
+ */
+ pos = src;
+#if YYJSON_DISABLE_UTF8_VALIDATION
+ while (true) repeat8({
+ if (likely((*src & 0xF0) == 0xE0)) src += 3;
+ else break;
+ })
+ if (*src < 0x80) goto skip_ascii;
+ while (true) repeat8({
+ if (likely((*src & 0xE0) == 0xC0)) src += 2;
+ else break;
+ })
+ while (true) repeat8({
+ if (likely((*src & 0xF8) == 0xF0)) src += 4;
+ else break;
+ })
+#else
+ uni = byte_load_4(src);
+ while (is_utf8_seq3(uni)) {
+ src += 3;
+ uni = byte_load_4(src);
+ }
+ if (is_utf8_seq1(uni)) goto skip_ascii;
+ while (is_utf8_seq2(uni)) {
+ src += 2;
+ uni = byte_load_4(src);
+ }
+ while (is_utf8_seq4(uni)) {
+ src += 4;
+ uni = byte_load_4(src);
+ }
+#endif
+ if (unlikely(pos == src)) {
+ if (has_allow(INVALID_UNICODE)) ++src;
+ else return_err(src, "invalid UTF-8 encoding in string");
+ }
+ goto skip_ascii;
+ }
+
+ /* The escape character appears, we need to copy it. */
+ dst = src;
+copy_escape:
+ if (likely(*src == '\\')) {
+ switch (*++src) {
+ case '"': *dst++ = '"'; src++; break;
+ case '\\': *dst++ = '\\'; src++; break;
+ case '/': *dst++ = '/'; src++; break;
+ case 'b': *dst++ = '\b'; src++; break;
+ case 'f': *dst++ = '\f'; src++; break;
+ case 'n': *dst++ = '\n'; src++; break;
+ case 'r': *dst++ = '\r'; src++; break;
+ case 't': *dst++ = '\t'; src++; break;
+ case 'u':
+ src--;
+ if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
+ break;
+ default: {
+ if (has_allow(EXT_ESCAPE)) {
+ /* read extended escape (non-standard) */
+ switch (*src) {
+ case '\'': *dst++ = '\''; src++; break;
+ case 'a': *dst++ = '\a'; src++; break;
+ case 'v': *dst++ = '\v'; src++; break;
+ case '?': *dst++ = '\?'; src++; break;
+ case 'e': *dst++ = 0x1B; src++; break;
+ case '0':
+ if (!char_is_digit(src[1])) {
+ *dst++ = '\0'; src++; break;
+ }
+ return_err(src - 1, "octal escape is not allowed");
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return_err(src - 1, "invalid number escape");
+ case 'x': {
+ u8 c;
+ if (hex_load_2(src + 1, &c)) {
+ src += 3;
+ if (c <= 0x7F) { /* 1-byte ASCII */
+ *dst++ = c;
+ } else { /* 2-byte UTF-8 */
+ *dst++ = (u8)(0xC0 | (c >> 6));
+ *dst++ = (u8)(0x80 | (c & 0x3F));
+ }
+ break;
+ }
+ return_err(src - 1, "invalid hex escape");
+ }
+ case '\n': src++; break;
+ case '\r': src++; src += (*src == '\n'); break;
+ case 0xE2: /* Line terminator: U+2028, U+2029 */
+ if ((src[1] == 0x80 && src[2] == 0xA8) ||
+ (src[1] == 0x80 && src[2] == 0xA9)) {
+ src += 3;
+ }
+ break;
+ default:
+ break; /* skip */
+ }
+ } else if (quo == '\'' && *src == '\'') {
+ *dst++ = '\''; src++; break;
+ } else {
+ return_err(src - 1, "invalid escaped sequence in string");
+ }
+ }
+ }
+ } else if (likely(*src == quo)) {
+ val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ val->uni.str = (const char *)hdr;
+ *dst = '\0';
+ *end = src + 1;
+ if (con) con[0] = con[1] = NULL;
+ return true;
+ } else {
+ if (!has_allow(INVALID_UNICODE)) {
+ return_err(src, "unexpected control character in string");
+ }
+ if (src >= eof) return_err(src, "unclosed string");
+ *dst++ = *src++;
+ }
+
+copy_ascii:
+ /*
+ Copy continuous ASCII, loop unrolling, same as the following code:
+
+ while (true) repeat16({
+ if (char_is_ascii_skip(*src)) *dst++ = *src++;
+ else break;
+ })
+ */
+ if (quo == '"') {
+#define expr_jump(i) \
+ if (likely((char_is_ascii_skip(src[i])))) {} \
+ else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
+ repeat16_incr(expr_jump)
+#undef expr_jump
+ } else {
+#define expr_jump(i) \
+ if (likely((char_is_ascii_skip_sq(src[i])))) {} \
+ else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
+ repeat16_incr(expr_jump)
+#undef expr_jump
+ }
+
+ byte_move_16(dst, src);
+ dst += 16; src += 16;
+ goto copy_ascii;
+
+ /*
+ The memory is copied forward since `dst < src`.
+ So it's safe to move one extra byte to reduce instruction count.
+ */
+#define expr_jump(i) \
+ copy_ascii_stop_##i: \
+ byte_move_forward(dst, src, i); \
+ dst += i; src += i; \
+ goto copy_utf8;
+ repeat16_incr(expr_jump)
+#undef expr_jump
+
+copy_utf8:
+ if (*src & 0x80) { /* non-ASCII character */
+ pos = src;
+ uni = byte_load_4(src);
+#if YYJSON_DISABLE_UTF8_VALIDATION
+ while (true) repeat4({
+ if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
+ byte_copy_4(dst, &uni);
+ dst += 3; src += 3;
+ uni = byte_load_4(src);
+ } else break;
+ })
+ if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
+ while (true) repeat4({
+ if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
+ byte_copy_2(dst, &uni);
+ dst += 2; src += 2;
+ uni = byte_load_4(src);
+ } else break;
+ })
+ while (true) repeat4({
+ if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
+ byte_copy_4(dst, &uni);
+ dst += 4; src += 4;
+ uni = byte_load_4(src);
+ } else break;
+ })
+#else
+ while (is_utf8_seq3(uni)) {
+ byte_copy_4(dst, &uni);
+ dst += 3; src += 3;
+ uni = byte_load_4(src);
+ }
+ if (is_utf8_seq1(uni)) goto copy_ascii;
+ while (is_utf8_seq2(uni)) {
+ byte_copy_2(dst, &uni);
+ dst += 2; src += 2;
+ uni = byte_load_4(src);
+ }
+ while (is_utf8_seq4(uni)) {
+ byte_copy_4(dst, &uni);
+ dst += 4; src += 4;
+ uni = byte_load_4(src);
+ }
+#endif
+ if (unlikely(pos == src)) {
+ if (!has_allow(INVALID_UNICODE)) {
+ return_err(src, MSG_ERR_UTF8);
+ }
+ goto copy_ascii_stop_1;
+ }
+ goto copy_ascii;
+ }
+ goto copy_escape;
+
+#undef return_err
+}
+
+static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+ return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
+}
+
+static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg, u8 **con) {
+ return read_str_opt('\"', ptr, eof, flg, val, msg, con);
+}
+
+static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg,
+ yyjson_val *val, const char **msg) {
+ return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
+}
+
+/** Read unquoted key (identifier name). */
+static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg,
+ u8 **pre, yyjson_val *val, const char **msg) {
+#define return_err(_end, _msg) do { \
+ *msg = _msg; \
+ *end = _end; \
+ return false; \
+} while (false)
+
+#define return_suc(_str_end, _cur_end) do { \
+ val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
+ (u64)(YYJSON_TYPE_STR); \
+ val->uni.str = (const char *)hdr; \
+ *pre = _str_end; *end = _cur_end; \
+ return true; \
+} while (false)
+
+ u8 *hdr = *ptr;
+ u8 **end = ptr;
+ u8 *src = hdr, *dst = NULL;
+ u16 hi, lo;
+ u32 uni, tmp;
+
+ /* add null-terminator for previous raw string */
+ **pre = '\0';
+
+skip_ascii:
+#define expr_jump(i) \
+ if (likely(char_is_id_ascii(src[i]))) {} \
+ else goto skip_ascii_stop##i;
+
+#define expr_stop(i) \
+ skip_ascii_stop##i: \
+ src += i; \
+ goto skip_ascii_end;
+
+ repeat16_incr(expr_jump)
+ src += 16;
+ goto skip_ascii;
+ repeat16_incr(expr_stop)
+
+#undef expr_jump
+#undef expr_stop
+
+skip_ascii_end:
+ gcc_store_barrier(*src);
+ if (likely(!char_is_id_next(*src))) {
+ return_suc(src, src);
+ }
+
+skip_utf8:
+ while (*src >= 0x80) {
+ if (has_allow(EXT_WHITESPACE)) {
+ if (char_is_space_ext(*src) && ext_space_len(src)) {
+ return_suc(src, src);
+ }
+ }
+ uni = byte_load_4(src);
+ if (is_utf8_seq2(uni)) {
+ src += 2;
+ } else if (is_utf8_seq3(uni)) {
+ src += 3;
+ } else if (is_utf8_seq4(uni)) {
+ src += 4;
+ } else {
+#if !YYJSON_DISABLE_UTF8_VALIDATION
+ if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
+#endif
+ src += 1;
+ }
+ }
+ if (char_is_id_ascii(*src)) goto skip_ascii;
+
+ /* The escape character appears, we need to copy it. */
+ dst = src;
+copy_escape:
+ if (byte_match_2(src, "\\u")) {
+ if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
+ } else {
+ if (!char_is_id_next(*src)) return_suc(dst, src);
+ return_err(src, "unexpected character in key");
+ }
+
+copy_ascii:
+ /*
+ Copy continuous ASCII, loop unrolling, same as the following code:
+
+ while (true) repeat16({
+ if (char_is_ascii_skip(*src)) *dst++ = *src++;
+ else break;
+ })
+ */
+#define expr_jump(i) \
+ if (likely((char_is_id_ascii(src[i])))) {} \
+ else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
+ repeat16_incr(expr_jump)
+#undef expr_jump
+
+ byte_move_16(dst, src);
+ dst += 16; src += 16;
+ goto copy_ascii;
+
+#define expr_jump(i) \
+ copy_ascii_stop_##i: \
+ byte_move_forward(dst, src, i); \
+ dst += i; src += i; \
+ goto copy_utf8;
+ repeat16_incr(expr_jump)
+#undef expr_jump
+
+copy_utf8:
+ while (*src >= 0x80) { /* non-ASCII character */
+ if (has_allow(EXT_WHITESPACE)) {
+ if (char_is_space_ext(*src) && ext_space_len(src)) {
+ return_suc(dst, src);
+ }
+ }
+ uni = byte_load_4(src);
+ if (is_utf8_seq2(uni)) {
+ byte_copy_2(dst, &uni);
+ dst += 2; src += 2;
+ } else if (is_utf8_seq3(uni)) {
+ byte_copy_4(dst, &uni);
+ dst += 3; src += 3;
+ } else if (is_utf8_seq4(uni)) {
+ byte_copy_4(dst, &uni);
+ dst += 4; src += 4;
+ } else {
+#if !YYJSON_DISABLE_UTF8_VALIDATION
+ if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
+#endif
+ *dst = *src;
+ dst += 1; src += 1;
+ }
+ }
+ if (char_is_id_ascii(*src)) goto copy_ascii;
+ goto copy_escape;
+
+#undef return_err
+#undef return_suc
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Reader Implementation (Private)
+ *
+ * We use goto statements to build the finite state machine (FSM).
+ * The FSM's state was held by program counter (PC) and the 'goto' make the
+ * state transitions.
+ *============================================================================*/
+
+/** Read single value JSON document. */
+static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof,
+ yyjson_alc alc,
+ yyjson_read_flag flg,
+ yyjson_read_err *err) {
+#define return_err(_pos, _code, _msg) do { \
+ if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
+ err->pos = (usize)(eof - hdr); \
+ err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
+ err->msg = MSG_NOT_END; \
+ } else { \
+ err->pos = (usize)(_pos - hdr); \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ err->msg = _msg; \
+ } \
+ if (val_hdr) alc.free(alc.ctx, val_hdr); \
+ return NULL; \
+} while (false)
+
+ usize hdr_len; /* value count used by doc */
+ usize alc_num; /* value count capacity */
+ yyjson_val *val_hdr; /* the head of allocated values */
+ yyjson_val *val; /* current value */
+ yyjson_doc *doc; /* the JSON document, equals to val_hdr */
+ const char *msg; /* error message */
+
+ u8 raw_end[1]; /* raw end for null-terminator */
+ u8 *raw_ptr = raw_end;
+ u8 **pre = &raw_ptr; /* previous raw end pointer */
+
+ hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
+ hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
+ alc_num = hdr_len + 1; /* single value */
+
+ val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
+ if (unlikely(!val_hdr)) goto fail_alloc;
+ val = val_hdr + hdr_len;
+
+ if (char_is_num(*cur)) {
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
+ goto fail_number;
+ }
+ if (*cur == '"') {
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
+ goto fail_string;
+ }
+ if (*cur == 't') {
+ if (likely(read_true(&cur, val))) goto doc_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ if (likely(read_false(&cur, val))) goto doc_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ if (likely(read_null(&cur, val))) goto doc_end;
+ if (has_allow(INF_AND_NAN)) {
+ if (read_nan(&cur, pre, flg, val)) goto doc_end;
+ }
+ goto fail_literal_null;
+ }
+ if (has_allow(INF_AND_NAN)) {
+ if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
+ goto fail_string;
+ }
+ goto fail_character;
+
+doc_end:
+ /* check invalid contents after json document */
+ if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
+ while (char_is_space(*cur)) cur++;
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (!skip_trivia(&cur, eof, flg) && cur == eof) {
+ goto fail_comment;
+ }
+ }
+ if (unlikely(cur < eof)) goto fail_garbage;
+ }
+
+ **pre = '\0';
+ doc = (yyjson_doc *)val_hdr;
+ doc->root = val_hdr + hdr_len;
+ doc->alc = alc;
+ doc->dat_read = (usize)(cur - hdr);
+ doc->val_read = 1;
+ doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
+ return doc;
+
+fail_string: return_err(cur, INVALID_STRING, msg);
+fail_number: return_err(cur, INVALID_NUMBER, msg);
+fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
+fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
+fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
+fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
+fail_character: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
+fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
+fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+
+#undef return_err
+}
+
+/** Read JSON document (accept all style, but optimized for minify). */
+static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
+ yyjson_alc alc,
+ yyjson_read_flag flg,
+ yyjson_read_err *err) {
+#define return_err(_pos, _code, _msg) do { \
+ if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
+ err->pos = (usize)(eof - hdr); \
+ err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
+ err->msg = MSG_NOT_END; \
+ } else { \
+ err->pos = (usize)(_pos - hdr); \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ err->msg = _msg; \
+ } \
+ if (val_hdr) alc.free(alc.ctx, val_hdr); \
+ return NULL; \
+} while (false)
+
+#define val_incr() do { \
+ val++; \
+ if (unlikely(val >= val_end)) { \
+ usize alc_old = alc_len; \
+ usize val_ofs = (usize)(val - val_hdr); \
+ usize ctn_ofs = (usize)(ctn - val_hdr); \
+ alc_len += alc_len / 2; \
+ if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
+ val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
+ alc_old * sizeof(yyjson_val), \
+ alc_len * sizeof(yyjson_val)); \
+ if ((!val_tmp)) goto fail_alloc; \
+ val = val_tmp + val_ofs; \
+ ctn = val_tmp + ctn_ofs; \
+ val_hdr = val_tmp; \
+ val_end = val_tmp + (alc_len - 2); \
+ } \
+} while (false)
+
+ usize dat_len; /* data length in bytes, hint for allocator */
+ usize hdr_len; /* value count used by yyjson_doc */
+ usize alc_len; /* value count allocated */
+ usize alc_max; /* maximum value count for allocator */
+ usize ctn_len; /* the number of elements in current container */
+ yyjson_val *val_hdr; /* the head of allocated values */
+ yyjson_val *val_end; /* the end of allocated values */
+ yyjson_val *val_tmp; /* temporary pointer for realloc */
+ yyjson_val *val; /* current JSON value */
+ yyjson_val *ctn; /* current container */
+ yyjson_val *ctn_parent; /* parent of current container */
+ yyjson_doc *doc; /* the JSON document, equals to val_hdr */
+ const char *msg; /* error message */
+
+ u8 raw_end[1]; /* raw end for null-terminator */
+ u8 *raw_ptr = raw_end;
+ u8 **pre = &raw_ptr; /* previous raw end pointer */
+
+ dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
+ hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
+ hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
+ alc_max = USIZE_MAX / sizeof(yyjson_val);
+ alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
+ alc_len = yyjson_min(alc_len, alc_max);
+
+ val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
+ if (unlikely(!val_hdr)) goto fail_alloc;
+ val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
+ val = val_hdr + hdr_len;
+ ctn = val;
+ ctn_len = 0;
+
+ if (*cur++ == '{') {
+ ctn->tag = YYJSON_TYPE_OBJ;
+ ctn->uni.ofs = 0;
+ goto obj_key_begin;
+ } else {
+ ctn->tag = YYJSON_TYPE_ARR;
+ ctn->uni.ofs = 0;
+ goto arr_val_begin;
+ }
+
+arr_begin:
+ /* save current container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+
+ /* create a new array value, save parent container offset */
+ val_incr();
+ val->tag = YYJSON_TYPE_ARR;
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+
+ /* push the new array value as current container */
+ ctn = val;
+ ctn_len = 0;
+
+arr_val_begin:
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (char_is_num(*cur)) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
+ goto fail_number;
+ }
+ if (*cur == '"') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
+ goto fail_string;
+ }
+ if (*cur == 't') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto arr_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto arr_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto arr_val_end;
+ if (has_allow(INF_AND_NAN)) {
+ if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
+ }
+ goto fail_literal_null;
+ }
+ if (*cur == ']') {
+ cur++;
+ if (likely(ctn_len == 0)) goto arr_end;
+ if (has_allow(TRAILING_COMMAS)) goto arr_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_begin;
+ }
+ if (has_allow(INF_AND_NAN) &&
+ (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
+ val_incr();
+ ctn_len++;
+ if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
+ goto fail_character_val;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_val;
+
+arr_val_end:
+ if (*cur == ',') {
+ cur++;
+ goto arr_val_begin;
+ }
+ if (*cur == ']') {
+ cur++;
+ goto arr_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_arr_end;
+
+arr_end:
+ /* get parent container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+
+ /* save the next sibling value offset */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+
+ /* pop parent as current container */
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+obj_begin:
+ /* push container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+ val_incr();
+ val->tag = YYJSON_TYPE_OBJ;
+ /* offset to the parent */
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+ ctn = val;
+ ctn_len = 0;
+
+obj_key_begin:
+ if (likely(*cur == '"')) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
+ goto fail_string;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ if (likely(ctn_len == 0)) goto obj_end;
+ if (has_allow(TRAILING_COMMAS)) goto obj_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_begin;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
+ goto fail_string;
+ }
+ if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
+ val_incr();
+ ctn_len++;
+ if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_key;
+
+obj_key_end:
+ if (*cur == ':') {
+ cur++;
+ goto obj_val_begin;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_sep;
+
+obj_val_begin:
+ if (*cur == '"') {
+ val++;
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
+ goto fail_string;
+ }
+ if (char_is_num(*cur)) {
+ val++;
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
+ goto fail_number;
+ }
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (*cur == 't') {
+ val++;
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto obj_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val++;
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto obj_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val++;
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto obj_val_end;
+ if (has_allow(INF_AND_NAN)) {
+ if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
+ }
+ goto fail_literal_null;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_begin;
+ }
+ if (has_allow(INF_AND_NAN) &&
+ (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
+ val++;
+ ctn_len++;
+ if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
+ goto fail_character_val;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val++;
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_val;
+
+obj_val_end:
+ if (likely(*cur == ',')) {
+ cur++;
+ goto obj_key_begin;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ goto obj_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_end;
+
+obj_end:
+ /* pop container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+ /* point to the next value */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+doc_end:
+ /* check invalid contents after json document */
+ if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
+ while (char_is_space(*cur)) cur++;
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (!skip_trivia(&cur, eof, flg) && cur == eof) {
+ goto fail_comment;
+ }
+ }
+ if (unlikely(cur < eof)) goto fail_garbage;
+ }
+
+ **pre = '\0';
+ doc = (yyjson_doc *)val_hdr;
+ doc->root = val_hdr + hdr_len;
+ doc->alc = alc;
+ doc->dat_read = (usize)(cur - hdr);
+ doc->val_read = (usize)((val - doc->root) + 1);
+ doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
+ return doc;
+
+fail_string: return_err(cur, INVALID_STRING, msg);
+fail_number: return_err(cur, INVALID_NUMBER, msg);
+fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
+fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
+fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
+fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
+fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
+fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
+fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
+fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
+fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
+fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
+fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
+fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+
+#undef val_incr
+#undef return_err
+}
+
+/** Read JSON document (accept all style, but optimized for pretty). */
+static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
+ yyjson_alc alc,
+ yyjson_read_flag flg,
+ yyjson_read_err *err) {
+#define return_err(_pos, _code, _msg) do { \
+ if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
+ err->pos = (usize)(eof - hdr); \
+ err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
+ err->msg = MSG_NOT_END; \
+ } else { \
+ err->pos = (usize)(_pos - hdr); \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ err->msg = _msg; \
+ } \
+ if (val_hdr) alc.free(alc.ctx, val_hdr); \
+ return NULL; \
+} while (false)
+
+#define val_incr() do { \
+ val++; \
+ if (unlikely(val >= val_end)) { \
+ usize alc_old = alc_len; \
+ usize val_ofs = (usize)(val - val_hdr); \
+ usize ctn_ofs = (usize)(ctn - val_hdr); \
+ alc_len += alc_len / 2; \
+ if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
+ val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
+ alc_old * sizeof(yyjson_val), \
+ alc_len * sizeof(yyjson_val)); \
+ if ((!val_tmp)) goto fail_alloc; \
+ val = val_tmp + val_ofs; \
+ ctn = val_tmp + ctn_ofs; \
+ val_hdr = val_tmp; \
+ val_end = val_tmp + (alc_len - 2); \
+ } \
+} while (false)
+
+ usize dat_len; /* data length in bytes, hint for allocator */
+ usize hdr_len; /* value count used by yyjson_doc */
+ usize alc_len; /* value count allocated */
+ usize alc_max; /* maximum value count for allocator */
+ usize ctn_len; /* the number of elements in current container */
+ yyjson_val *val_hdr; /* the head of allocated values */
+ yyjson_val *val_end; /* the end of allocated values */
+ yyjson_val *val_tmp; /* temporary pointer for realloc */
+ yyjson_val *val; /* current JSON value */
+ yyjson_val *ctn; /* current container */
+ yyjson_val *ctn_parent; /* parent of current container */
+ yyjson_doc *doc; /* the JSON document, equals to val_hdr */
+ const char *msg; /* error message */
+
+ u8 raw_end[1]; /* raw end for null-terminator */
+ u8 *raw_ptr = raw_end;
+ u8 **pre = &raw_ptr; /* previous raw end pointer */
+
+ dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
+ hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
+ hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
+ alc_max = USIZE_MAX / sizeof(yyjson_val);
+ alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
+ alc_len = yyjson_min(alc_len, alc_max);
+
+ val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
+ if (unlikely(!val_hdr)) goto fail_alloc;
+ val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
+ val = val_hdr + hdr_len;
+ ctn = val;
+ ctn_len = 0;
+
+ if (*cur++ == '{') {
+ ctn->tag = YYJSON_TYPE_OBJ;
+ ctn->uni.ofs = 0;
+ if (*cur == '\n') cur++;
+ goto obj_key_begin;
+ } else {
+ ctn->tag = YYJSON_TYPE_ARR;
+ ctn->uni.ofs = 0;
+ if (*cur == '\n') cur++;
+ goto arr_val_begin;
+ }
+
+arr_begin:
+ /* save current container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+
+ /* create a new array value, save parent container offset */
+ val_incr();
+ val->tag = YYJSON_TYPE_ARR;
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+
+ /* push the new array value as current container */
+ ctn = val;
+ ctn_len = 0;
+ if (*cur == '\n') cur++;
+
+arr_val_begin:
+#if YYJSON_IS_REAL_GCC
+ while (true) repeat16({
+ if (byte_match_2(cur, " ")) cur += 2;
+ else break;
+ })
+#else
+ while (true) repeat16({
+ if (likely(byte_match_2(cur, " "))) cur += 2;
+ else break;
+ })
+#endif
+
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (char_is_num(*cur)) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
+ goto fail_number;
+ }
+ if (*cur == '"') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
+ goto fail_string;
+ }
+ if (*cur == 't') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto arr_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto arr_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto arr_val_end;
+ if (has_allow(INF_AND_NAN)) {
+ if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
+ }
+ goto fail_literal_null;
+ }
+ if (*cur == ']') {
+ cur++;
+ if (likely(ctn_len == 0)) goto arr_end;
+ if (has_allow(TRAILING_COMMAS)) goto arr_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_begin;
+ }
+ if (has_allow(INF_AND_NAN) &&
+ (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
+ val_incr();
+ ctn_len++;
+ if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
+ goto fail_character_val;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_val;
+
+arr_val_end:
+ if (byte_match_2(cur, ",\n")) {
+ cur += 2;
+ goto arr_val_begin;
+ }
+ if (*cur == ',') {
+ cur++;
+ goto arr_val_begin;
+ }
+ if (*cur == ']') {
+ cur++;
+ goto arr_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_arr_end;
+
+arr_end:
+ /* get parent container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+
+ /* save the next sibling value offset */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+
+ /* pop parent as current container */
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if (*cur == '\n') cur++;
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+obj_begin:
+ /* push container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+ val_incr();
+ val->tag = YYJSON_TYPE_OBJ;
+ /* offset to the parent */
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+ ctn = val;
+ ctn_len = 0;
+ if (*cur == '\n') cur++;
+
+obj_key_begin:
+#if YYJSON_IS_REAL_GCC
+ while (true) repeat16({
+ if (byte_match_2(cur, " ")) cur += 2;
+ else break;
+ })
+#else
+ while (true) repeat16({
+ if (likely(byte_match_2(cur, " "))) cur += 2;
+ else break;
+ })
+#endif
+ if (likely(*cur == '"')) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
+ goto fail_string;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ if (likely(ctn_len == 0)) goto obj_end;
+ if (has_allow(TRAILING_COMMAS)) goto obj_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_begin;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
+ goto fail_string;
+ }
+ if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
+ val_incr();
+ ctn_len++;
+ if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_key;
+
+obj_key_end:
+ if (byte_match_2(cur, ": ")) {
+ cur += 2;
+ goto obj_val_begin;
+ }
+ if (*cur == ':') {
+ cur++;
+ goto obj_val_begin;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_sep;
+
+obj_val_begin:
+ if (*cur == '"') {
+ val++;
+ ctn_len++;
+ if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
+ goto fail_string;
+ }
+ if (char_is_num(*cur)) {
+ val++;
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
+ goto fail_number;
+ }
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (*cur == 't') {
+ val++;
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto obj_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val++;
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto obj_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val++;
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto obj_val_end;
+ if (has_allow(INF_AND_NAN)) {
+ if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
+ }
+ goto fail_literal_null;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_begin;
+ }
+ if (has_allow(INF_AND_NAN) &&
+ (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
+ val++;
+ ctn_len++;
+ if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
+ goto fail_character_val;
+ }
+ if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
+ val++;
+ ctn_len++;
+ if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
+ goto fail_string;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_val;
+
+obj_val_end:
+ if (byte_match_2(cur, ",\n")) {
+ cur += 2;
+ goto obj_key_begin;
+ }
+ if (likely(*cur == ',')) {
+ cur++;
+ goto obj_key_begin;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ goto obj_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_end;
+ }
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
+ if (cur == eof) goto fail_comment;
+ }
+ goto fail_character_obj_end;
+
+obj_end:
+ /* pop container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+ /* point to the next value */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if (*cur == '\n') cur++;
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+doc_end:
+ /* check invalid contents after json document */
+ if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
+ while (char_is_space(*cur)) cur++;
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (!skip_trivia(&cur, eof, flg) && cur == eof) {
+ goto fail_comment;
+ }
+ }
+ if (unlikely(cur < eof)) goto fail_garbage;
+ }
+
+ **pre = '\0';
+ doc = (yyjson_doc *)val_hdr;
+ doc->root = val_hdr + hdr_len;
+ doc->alc = alc;
+ doc->dat_read = (usize)(cur - hdr);
+ doc->val_read = (usize)((val - doc->root) + 1);
+ doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
+ return doc;
+
+fail_string: return_err(cur, INVALID_STRING, msg);
+fail_number: return_err(cur, INVALID_NUMBER, msg);
+fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
+fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
+fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
+fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
+fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
+fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
+fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
+fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
+fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
+fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
+fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
+fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+
+#undef val_incr
+#undef return_err
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Reader (Public)
+ *============================================================================*/
+
+yyjson_doc *yyjson_read_opts(char *dat, usize len,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_read_err *err) {
+#define return_err(_pos, _code, _msg) do { \
+ err->pos = (usize)(_pos); \
+ err->msg = _msg; \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
+ return NULL; \
+} while (false)
+
+ yyjson_read_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ yyjson_doc *doc;
+ u8 *hdr = NULL, *eof, *cur;
+
+ /* validate input parameters */
+ if (!err) err = &tmp_err;
+ if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
+ if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
+
+ /* add 4-byte zero padding for input data if necessary */
+ if (has_flg(INSITU)) {
+ hdr = (u8 *)dat;
+ eof = (u8 *)dat + len;
+ cur = (u8 *)dat;
+ } else {
+ if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
+ return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
+ }
+ hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
+ if (unlikely(!hdr)) {
+ return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
+ }
+ eof = hdr + len;
+ cur = hdr;
+ memcpy(hdr, dat, len);
+ }
+ memset(eof, 0, YYJSON_PADDING_SIZE);
+
+ if (has_allow(BOM)) {
+ if (len >= 3 && is_utf8_bom(cur)) cur += 3;
+ }
+
+ /* skip empty contents before json document */
+ if (unlikely(!char_is_ctn(*cur))) {
+ while (char_is_space(*cur)) cur++;
+ if (unlikely(!char_is_ctn(*cur))) {
+ if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
+ if (!skip_trivia(&cur, eof, flg) && cur == eof) {
+ return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
+ }
+ }
+ }
+ if (unlikely(cur >= eof)) {
+ return_err(0, EMPTY_CONTENT, "input data is empty");
+ }
+ }
+
+ /* read json document */
+ if (likely(char_is_ctn(*cur))) {
+ if (char_is_space(cur[1]) && char_is_space(cur[2])) {
+ doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
+ } else {
+ doc = read_root_minify(hdr, cur, eof, alc, flg, err);
+ }
+ } else {
+ doc = read_root_single(hdr, cur, eof, alc, flg, err);
+ }
+
+ /* check result */
+ if (likely(doc)) {
+ memset(err, 0, sizeof(yyjson_read_err));
+ } else {
+ /* RFC 8259: JSON text MUST be encoded using UTF-8 */
+ if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
+ if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
+ else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
+ else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
+ }
+ if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
+ }
+ return doc;
+
+#undef return_err
+}
+
+yyjson_doc *yyjson_read_file(const char *path,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_read_err *err) {
+#define return_err(_code, _msg) do { \
+ err->pos = 0; \
+ err->msg = _msg; \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ return NULL; \
+} while (false)
+
+ yyjson_read_err tmp_err;
+ yyjson_doc *doc;
+ FILE *file;
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
+
+ file = fopen_readonly(path);
+ if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
+
+ doc = yyjson_read_fp(file, flg, alc_ptr, err);
+ fclose(file);
+ return doc;
+
+#undef return_err
+}
+
+yyjson_doc *yyjson_read_fp(FILE *file,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_read_err *err) {
+#define return_err(_code, _msg) do { \
+ err->pos = 0; \
+ err->msg = _msg; \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ if (buf) alc.free(alc.ctx, buf); \
+ return NULL; \
+} while (false)
+
+ yyjson_read_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ yyjson_doc *doc;
+
+ long file_size = 0, file_pos;
+ void *buf = NULL;
+ usize buf_size = 0;
+
+ /* validate input parameters */
+ if (!err) err = &tmp_err;
+ if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
+
+ /* get current position */
+ file_pos = ftell(file);
+ if (file_pos != -1) {
+ /* get total file size, may fail */
+ if (fseek(file, 0, SEEK_END) == 0) file_size = ftell(file);
+ /* reset to original position, may fail */
+ if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
+ /* get file size from current postion to end */
+ if (file_size > 0) file_size -= file_pos;
+ }
+
+ /* read file */
+ if (file_size > 0) {
+ /* read the entire file in one call */
+ buf_size = (usize)file_size + YYJSON_PADDING_SIZE;
+ buf = alc.malloc(alc.ctx, buf_size);
+ if (buf == NULL) {
+ return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+ }
+ if (fread_safe(buf, (usize)file_size, file) != (usize)file_size) {
+ return_err(FILE_READ, MSG_FREAD);
+ }
+ } else {
+ /* failed to get file size, read it as a stream */
+ usize chunk_min = (usize)64;
+ usize chunk_max = (usize)512 * 1024 * 1024;
+ usize chunk_now = chunk_min;
+ usize read_size;
+ void *tmp;
+
+ buf_size = YYJSON_PADDING_SIZE;
+ while (true) {
+ if (buf_size + chunk_now < buf_size) { /* overflow */
+ return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+ }
+ buf_size += chunk_now;
+ if (!buf) {
+ buf = alc.malloc(alc.ctx, buf_size);
+ if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+ } else {
+ tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
+ if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+ buf = tmp;
+ }
+ tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
+ read_size = fread_safe(tmp, chunk_now, file);
+ file_size += (long)read_size;
+ if (read_size != chunk_now) break;
+
+ chunk_now *= 2;
+ if (chunk_now > chunk_max) chunk_now = chunk_max;
+ }
+ }
+
+ /* read JSON */
+ memset((u8 *)buf + file_size, 0, YYJSON_PADDING_SIZE);
+ flg |= YYJSON_READ_INSITU;
+ doc = yyjson_read_opts((char *)buf, (usize)file_size, flg, &alc, err);
+ if (doc) {
+ doc->str_pool = (char *)buf;
+ return doc;
+ } else {
+ alc.free(alc.ctx, buf);
+ return NULL;
+ }
+
+#undef return_err
+}
+
+const char *yyjson_read_number(const char *dat,
+ yyjson_val *val,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err) {
+#define return_err(_pos, _code, _msg) do { \
+ err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
+ err->msg = _msg; \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ return NULL; \
+} while (false)
+
+ u8 *hdr = constcast(u8 *)dat, *cur = hdr;
+ u8 raw_end[1]; /* raw end for null-terminator */
+ u8 *raw_ptr = raw_end;
+ u8 **pre = &raw_ptr; /* previous raw end pointer */
+ const char *msg;
+ yyjson_read_err tmp_err;
+
+#if YYJSON_DISABLE_FAST_FP_CONV
+ u8 buf[128];
+ usize dat_len;
+#endif
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!dat)) {
+ return_err(cur, INVALID_PARAMETER, "input data is NULL");
+ }
+ if (unlikely(!val)) {
+ return_err(cur, INVALID_PARAMETER, "output value is NULL");
+ }
+
+#if YYJSON_DISABLE_FAST_FP_CONV
+ if (!alc) alc = &YYJSON_DEFAULT_ALC;
+ dat_len = strlen(dat);
+ if (dat_len < sizeof(buf)) {
+ memcpy(buf, dat, dat_len + 1);
+ hdr = buf;
+ cur = hdr;
+ } else {
+ hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
+ cur = hdr;
+ if (unlikely(!hdr)) {
+ return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
+ }
+ memcpy(hdr, dat, dat_len + 1);
+ }
+ hdr[dat_len] = 0;
+#endif
+
+#if YYJSON_DISABLE_FAST_FP_CONV
+ if (!read_num(&cur, pre, flg, val, &msg)) {
+ if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
+ return_err(cur, INVALID_NUMBER, msg);
+ }
+ if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
+ if (yyjson_is_raw(val)) val->uni.str = dat;
+ return dat + (cur - hdr);
+#else
+ if (!read_num(&cur, pre, flg, val, &msg)) {
+ return_err(cur, INVALID_NUMBER, msg);
+ }
+ return (const char *)cur;
+#endif
+
+#undef return_err
+}
+
+
+
+/*==============================================================================
+ * MARK: - Incremental JSON Reader (Public)
+ *============================================================================*/
+
+#if !YYJSON_DISABLE_INCR_READER
+
+/* labels within yyjson_incr_read() to resume incremental parsing */
+#define LABEL_doc_begin 0
+#define LABEL_arr_val_begin 1
+#define LABEL_arr_val_end 2
+#define LABEL_obj_key_begin 3
+#define LABEL_obj_key_end 4
+#define LABEL_obj_val_begin 5
+#define LABEL_obj_val_end 6
+#define LABEL_doc_end 7
+
+/** State for incremental JSON reader, opaque in the API. */
+struct yyjson_incr_state {
+ u32 label; /* current parser goto label */
+ yyjson_alc alc; /* allocator */
+ yyjson_read_flag flg; /* read flags */
+ u8 *hdr; /* JSON data header */
+ u8 *cur; /* current position in JSON data */
+ usize buf_len; /* total buffer length (without padding) */
+ usize hdr_len; /* value count used by yyjson_doc */
+ usize alc_len; /* value count allocated */
+ usize ctn_len; /* the number of elements in current container */
+ yyjson_val *val_hdr; /* the head of allocated values */
+ yyjson_val *val_end; /* the end of allocated values */
+ yyjson_val *val; /* current JSON value */
+ yyjson_val *ctn; /* current container */
+ u8 *str_con[2]; /* string parser incremental state */
+};
+
+yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc_ptr) {
+ yyjson_incr_state *state = NULL;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+
+ /* remove non-standard flags */
+ flg &= ~YYJSON_READ_JSON5;
+ flg &= ~YYJSON_READ_ALLOW_BOM;
+ flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
+
+ if (unlikely(!buf)) return NULL;
+ if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
+ state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
+ if (!state) return NULL;
+ memset(state, 0, sizeof(yyjson_incr_state));
+ state->alc = alc;
+ state->flg = flg;
+ state->buf_len = buf_len;
+
+ /* add 4-byte zero padding for input data if necessary */
+ if (has_flg(INSITU)) {
+ state->hdr = (u8 *)buf;
+ } else {
+ state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
+ if (unlikely(!state->hdr)) {
+ alc.free(alc.ctx, state);
+ return NULL;
+ }
+ memcpy(state->hdr, buf, buf_len);
+ }
+ memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
+ state->cur = state->hdr;
+ state->label = LABEL_doc_begin;
+ return state;
+}
+
+void yyjson_incr_free(yyjson_incr_state *state) {
+ if (state) {
+ yyjson_alc alc = state->alc;
+ memset(&state->alc, 0, sizeof(alc));
+ if (state->val_hdr) {
+ alc.free(alc.ctx, (void *)state->val_hdr);
+ }
+ if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
+ alc.free(alc.ctx, state->hdr);
+ }
+ alc.free(alc.ctx, state);
+ }
+}
+
+yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
+ yyjson_read_err *err) {
+#define return_err_inv_param(_msg) do { \
+ err->pos = 0; \
+ err->msg = _msg; \
+ err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
+ return NULL; \
+} while (false)
+
+#define return_err(_pos, _code, _msg) do { \
+ if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
+ goto unexpected_end; \
+ } else { \
+ err->pos = (usize)(_pos - hdr); \
+ err->code = YYJSON_READ_ERROR_##_code; \
+ err->msg = _msg; \
+ } \
+ return NULL; \
+} while (false)
+
+#define val_incr() do { \
+ val++; \
+ if (unlikely(val >= val_end)) { \
+ usize alc_old = alc_len; \
+ alc_len += alc_len / 2; \
+ if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
+ val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
+ alc_old * sizeof(yyjson_val), \
+ alc_len * sizeof(yyjson_val)); \
+ if ((!val_tmp)) goto fail_alloc; \
+ val = val_tmp + (usize)(val - val_hdr); \
+ ctn = val_tmp + (usize)(ctn - val_hdr); \
+ state->val = val_tmp + (usize)(state->val - val_hdr); \
+ state->val_hdr = val_hdr = val_tmp; \
+ val_end = val_tmp + (alc_len - 2); \
+ state->val_end = val_end; \
+ } \
+} while (false)
+
+ /* save position where it's possible to resume incremental parsing */
+#define save_incr_state(_label) do { \
+ state->label = LABEL_##_label; \
+ state->cur = cur; \
+ state->val = val; \
+ state->ctn_len = ctn_len; \
+ state->hdr_len = hdr_len; \
+ if (unlikely(cur >= end)) goto unexpected_end; \
+} while (false)
+
+#define check_maybe_truncated_number() do { \
+ if (unlikely(cur >= end)) { \
+ if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
+ msg = "number too long"; \
+ goto fail_number; \
+ } \
+ goto unexpected_end; \
+ } \
+} while (false)
+
+ u8 *hdr = NULL, *end = NULL, *cur = NULL;
+ yyjson_read_flag flg;
+ yyjson_alc alc;
+ usize dat_len; /* data length in bytes, hint for allocator */
+ usize hdr_len; /* value count used by yyjson_doc */
+ usize alc_len; /* value count allocated */
+ usize alc_max; /* maximum value count for allocator */
+ usize ctn_len; /* the number of elements in current container */
+ yyjson_val *val_hdr; /* the head of allocated values */
+ yyjson_val *val_end; /* the end of allocated values */
+ yyjson_val *val_tmp; /* temporary pointer for realloc */
+ yyjson_val *val; /* current JSON value */
+ yyjson_val *ctn; /* current container */
+ yyjson_val *ctn_parent; /* parent of current container */
+ yyjson_doc *doc; /* the JSON document, equals to val_hdr */
+ const char *msg; /* error message */
+
+ yyjson_read_err tmp_err;
+ u8 raw_end[1]; /* raw end for null-terminator */
+ u8 *raw_ptr = raw_end;
+ u8 **pre = &raw_ptr; /* previous raw end pointer */
+ u8 **con = NULL; /* for incremental string parsing */
+ u8 saved_end = '\0'; /* saved end char */
+
+ /* validate input parameters */
+ if (!err) err = &tmp_err;
+ if (unlikely(!state)) {
+ return_err_inv_param("input state is NULL");
+ }
+ if (unlikely(!len)) {
+ return_err_inv_param("input length is 0");
+ }
+ if (unlikely(len > state->buf_len)) {
+ return_err_inv_param("length is greater than total input length");
+ }
+
+ /* restore state saved from the previous call */
+ hdr = state->hdr;
+ end = state->hdr + len;
+ cur = state->cur;
+ flg = state->flg;
+ alc = state->alc;
+ ctn_len = state->ctn_len;
+ hdr_len = state->hdr_len;
+ alc_len = state->alc_len;
+ val = state->val;
+ val_hdr = state->val_hdr;
+ val_end = state->val_end;
+ ctn = state->ctn;
+ con = state->str_con;
+ alc_max = USIZE_MAX / sizeof(yyjson_val);
+
+ /* insert null terminator to make us stop at the specified end, even if
+ the data contains more valid JSON */
+ saved_end = *end;
+ *end = '\0';
+
+ /* resume parsing from the last save point */
+ switch (state->label) {
+ case LABEL_doc_begin: goto doc_begin;
+ case LABEL_arr_val_begin: goto arr_val_begin;
+ case LABEL_arr_val_end: goto arr_val_end;
+ case LABEL_obj_key_begin: goto obj_key_begin;
+ case LABEL_obj_key_end: goto obj_key_end;
+ case LABEL_obj_val_begin: goto obj_val_begin;
+ case LABEL_obj_val_end: goto obj_val_end;
+ case LABEL_doc_end: goto doc_end;
+ default: return_err_inv_param("invalid incremental state");
+ }
+
+doc_begin:
+ /* skip empty contents before json document */
+ if (unlikely(!char_is_ctn(*cur))) {
+ while (char_is_space(*cur)) cur++;
+ if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
+ }
+
+ /* allocate memory for document */
+ if (!val_hdr) {
+ hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
+ hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
+ if (likely(char_is_ctn(*cur))) {
+ dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
+ alc_len = hdr_len +
+ (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
+ alc_len = yyjson_min(alc_len, alc_max);
+ } else {
+ alc_len = hdr_len + 1; /* single value */
+ }
+ val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
+ alc_len * sizeof(yyjson_val));
+ if (unlikely(!val_hdr)) goto fail_alloc;
+ val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
+ val = val_hdr + hdr_len;
+ ctn = val;
+ ctn_len = 0;
+ state->val_hdr = val_hdr;
+ state->val_end = val_end;
+ save_incr_state(doc_begin);
+ }
+
+ /* read json document */
+ if (*cur == '{') {
+ cur++;
+ ctn->tag = YYJSON_TYPE_OBJ;
+ ctn->uni.ofs = 0;
+ goto obj_key_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ ctn->tag = YYJSON_TYPE_ARR;
+ ctn->uni.ofs = 0;
+ goto arr_val_begin;
+ }
+ if (char_is_num(*cur)) {
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
+ goto fail_number;
+ }
+ if (*cur == '"') {
+ if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
+ goto fail_string;
+ }
+ if (*cur == 't') {
+ if (likely(read_true(&cur, val))) goto doc_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ if (likely(read_false(&cur, val))) goto doc_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ if (likely(read_null(&cur, val))) goto doc_end;
+ goto fail_literal_null;
+ }
+
+ msg = "unexpected character, expected a valid root value";
+ if (cur == hdr) {
+ /* RFC 8259: JSON text MUST be encoded using UTF-8 */
+ if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
+ else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
+ else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
+ }
+ return_err(cur, UNEXPECTED_CHARACTER, msg);
+
+arr_begin:
+ /* save current container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+
+ /* create a new array value, save parent container offset */
+ val_incr();
+ val->tag = YYJSON_TYPE_ARR;
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+
+ /* push the new array value as current container */
+ ctn = val;
+ ctn_len = 0;
+
+arr_val_begin:
+ save_incr_state(arr_val_begin);
+arr_val_continue:
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (char_is_num(*cur)) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
+ goto fail_number;
+ }
+ if (*cur == '"') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
+ goto arr_val_end;
+ goto fail_string;
+ }
+ if (*cur == 't') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto arr_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto arr_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val_incr();
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto arr_val_end;
+ goto fail_literal_null;
+ }
+ if (*cur == ']') {
+ cur++;
+ if (likely(ctn_len == 0)) goto arr_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_continue;
+ }
+ goto fail_character_val;
+
+arr_val_maybe_end:
+ /* if incremental parsing stops in the middle of a number, it may continue
+ with more digits, so arr val maybe didn't end yet */
+ check_maybe_truncated_number();
+
+arr_val_end:
+ save_incr_state(arr_val_end);
+ if (*cur == ',') {
+ cur++;
+ goto arr_val_begin;
+ }
+ if (*cur == ']') {
+ cur++;
+ goto arr_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto arr_val_end;
+ }
+ goto fail_character_arr_end;
+
+arr_end:
+ /* get parent container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+
+ /* save the next sibling value offset */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+
+ /* pop parent as current container */
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+obj_begin:
+ /* push container */
+ ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
+ (ctn->tag & YYJSON_TAG_MASK);
+ val_incr();
+ val->tag = YYJSON_TYPE_OBJ;
+ /* offset to the parent */
+ val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
+ ctn = val;
+ ctn_len = 0;
+
+obj_key_begin:
+ save_incr_state(obj_key_begin);
+obj_key_continue:
+ if (likely(*cur == '"')) {
+ val_incr();
+ ctn_len++;
+ if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
+ goto obj_key_end;
+ goto fail_string;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ if (likely(ctn_len == 0)) goto obj_end;
+ while (*cur != ',') cur--;
+ goto fail_trailing_comma;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_continue;
+ }
+ goto fail_character_obj_key;
+
+obj_key_end:
+ save_incr_state(obj_key_end);
+ if (*cur == ':') {
+ cur++;
+ goto obj_val_begin;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_key_end;
+ }
+ goto fail_character_obj_sep;
+
+obj_val_begin:
+ save_incr_state(obj_val_begin);
+obj_val_continue:
+ if (*cur == '"') {
+ val++;
+ ctn_len++;
+ if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
+ goto obj_val_end;
+ goto fail_string;
+ }
+ if (char_is_num(*cur)) {
+ val++;
+ ctn_len++;
+ if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
+ goto fail_number;
+ }
+ if (*cur == '{') {
+ cur++;
+ goto obj_begin;
+ }
+ if (*cur == '[') {
+ cur++;
+ goto arr_begin;
+ }
+ if (*cur == 't') {
+ val++;
+ ctn_len++;
+ if (likely(read_true(&cur, val))) goto obj_val_end;
+ goto fail_literal_true;
+ }
+ if (*cur == 'f') {
+ val++;
+ ctn_len++;
+ if (likely(read_false(&cur, val))) goto obj_val_end;
+ goto fail_literal_false;
+ }
+ if (*cur == 'n') {
+ val++;
+ ctn_len++;
+ if (likely(read_null(&cur, val))) goto obj_val_end;
+ goto fail_literal_null;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_continue;
+ }
+ goto fail_character_val;
+
+obj_val_maybe_end:
+ /* if incremental parsing stops in the middle of a number, it may continue
+ with more digits, so obj val maybe didn't end yet */
+ check_maybe_truncated_number();
+
+obj_val_end:
+ save_incr_state(obj_val_end);
+ if (likely(*cur == ',')) {
+ cur++;
+ goto obj_key_begin;
+ }
+ if (likely(*cur == '}')) {
+ cur++;
+ goto obj_end;
+ }
+ if (char_is_space(*cur)) {
+ while (char_is_space(*++cur));
+ goto obj_val_end;
+ }
+ goto fail_character_obj_end;
+
+obj_end:
+ /* pop container */
+ ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
+ /* point to the next value */
+ ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
+ ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
+ if (unlikely(ctn == ctn_parent)) goto doc_end;
+ ctn = ctn_parent;
+ ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
+ if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
+ goto obj_val_end;
+ } else {
+ goto arr_val_end;
+ }
+
+doc_end:
+ /* check invalid contents after json document */
+ if (unlikely(cur < end) && !has_flg(STOP_WHEN_DONE)) {
+ save_incr_state(doc_end);
+ while (char_is_space(*cur)) cur++;
+ if (unlikely(cur < end)) goto fail_garbage;
+ }
+
+ **pre = '\0';
+ doc = (yyjson_doc *)val_hdr;
+ doc->root = val_hdr + hdr_len;
+ doc->alc = alc;
+ doc->dat_read = (usize)(cur - hdr);
+ doc->val_read = (usize)((val - doc->root) + 1);
+ doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
+ state->hdr = NULL;
+ state->val_hdr = NULL;
+ memset(err, 0, sizeof(yyjson_read_err));
+ return doc;
+
+unexpected_end:
+ err->pos = len;
+ /* if no nore data, stop the incr read */
+ if (unlikely(len >= state->buf_len)) {
+ err->code = YYJSON_READ_ERROR_UNEXPECTED_END;
+ err->msg = MSG_NOT_END;
+ return NULL;
+ }
+ /* save parser state in extended error struct, in addition to what was
+ * stored in the last save_incr_state */
+ err->code = YYJSON_READ_ERROR_MORE;
+ err->msg = "need more data";
+ state->val_end = val_end;
+ state->ctn = ctn;
+ state->alc_len = alc_len;
+ /* restore the end where we've inserted a null terminator */
+ *end = saved_end;
+ return NULL;
+
+fail_string: return_err(cur, INVALID_STRING, msg);
+fail_number: return_err(cur, INVALID_NUMBER, msg);
+fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
+fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
+fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
+fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
+fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
+fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
+fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
+fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
+fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
+fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
+fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+
+#undef val_incr
+#undef return_err
+#undef return_err_inv_param
+#undef save_incr_state
+#undef check_maybe_truncated_number
+}
+
+#endif /* YYJSON_DISABLE_INCR_READER */
+
+#undef has_flg
+#undef has_allow
+#endif /* YYJSON_DISABLE_READER */
+
+
+
+#if !YYJSON_DISABLE_WRITER /* writer begin */
+
+/* Check write flag, avoids `always false` warning when disabled. */
+#define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
+#define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
+static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk,
+ bool non_standard) {
+#if YYJSON_DISABLE_NON_STANDARD
+ if (non_standard) return false;
+#endif
+ return (flg & chk) != 0;
+}
+
+/*==============================================================================
+ * MARK: - Integer Writer (Private)
+ *
+ * The maximum value of uint32_t is 4294967295 (10 digits),
+ * these digits are named as 'aabbccddee' here.
+ *
+ * Although most compilers may convert the "division by constant value" into
+ * "multiply and shift", manual conversion can still help some compilers
+ * generate fewer and better instructions.
+ *
+ * Reference:
+ * Division by Invariant Integers using Multiplication, 1994.
+ * https://gmplib.org/~tege/divcnst-pldi94.pdf
+ * Improved division by invariant integers, 2011.
+ * https://gmplib.org/~tege/division-paper.pdf
+ *============================================================================*/
+
+/** Digit table from 00 to 99. */
+yyjson_align(2)
+static const char digit_table[200] = {
+ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
+ '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
+ '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
+ '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
+ '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
+ '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+ '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
+ '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
+ '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
+ '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
+ '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
+ '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+ '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
+ '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
+ '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
+ '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
+ '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
+ '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+ '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
+ '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
+};
+
+static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
+ u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
+ aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
+ ccdd = val - aabb * 10000; /* (val % 10000) */
+ aa = (aabb * 5243) >> 19; /* (aabb / 100) */
+ cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
+ bb = aabb - aa * 100; /* (aabb % 100) */
+ dd = ccdd - cc * 100; /* (ccdd % 100) */
+ byte_copy_2(buf + 0, digit_table + aa * 2);
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ byte_copy_2(buf + 4, digit_table + cc * 2);
+ byte_copy_2(buf + 6, digit_table + dd * 2);
+ return buf + 8;
+}
+
+static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
+ u32 aa, bb; /* 4 digits: aabb */
+ aa = (val * 5243) >> 19; /* (val / 100) */
+ bb = val - aa * 100; /* (val % 100) */
+ byte_copy_2(buf + 0, digit_table + aa * 2);
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ return buf + 4;
+}
+
+static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) {
+ u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
+
+ if (val < 100) { /* 1-2 digits: aa */
+ lz = val < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + val * 2 + lz);
+ buf -= lz;
+ return buf + 2;
+
+ } else if (val < 10000) { /* 3-4 digits: aabb */
+ aa = (val * 5243) >> 19; /* (val / 100) */
+ bb = val - aa * 100; /* (val % 100) */
+ lz = aa < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ return buf + 4;
+
+ } else if (val < 1000000) { /* 5-6 digits: aabbcc */
+ aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
+ bbcc = val - aa * 10000; /* (val % 10000) */
+ bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
+ cc = bbcc - bb * 100; /* (bbcc % 100) */
+ lz = aa < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ byte_copy_2(buf + 4, digit_table + cc * 2);
+ return buf + 6;
+
+ } else { /* 7-8 digits: aabbccdd */
+ aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
+ ccdd = val - aabb * 10000; /* (val % 10000) */
+ aa = (aabb * 5243) >> 19; /* (aabb / 100) */
+ cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
+ bb = aabb - aa * 100; /* (aabb % 100) */
+ dd = ccdd - cc * 100; /* (ccdd % 100) */
+ lz = aa < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ byte_copy_2(buf + 4, digit_table + cc * 2);
+ byte_copy_2(buf + 6, digit_table + dd * 2);
+ return buf + 8;
+ }
+}
+
+static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) {
+ u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
+
+ if (val < 1000000) { /* 5-6 digits: aabbcc */
+ aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
+ bbcc = val - aa * 10000; /* (val % 10000) */
+ bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
+ cc = bbcc - bb * 100; /* (bbcc % 100) */
+ lz = aa < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ byte_copy_2(buf + 4, digit_table + cc * 2);
+ return buf + 6;
+
+ } else { /* 7-8 digits: aabbccdd */
+ aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
+ ccdd = val - aabb * 10000; /* (val % 10000) */
+ aa = (aabb * 5243) >> 19; /* (aabb / 100) */
+ cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
+ bb = aabb - aa * 100; /* (aabb % 100) */
+ dd = ccdd - cc * 100; /* (ccdd % 100) */
+ lz = aa < 10; /* leading zero: 0 or 1 */
+ byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + bb * 2);
+ byte_copy_2(buf + 4, digit_table + cc * 2);
+ byte_copy_2(buf + 6, digit_table + dd * 2);
+ return buf + 8;
+ }
+}
+
+static_inline u8 *write_u64(u64 val, u8 *buf) {
+ u64 tmp, hgh;
+ u32 mid, low;
+
+ if (val < 100000000) { /* 1-8 digits */
+ buf = write_u32_len_1_to_8((u32)val, buf);
+ return buf;
+
+ } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
+ hgh = val / 100000000; /* (val / 100000000) */
+ low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
+ buf = write_u32_len_1_to_8((u32)hgh, buf);
+ buf = write_u32_len_8(low, buf);
+ return buf;
+
+ } else { /* 17-20 digits */
+ tmp = val / 100000000; /* (val / 100000000) */
+ low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
+ hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
+ mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
+ buf = write_u32_len_5_to_8((u32)hgh, buf);
+ buf = write_u32_len_4(mid, buf);
+ buf = write_u32_len_8(low, buf);
+ return buf;
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - Number Writer (Private)
+ *============================================================================*/
+
+#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
+
+/** Trailing zero count table for number 0 to 99.
+ (generate with misc/make_tables.c) */
+static const u8 dec_trailing_zero_table[] = {
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
+ u64 hgh;
+ u32 low;
+ if (val < 100000000) { /* 1-8 digits */
+ buf = write_u32_len_1_to_8((u32)val, buf);
+ return buf;
+ } else { /* 9-16 digits */
+ hgh = val / 100000000; /* (val / 100000000) */
+ low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
+ buf = write_u32_len_1_to_8((u32)hgh, buf);
+ buf = write_u32_len_8(low, buf);
+ return buf;
+ }
+}
+
+static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
+ u64 hgh;
+ u32 mid, low, one;
+ if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
+ hgh = val / 100000000; /* (val / 100000000) */
+ low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
+ one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
+ mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
+ *buf = (u8)((u8)one + (u8)'0');
+ buf += one > 0;
+ buf = write_u32_len_8(mid, buf);
+ buf = write_u32_len_8(low, buf);
+ return buf;
+ } else if (val >= (u64)100000000){ /* len: 9 to 15 */
+ hgh = val / 100000000; /* (val / 100000000) */
+ low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
+ buf = write_u32_len_1_to_8((u32)hgh, buf);
+ buf = write_u32_len_8(low, buf);
+ return buf;
+ } else { /* len: 1 to 8 */
+ buf = write_u32_len_1_to_8((u32)val, buf);
+ return buf;
+ }
+}
+
+/**
+ Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
+ These digits are named as "abbccddee" here.
+ For example, input 123456000, output "123456".
+ */
+static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
+ bool lz;
+ u32 tz, tz1, tz2;
+
+ u32 abbcc = val / 10000; /* (abbccddee / 10000) */
+ u32 ddee = val - abbcc * 10000; /* (abbccddee % 10000) */
+ u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
+ u32 a = (abb * 41) >> 12; /* (abb / 100) */
+ u32 bb = abb - a * 100; /* (abb % 100) */
+ u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
+
+ /* write abbcc */
+ buf[0] = (u8)(a + '0');
+ buf += a > 0;
+ lz = bb < 10 && a == 0;
+ byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
+ buf -= lz;
+ byte_copy_2(buf + 2, digit_table + cc * 2);
+
+ if (ddee) {
+ u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
+ u32 ee = ddee - dd * 100; /* (ddee % 100) */
+ byte_copy_2(buf + 4, digit_table + dd * 2);
+ byte_copy_2(buf + 6, digit_table + ee * 2);
+ tz1 = dec_trailing_zero_table[dd];
+ tz2 = dec_trailing_zero_table[ee];
+ tz = ee ? tz2 : (tz1 + 2);
+ buf += 8 - tz;
+ return buf;
+ } else {
+ tz1 = dec_trailing_zero_table[bb];
+ tz2 = dec_trailing_zero_table[cc];
+ tz = cc ? tz2 : (tz1 + tz2);
+ buf += 4 - tz;
+ return buf;
+ }
+}
+
+/**
+ Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
+ These digits are named as "abbccddeeffgghhii" here.
+ For example, input 1234567890123000, output "1234567890123".
+ */
+static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
+ u32 tz, tz1, tz2;
+
+ u32 abbccddee = (u32)(val / 100000000);
+ u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
+ u32 abbcc = abbccddee / 10000;
+ u32 ddee = abbccddee - abbcc * 10000;
+ u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
+ u32 a = (abb * 41) >> 12; /* (abb / 100) */
+ u32 bb = abb - a * 100; /* (abb % 100) */
+ u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
+ buf[0] = (u8)(a + '0');
+ buf += a > 0;
+ byte_copy_2(buf + 0, digit_table + bb * 2);
+ byte_copy_2(buf + 2, digit_table + cc * 2);
+
+ if (ffgghhii) {
+ u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
+ u32 ee = ddee - dd * 100; /* (ddee % 100) */
+ u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
+ u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
+ u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
+ u32 gg = ffgg - ff * 100; /* (aabb % 100) */
+ byte_copy_2(buf + 4, digit_table + dd * 2);
+ byte_copy_2(buf + 6, digit_table + ee * 2);
+ byte_copy_2(buf + 8, digit_table + ff * 2);
+ byte_copy_2(buf + 10, digit_table + gg * 2);
+ if (hhii) {
+ u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
+ u32 ii = hhii - hh * 100; /* (ccdd % 100) */
+ byte_copy_2(buf + 12, digit_table + hh * 2);
+ byte_copy_2(buf + 14, digit_table + ii * 2);
+ tz1 = dec_trailing_zero_table[hh];
+ tz2 = dec_trailing_zero_table[ii];
+ tz = ii ? tz2 : (tz1 + 2);
+ return buf + 16 - tz;
+ } else {
+ tz1 = dec_trailing_zero_table[ff];
+ tz2 = dec_trailing_zero_table[gg];
+ tz = gg ? tz2 : (tz1 + 2);
+ return buf + 12 - tz;
+ }
+ } else {
+ if (ddee) {
+ u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
+ u32 ee = ddee - dd * 100; /* (ddee % 100) */
+ byte_copy_2(buf + 4, digit_table + dd * 2);
+ byte_copy_2(buf + 6, digit_table + ee * 2);
+ tz1 = dec_trailing_zero_table[dd];
+ tz2 = dec_trailing_zero_table[ee];
+ tz = ee ? tz2 : (tz1 + 2);
+ return buf + 8 - tz;
+ } else {
+ tz1 = dec_trailing_zero_table[bb];
+ tz2 = dec_trailing_zero_table[cc];
+ tz = cc ? tz2 : (tz1 + tz2);
+ return buf + 4 - tz;
+ }
+ }
+}
+
+/** Write exponent part in range `e-45` to `e38`. */
+static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
+ bool lz;
+ byte_copy_2(buf, "e-");
+ buf += 2 - (exp >= 0);
+ exp = exp < 0 ? -exp : exp;
+ lz = exp < 10;
+ byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
+ return buf + 2 - lz;
+}
+
+/** Write exponent part in range `e-324` to `e308`. */
+static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
+ byte_copy_2(buf, "e-");
+ buf += 2 - (exp >= 0);
+ exp = exp < 0 ? -exp : exp;
+ if (exp < 100) {
+ bool lz = exp < 10;
+ byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
+ return buf + 2 - lz;
+ } else {
+ u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
+ u32 lo = (u32)exp - hi * 100; /* exp % 100 */
+ buf[0] = (u8)((u8)hi + (u8)'0');
+ byte_copy_2(buf + 1, digit_table + lo * 2);
+ return buf + 3;
+ }
+}
+
+/** Magic number for fast `divide by power of 10`. */
+typedef struct {
+ u64 p10, mul;
+ u32 shr1, shr2;
+} div_pow10_magic;
+
+/** Generated with llvm, see https://github.com/llvm/llvm-project/
+ blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
+static const div_pow10_magic div_pow10_table[] = {
+ { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0, 0 },
+ { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0, 3 },
+ { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2, 2 },
+ { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3, 4 },
+ { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0, 11 },
+ { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5, 7 },
+ { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0, 18 },
+ { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0, 23 },
+ { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0, 26 },
+ { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9, 11 },
+ { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0, 33 },
+ { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0, 36 },
+ { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0, 37 },
+ { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0, 41 },
+ { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0, 42 },
+ { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
+ { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0, 51 },
+ { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
+ { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
+ { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0, 62 },
+};
+
+/** Divide a number by power of 10. */
+static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
+ u64 hi, lo;
+ div_pow10_magic m = div_pow10_table[exp];
+ u128_mul(num >> m.shr1, m.mul, &hi, &lo);
+ *div = hi >> m.shr2;
+ *mod = num - (*div * m.p10);
+ *p10 = m.p10;
+}
+
+/** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
+static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
+ u64 hi, lo;
+ u32 y_hi, y_lo;
+ u128_mul(cp, u, &hi, &lo);
+ y_hi = (u32)hi;
+ y_lo = (u32)(lo >> 32);
+ return y_hi | (y_lo > 1);
+}
+
+/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
+static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
+ u64 x_hi, x_lo, y_hi, y_lo;
+ u128_mul(cp, lo, &x_hi, &x_lo);
+ u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
+ return y_hi | (y_lo > 1);
+}
+
+/** Convert f32 from binary to decimal (shortest but may have trailing zeros).
+ The input should not be 0, inf or nan. */
+static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
+ u32 sig_bin, i32 exp_bin,
+ u32 *sig_dec, i32 *exp_dec) {
+
+ bool is_even, irregular, round_up, trim;
+ bool u0_inside, u1_inside, w0_inside, w1_inside;
+ u64 p10_hi, p10_lo, hi, lo;
+ u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
+ i32 k, h;
+
+ /* Fast path, see f64_bin_to_dec(). */
+ while (likely(sig_raw)) {
+ u32 mod, dec, add_1, add_10, s_hi, s_lo;
+ u32 c, half_ulp, t0, t1;
+
+ /* k = floor(exp_bin * log10(2)); */
+ /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
+ k = (i32)(exp_bin * 315653) >> 20;
+ h = exp_bin + ((-k * 217707) >> 16);
+ pow10_table_get_sig(-k, &p10_hi, &p10_lo);
+
+ /* sig_bin << (1/2/3/4) */
+ cb = sig_bin << (h + 1);
+ u128_mul(cb, p10_hi, &hi, &lo);
+ s_hi = (u32)(hi);
+ s_lo = (u32)(lo >> 32);
+ mod = s_hi % 10;
+ dec = s_hi - mod;
+
+ /* right shift 4 to fit in u32 */
+ c = (mod << (32 - 4)) | (s_lo >> 4);
+ half_ulp = (u32)(p10_hi >> (32 + 4 - h));
+
+ /* check w1, u0, w0 range */
+ w1_inside = (s_lo >= ((u32)1 << 31));
+ if (unlikely(s_lo == ((u32)1 << 31))) break;
+ u0_inside = (half_ulp >= c);
+ if (unlikely(half_ulp == c)) break;
+ t0 = (u32)10 << (32 - 4);
+ t1 = c + half_ulp;
+ w0_inside = (t1 >= t0);
+ if (unlikely(t0 - t1 <= (u32)1)) break;
+
+ trim = (u0_inside | w0_inside);
+ add_10 = (w0_inside ? 10 : 0);
+ add_1 = mod + w1_inside;
+ *sig_dec = dec + (trim ? add_10 : add_1);
+ *exp_dec = k;
+ return;
+ }
+
+ /* Schubfach algorithm, see f64_bin_to_dec(). */
+ irregular = (sig_raw == 0 && exp_raw > 1);
+ is_even = !(sig_bin & 1);
+ cbl = 4 * sig_bin - 2 + irregular;
+ cb = 4 * sig_bin;
+ cbr = 4 * sig_bin + 2;
+
+ /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
+ /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
+ k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
+ h = exp_bin + ((-k * 217707) >> 16) + 1;
+ pow10_table_get_sig(-k, &p10_hi, &p10_lo);
+ p10_hi += 1;
+
+ vbl = u64_round_to_odd(p10_hi, cbl << h);
+ vb = u64_round_to_odd(p10_hi, cb << h);
+ vbr = u64_round_to_odd(p10_hi, cbr << h);
+ lower = vbl + !is_even;
+ upper = vbr - !is_even;
+
+ s = vb / 4;
+ if (s >= 10) {
+ sp = s / 10;
+ u0_inside = (lower <= 40 * sp);
+ w0_inside = (upper >= 40 * sp + 40);
+ if (u0_inside != w0_inside) {
+ *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
+ *exp_dec = k;
+ return;
+ }
+ }
+ u1_inside = (lower <= 4 * s);
+ w1_inside = (upper >= 4 * s + 4);
+ mid = 4 * s + 2;
+ round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
+ *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
+ *exp_dec = k;
+}
+
+/** Convert f64 from binary to decimal (shortest but may have trailing zeros).
+ The input should not be 0, inf or nan. */
+static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
+ u64 sig_bin, i32 exp_bin,
+ u64 *sig_dec, i32 *exp_dec) {
+
+ bool is_even, irregular, round_up, trim;
+ bool u0_inside, u1_inside, w0_inside, w1_inside;
+ u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
+ i32 k, h;
+
+ /*
+ Fast path:
+ For regular spacing significand 'c', there are 4 candidates:
+
+ u0 u1 c w1 w0
+ ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
+ 9 0 1 2 3 4 5 6 7 8 9 0 1
+ |___________________|___________________|
+ 1ulp
+
+ The `1ulp` is in the range [1.0, 10.0).
+ If (c - 0.5ulp < u0), trim the last digit and round down.
+ If (c + 0.5ulp > w0), trim the last digit and round up.
+ If (c - 0.5ulp < u1), round down.
+ If (c + 0.5ulp > w1), round up.
+ */
+ while (likely(sig_raw)) {
+ u64 mod, dec, add_1, add_10, s_hi, s_lo;
+ u64 c, half_ulp, t0, t1;
+
+ /* k = floor(exp_bin * log10(2)); */
+ /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
+ k = (i32)(exp_bin * 315653) >> 20;
+ h = exp_bin + ((-k * 217707) >> 16);
+ pow10_table_get_sig(-k, &p10_hi, &p10_lo);
+
+ /* sig_bin << (1/2/3/4) */
+ cb = sig_bin << (h + 1);
+ u128_mul(cb, p10_lo, &s_hi, &s_lo);
+ u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
+ mod = s_hi % 10;
+ dec = s_hi - mod;
+
+ /* right shift 4 to fit in u64 */
+ c = (mod << (64 - 4)) | (s_lo >> 4);
+ half_ulp = p10_hi >> (4 - h);
+
+ /* check w1, u0, w0 range */
+ w1_inside = (s_lo >= ((u64)1 << 63));
+ if (unlikely(s_lo == ((u64)1 << 63))) break;
+ u0_inside = (half_ulp >= c);
+ if (unlikely(half_ulp == c)) break;
+ t0 = ((u64)10 << (64 - 4));
+ t1 = c + half_ulp;
+ w0_inside = (t1 >= t0);
+ if (unlikely(t0 - t1 <= (u64)1)) break;
+
+ trim = (u0_inside | w0_inside);
+ add_10 = (w0_inside ? 10 : 0);
+ add_1 = mod + w1_inside;
+ *sig_dec = dec + (trim ? add_10 : add_1);
+ *exp_dec = k;
+ return;
+ }
+
+ /*
+ Schubfach algorithm:
+ Raffaello Giulietti, The Schubfach way to render doubles, 2022.
+ https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
+ https://github.com/openjdk/jdk/pull/3402 (Java implementation)
+ https://github.com/abolz/Drachennest (C++ implementation)
+ */
+ irregular = (sig_raw == 0 && exp_raw > 1);
+ is_even = !(sig_bin & 1);
+ cbl = 4 * sig_bin - 2 + irregular;
+ cb = 4 * sig_bin;
+ cbr = 4 * sig_bin + 2;
+
+ /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
+ /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
+ k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
+ h = exp_bin + ((-k * 217707) >> 16) + 1;
+ pow10_table_get_sig(-k, &p10_hi, &p10_lo);
+ p10_lo += 1;
+
+ vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
+ vb = u128_round_to_odd(p10_hi, p10_lo, cb << h);
+ vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
+ lower = vbl + !is_even;
+ upper = vbr - !is_even;
+
+ s = vb / 4;
+ if (s >= 10) {
+ sp = s / 10;
+ u0_inside = (lower <= 40 * sp);
+ w0_inside = (upper >= 40 * sp + 40);
+ if (u0_inside != w0_inside) {
+ *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
+ *exp_dec = k;
+ return;
+ }
+ }
+ u1_inside = (lower <= 4 * s);
+ w1_inside = (upper >= 4 * s + 4);
+ mid = 4 * s + 2;
+ round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
+ *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
+ *exp_dec = k;
+}
+
+/** Convert f64 from binary to decimal (fast but not the shortest).
+ The input should not be 0, inf, nan. */
+static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
+ u64 sig_bin, i32 exp_bin,
+ u64 *sig_dec, i32 *exp_dec,
+ bool *round_up) {
+ u64 cb, p10_hi, p10_lo, s_hi, s_lo;
+ i32 k, h;
+ bool irregular, u;
+
+ irregular = (sig_raw == 0 && exp_raw > 1);
+
+ /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
+ /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
+ k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
+ h = exp_bin + ((-k * 217707) >> 16);
+ pow10_table_get_sig(-k, &p10_hi, &p10_lo);
+
+ /* sig_bin << (1/2/3/4) */
+ cb = sig_bin << (h + 1);
+ u128_mul(cb, p10_lo, &s_hi, &s_lo);
+ u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
+
+ /* round up */
+ u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
+
+ *sig_dec = s_hi + u;
+ *exp_dec = k;
+ *round_up = u;
+ return;
+}
+
+/** Write inf/nan if allowed. */
+static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
+ u64 sig_raw, bool sign) {
+ if (has_flg(INF_AND_NAN_AS_NULL)) {
+ byte_copy_4(buf, "null");
+ return buf + 4;
+ }
+ if (has_allow(INF_AND_NAN)) {
+ if (sig_raw == 0) {
+ buf[0] = '-';
+ buf += sign;
+ byte_copy_8(buf, "Infinity");
+ return buf + 8;
+ } else {
+ byte_copy_4(buf, "NaN");
+ return buf + 3;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Write a float number (requires 40 bytes buffer).
+ We follow the ECMAScript specification for printing floating-point numbers,
+ similar to `Number.prototype.toString()`, but with the following changes:
+ 1. Keep the negative sign of `-0.0` to preserve input information.
+ 2. Keep decimal point to indicate the number is floating point.
+ 3. Remove positive sign in the exponent part.
+ */
+static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
+ yyjson_write_flag flg) {
+ u32 sig_bin, sig_dec, sig_raw;
+ i32 exp_bin, exp_dec, sig_len, dot_ofs;
+ u32 exp_raw, raw;
+ u8 *end;
+ bool sign;
+
+ /* cast double to float */
+ raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
+
+ /* decode raw bytes from IEEE-754 double format. */
+ sign = (bool)(raw >> (F32_BITS - 1));
+ sig_raw = raw & F32_SIG_MASK;
+ exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
+
+ /* return inf or nan */
+ if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
+ return write_inf_or_nan(buf, flg, sig_raw, sign);
+ }
+
+ /* add sign for all finite number */
+ buf[0] = '-';
+ buf += sign;
+
+ /* return zero */
+ if ((raw << 1) == 0) {
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+
+ if (likely(exp_raw != 0)) {
+ /* normal number */
+ sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
+ exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
+
+ /* fast path for small integer number without fraction */
+ if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
+ (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
+ sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
+ buf = write_u32_len_1_to_8(sig_dec, buf);
+ byte_copy_2(buf, ".0");
+ return buf + 2;
+ }
+
+ /* binary to decimal */
+ f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
+
+ /* the sig length is 7 or 9 */
+ sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
+
+ /* the decimal point offset relative to the first digit */
+ dot_ofs = sig_len + exp_dec;
+
+ if (-6 < dot_ofs && dot_ofs <= 21) {
+ i32 num_sep_pos, dot_set_pos, pre_ofs;
+ u8 *num_hdr, *num_end, *num_sep, *dot_end;
+ bool no_pre_zero;
+
+ /* fill zeros */
+ memset(buf, '0', 32);
+
+ /* not prefixed with zero, e.g. 1.234, 1234.0 */
+ no_pre_zero = (dot_ofs > 0);
+
+ /* write the number as digits */
+ pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
+ num_hdr = buf + pre_ofs;
+ num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
+
+ /* seperate these digits to leave a space for dot */
+ num_sep_pos = no_pre_zero ? dot_ofs : 0;
+ num_sep = num_hdr + num_sep_pos;
+ byte_move_8(num_sep + no_pre_zero, num_sep);
+ num_end += no_pre_zero;
+
+ /* write the dot */
+ dot_set_pos = yyjson_max(dot_ofs, 1);
+ buf[dot_set_pos] = '.';
+
+ /* return the ending */
+ dot_end = buf + dot_ofs + 2;
+ return yyjson_max(dot_end, num_end);
+
+ } else {
+ /* write with scientific notation, e.g. 1.234e56 */
+ end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
+ end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
+ exp_dec += sig_len - 1;
+ buf[0] = buf[1];
+ buf[1] = '.';
+ return write_f32_exp(exp_dec, end);
+ }
+
+ } else {
+ /* subnormal number */
+ sig_bin = sig_raw;
+ exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
+
+ /* binary to decimal */
+ f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
+
+ /* write significand part */
+ end = write_u32_len_1_to_8(sig_dec, buf + 1);
+ buf[0] = buf[1];
+ buf[1] = '.';
+ exp_dec += (i32)(end - buf) - 2;
+
+ /* trim trailing zeros */
+ end -= *(end - 1) == '0'; /* branchless for last zero */
+ end -= *(end - 1) == '0'; /* branchless for second last zero */
+ while (*(end - 1) == '0') end--; /* for unlikely more zeros */
+ end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
+
+ /* write exponent part */
+ return write_f32_exp(exp_dec, end);
+ }
+}
+
+/**
+ Write a double number (requires 40 bytes buffer).
+ We follow the ECMAScript specification for printing floating-point numbers,
+ similar to `Number.prototype.toString()`, but with the following changes:
+ 1. Keep the negative sign of `-0.0` to preserve input information.
+ 2. Keep decimal point to indicate the number is floating point.
+ 3. Remove positive sign in the exponent part.
+ */
+static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
+ u64 sig_bin, sig_dec, sig_raw;
+ i32 exp_bin, exp_dec, sig_len, dot_ofs;
+ u32 exp_raw;
+ u8 *end;
+ bool sign;
+
+ /* decode raw bytes from IEEE-754 double format. */
+ sign = (bool)(raw >> (F64_BITS - 1));
+ sig_raw = raw & F64_SIG_MASK;
+ exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
+
+ /* return inf or nan */
+ if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
+ return write_inf_or_nan(buf, flg, sig_raw, sign);
+ }
+
+ /* add sign for all finite number */
+ buf[0] = '-';
+ buf += sign;
+
+ /* return zero */
+ if ((raw << 1) == 0) {
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+
+ if (likely(exp_raw != 0)) {
+ /* normal number */
+ sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
+ exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
+
+ /* fast path for small integer number without fraction */
+ if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
+ (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
+ sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
+ buf = write_u64_len_1_to_16(sig_dec, buf);
+ byte_copy_2(buf, ".0");
+ return buf + 2;
+ }
+
+ /* binary to decimal */
+ f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
+
+ /* the sig length is 16 or 17 */
+ sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
+
+ /* the decimal point offset relative to the first digit */
+ dot_ofs = sig_len + exp_dec;
+
+ if (-6 < dot_ofs && dot_ofs <= 21) {
+ i32 num_sep_pos, dot_set_pos, pre_ofs;
+ u8 *num_hdr, *num_end, *num_sep, *dot_end;
+ bool no_pre_zero;
+
+ /* fill zeros */
+ memset(buf, '0', 32);
+
+ /* not prefixed with zero, e.g. 1.234, 1234.0 */
+ no_pre_zero = (dot_ofs > 0);
+
+ /* write the number as digits */
+ pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
+ num_hdr = buf + pre_ofs;
+ num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
+
+ /* seperate these digits to leave a space for dot */
+ num_sep_pos = no_pre_zero ? dot_ofs : 0;
+ num_sep = num_hdr + num_sep_pos;
+ byte_move_16(num_sep + no_pre_zero, num_sep);
+ num_end += no_pre_zero;
+
+ /* write the dot */
+ dot_set_pos = yyjson_max(dot_ofs, 1);
+ buf[dot_set_pos] = '.';
+
+ /* return the ending */
+ dot_end = buf + dot_ofs + 2;
+ return yyjson_max(dot_end, num_end);
+
+ } else {
+ /* write with scientific notation, e.g. 1.234e56 */
+ end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
+ end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
+ exp_dec += sig_len - 1;
+ buf[0] = buf[1];
+ buf[1] = '.';
+ return write_f64_exp(exp_dec, end);
+ }
+
+ } else {
+ /* subnormal number */
+ sig_bin = sig_raw;
+ exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
+
+ /* binary to decimal */
+ f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
+
+ /* write significand part */
+ end = write_u64_len_1_to_17(sig_dec, buf + 1);
+ buf[0] = buf[1];
+ buf[1] = '.';
+ exp_dec += (i32)(end - buf) - 2;
+
+ /* trim trailing zeros */
+ end -= *(end - 1) == '0'; /* branchless for last zero */
+ end -= *(end - 1) == '0'; /* branchless for second last zero */
+ while (*(end - 1) == '0') end--; /* for unlikely more zeros */
+ end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
+
+ /* write exponent part */
+ return write_f64_exp(exp_dec, end);
+ }
+}
+
+/**
+ Write a double number using fixed-point notation (requires 40 bytes buffer).
+
+ We follow the ECMAScript specification for printing floating-point numbers,
+ similar to `Number.prototype.toFixed(prec)`, but with the following changes:
+ 1. Keep the negative sign of `-0.0` to preserve input information.
+ 2. Keep decimal point to indicate the number is floating point.
+ 3. Remove positive sign in the exponent part.
+ 4. Remove trailing zeros and reduce unnecessary precision.
+ */
+static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg,
+ u32 prec) {
+ u64 sig_bin, sig_dec, sig_raw;
+ i32 exp_bin, exp_dec, sig_len, dot_ofs;
+ u32 exp_raw;
+ u8 *end;
+ bool sign;
+
+ /* decode raw bytes from IEEE-754 double format. */
+ sign = (bool)(raw >> (F64_BITS - 1));
+ sig_raw = raw & F64_SIG_MASK;
+ exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
+
+ /* return inf or nan */
+ if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
+ return write_inf_or_nan(buf, flg, sig_raw, sign);
+ }
+
+ /* add sign for all finite number */
+ buf[0] = '-';
+ buf += sign;
+
+ /* return zero */
+ if ((raw << 1) == 0) {
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+
+ if (likely(exp_raw != 0)) {
+ /* normal number */
+ sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
+ exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
+
+ /* fast path for small integer number without fraction */
+ if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
+ (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
+ sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
+ buf = write_u64_len_1_to_16(sig_dec, buf);
+ byte_copy_2(buf, ".0");
+ return buf + 2;
+ }
+
+ /* only `fabs(num) < 1e21` are processed here. */
+ if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
+ i32 num_sep_pos, dot_set_pos, pre_ofs;
+ u8 *num_hdr, *num_end, *num_sep;
+ bool round_up, no_pre_zero;
+
+ /* binary to decimal */
+ f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
+ &sig_dec, &exp_dec, &round_up);
+
+ /* the sig length is 16 or 17 */
+ sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
+
+ /* limit the length of digits after the decimal point */
+ if (exp_dec < -1) {
+ i32 sig_len_cut = -exp_dec - (i32)prec;
+ if (sig_len_cut > sig_len) {
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+ if (sig_len_cut > 0) {
+ u64 div, mod, p10;
+
+ /* remove round up */
+ sig_dec -= round_up;
+ sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
+
+ /* cut off some digits */
+ div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
+
+ /* add round up */
+ sig_dec = div + (mod >= p10 / 2);
+
+ /* update exp and sig length */
+ exp_dec += sig_len_cut;
+ sig_len -= sig_len_cut;
+ sig_len += (sig_len >= 0) &&
+ (sig_dec >= div_pow10_table[sig_len].p10);
+ }
+ if (sig_len <= 0) {
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+ }
+
+ /* fill zeros */
+ memset(buf, '0', 32);
+
+ /* the decimal point offset relative to the first digit */
+ dot_ofs = sig_len + exp_dec;
+
+ /* not prefixed with zero, e.g. 1.234, 1234.0 */
+ no_pre_zero = (dot_ofs > 0);
+
+ /* write the number as digits */
+ pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
+ num_hdr = buf + pre_ofs;
+ num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
+
+ /* seperate these digits to leave a space for dot */
+ num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
+ num_sep = buf + num_sep_pos;
+ byte_move_16(num_sep + 1, num_sep);
+ num_end += (exp_dec < 0);
+
+ /* write the dot */
+ dot_set_pos = yyjson_max(dot_ofs, 1);
+ buf[dot_set_pos] = '.';
+
+ /* remove trailing zeros */
+ buf += dot_set_pos + 2;
+ buf = yyjson_max(buf, num_end);
+ buf -= *(buf - 1) == '0'; /* branchless for last zero */
+ buf -= *(buf - 1) == '0'; /* branchless for second last zero */
+ while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
+ buf += *(buf - 1) == '.'; /* keep a zero after dot */
+ return buf;
+
+ } else {
+ /* binary to decimal */
+ f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
+ &sig_dec, &exp_dec);
+
+ /* the sig length is 16 or 17 */
+ sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
+
+ /* write with scientific notation, e.g. 1.234e56 */
+ end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
+ end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
+ exp_dec += sig_len - 1;
+ buf[0] = buf[1];
+ buf[1] = '.';
+ return write_f64_exp(exp_dec, end);
+ }
+ } else {
+ /* subnormal number */
+ byte_copy_4(buf, "0.0");
+ return buf + 3;
+ }
+}
+
+#else /* FP_WRITER */
+
+#if YYJSON_MSC_VER >= 1400
+#define snprintf_num(buf, len, fmt, dig, val) \
+ sprintf_s((char *)buf, len, fmt, dig, val)
+#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
+#define snprintf_num(buf, len, fmt, dig, val) \
+ snprintf((char *)buf, len, fmt, dig, val)
+#else
+#define snprintf_num(buf, len, fmt, dig, val) \
+ sprintf((char *)buf, fmt, dig, val)
+#endif
+
+static_noinline u8 *write_fp_reformat(u8 *buf, int len,
+ yyjson_write_flag flg, bool fixed) {
+ u8 *cur = buf;
+ if (unlikely(len < 1)) return NULL;
+ cur += (*cur == '-');
+ if (unlikely(!char_is_digit(*cur))) {
+ /* nan, inf, or bad output */
+ if (has_flg(INF_AND_NAN_AS_NULL)) {
+ byte_copy_4(buf, "null");
+ return buf + 4;
+ } else if (has_allow(INF_AND_NAN)) {
+ if (*cur == 'i') {
+ byte_copy_8(cur, "Infinity");
+ return cur + 8;
+ } else if (*cur == 'n') {
+ byte_copy_4(buf, "NaN");
+ return buf + 3;
+ }
+ }
+ return NULL;
+ } else {
+ /* finite number */
+ u8 *end = buf + len, *dot = NULL, *exp = NULL;
+
+ /*
+ The snprintf() function is locale-dependent. For currently known
+ locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
+ while other locales use ',' as the decimal point. we need to replace
+ ',' with '.' to avoid the locale setting.
+ */
+ for (; cur < end; cur++) {
+ switch (*cur) {
+ case ',': *cur = '.'; /* fallthrough */
+ case '.': dot = cur; break;
+ case 'e': exp = cur; break;
+ default: break;
+ }
+ }
+ if (fixed) {
+ /* remove trailing zeros */
+ while (*(end - 1) == '0') end--;
+ end += *(end - 1) == '.';
+ } else {
+ if (!dot && !exp) {
+ /* add decimal point, e.g. 123 -> 123.0 */
+ byte_copy_2(end, ".0");
+ end += 2;
+ } else if (exp) {
+ cur = exp + 1;
+ /* remove positive sign in the exponent part */
+ if (*cur == '+') {
+ memmove(cur, cur + 1, (usize)(end - cur - 1));
+ end--;
+ }
+ cur += (*cur == '-');
+ /* remove leading zeros in the exponent part */
+ if (*cur == '0') {
+ u8 *hdr = cur++;
+ while (*cur == '0') cur++;
+ memmove(hdr, cur, (usize)(end - cur));
+ end -= (usize)(cur - hdr);
+ }
+ }
+ }
+ return end;
+ }
+}
+
+/** Write a double number (requires 40 bytes buffer). */
+static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
+#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
+ int dig = DBL_DECIMAL_DIG;
+#else
+ int dig = F64_DEC_DIG;
+#endif
+ f64 val = f64_from_bits(raw);
+ int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
+ return write_fp_reformat(buf, len, flg, false);
+}
+
+/** Write a double number (requires 40 bytes buffer). */
+static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
+#if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
+ int dig = FLT_DECIMAL_DIG;
+#else
+ int dig = F32_DEC_DIG;
+#endif
+ f64 val = (f64)f64_to_f32(f64_from_bits(raw));
+ int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
+ return write_fp_reformat(buf, len, flg, false);
+}
+
+/** Write a double number (requires 40 bytes buffer). */
+static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw,
+ yyjson_write_flag flg, u32 prec) {
+ f64 val = (f64)f64_from_bits(raw);
+ if (-1e21 < val && val < 1e21) {
+ int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
+ return write_fp_reformat(buf, len, flg, true);
+ } else {
+ return write_f64_raw(buf, raw, flg);
+ }
+}
+
+#endif /* FP_WRITER */
+
+/** Write a JSON number (requires 40 bytes buffer). */
+static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) {
+ if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
+ u64 pos = val->uni.u64;
+ u64 neg = ~pos + 1;
+ usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
+ *cur = '-';
+ return write_u64(sign ? neg : pos, cur + sign);
+ } else {
+ u64 raw = val->uni.u64;
+ u32 val_fmt = (u32)(val->tag >> 32);
+ u32 all_fmt = flg;
+ u32 fmt = val_fmt | all_fmt;
+ if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
+ /* double to shortest */
+ return write_f64_raw(cur, raw, flg);
+ } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
+ /* double to fixed */
+ u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
+ u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
+ u32 prec = val_prec ? val_prec : all_prec;
+ return write_f64_raw_fixed(cur, raw, flg, prec);
+ } else {
+ if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
+ /* float to shortest */
+ return write_f32_raw(cur, raw, flg);
+ } else {
+ /* double to shortest */
+ return write_f64_raw(cur, raw, flg);
+ }
+ }
+ }
+}
+
+char *yyjson_write_number(const yyjson_val *val, char *buf) {
+ if (unlikely(!val || !buf)) return NULL;
+ switch (val->tag & YYJSON_TAG_MASK) {
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: {
+ buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
+ *buf = '\0';
+ return buf;
+ }
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: {
+ u64 pos = val->uni.u64;
+ u64 neg = ~pos + 1;
+ usize sign = ((i64)pos < 0);
+ *buf = '-';
+ buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
+ *buf = '\0';
+ return buf;
+ }
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: {
+ u64 raw = val->uni.u64;
+ u32 fmt = (u32)(val->tag >> 32);
+ u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN;
+ if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
+ buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
+ } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
+ u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
+ buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
+ } else {
+ if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
+ buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
+ } else {
+ buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
+ }
+ }
+ if (buf) *buf = '\0';
+ return buf;
+ }
+ default: return NULL;
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - String Writer (Private)
+ *============================================================================*/
+
+/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
+typedef u8 char_enc_type;
+#define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
+#define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
+#define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
+#define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
+#define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
+#define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
+#define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
+#define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
+#define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
+#define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
+
+/** Character encode type table: don't escape unicode, don't escape '/'.
+ (generate with misc/make_tables.c) */
+static const char_enc_type enc_table_cpy[256] = {
+ 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/** Character encode type table: don't escape unicode, escape '/'.
+ (generate with misc/make_tables.c) */
+static const char_enc_type enc_table_cpy_slash[256] = {
+ 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/** Character encode type table: escape unicode, don't escape '/'.
+ (generate with misc/make_tables.c) */
+static const char_enc_type enc_table_esc[256] = {
+ 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/** Character encode type table: escape unicode, escape '/'.
+ (generate with misc/make_tables.c) */
+static const char_enc_type enc_table_esc_slash[256] = {
+ 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
+ (generate with misc/make_tables.c) */
+yyjson_align(2)
+static const u8 esc_hex_char_table[512] = {
+ '0', '0', '0', '1', '0', '2', '0', '3',
+ '0', '4', '0', '5', '0', '6', '0', '7',
+ '0', '8', '0', '9', '0', 'A', '0', 'B',
+ '0', 'C', '0', 'D', '0', 'E', '0', 'F',
+ '1', '0', '1', '1', '1', '2', '1', '3',
+ '1', '4', '1', '5', '1', '6', '1', '7',
+ '1', '8', '1', '9', '1', 'A', '1', 'B',
+ '1', 'C', '1', 'D', '1', 'E', '1', 'F',
+ '2', '0', '2', '1', '2', '2', '2', '3',
+ '2', '4', '2', '5', '2', '6', '2', '7',
+ '2', '8', '2', '9', '2', 'A', '2', 'B',
+ '2', 'C', '2', 'D', '2', 'E', '2', 'F',
+ '3', '0', '3', '1', '3', '2', '3', '3',
+ '3', '4', '3', '5', '3', '6', '3', '7',
+ '3', '8', '3', '9', '3', 'A', '3', 'B',
+ '3', 'C', '3', 'D', '3', 'E', '3', 'F',
+ '4', '0', '4', '1', '4', '2', '4', '3',
+ '4', '4', '4', '5', '4', '6', '4', '7',
+ '4', '8', '4', '9', '4', 'A', '4', 'B',
+ '4', 'C', '4', 'D', '4', 'E', '4', 'F',
+ '5', '0', '5', '1', '5', '2', '5', '3',
+ '5', '4', '5', '5', '5', '6', '5', '7',
+ '5', '8', '5', '9', '5', 'A', '5', 'B',
+ '5', 'C', '5', 'D', '5', 'E', '5', 'F',
+ '6', '0', '6', '1', '6', '2', '6', '3',
+ '6', '4', '6', '5', '6', '6', '6', '7',
+ '6', '8', '6', '9', '6', 'A', '6', 'B',
+ '6', 'C', '6', 'D', '6', 'E', '6', 'F',
+ '7', '0', '7', '1', '7', '2', '7', '3',
+ '7', '4', '7', '5', '7', '6', '7', '7',
+ '7', '8', '7', '9', '7', 'A', '7', 'B',
+ '7', 'C', '7', 'D', '7', 'E', '7', 'F',
+ '8', '0', '8', '1', '8', '2', '8', '3',
+ '8', '4', '8', '5', '8', '6', '8', '7',
+ '8', '8', '8', '9', '8', 'A', '8', 'B',
+ '8', 'C', '8', 'D', '8', 'E', '8', 'F',
+ '9', '0', '9', '1', '9', '2', '9', '3',
+ '9', '4', '9', '5', '9', '6', '9', '7',
+ '9', '8', '9', '9', '9', 'A', '9', 'B',
+ '9', 'C', '9', 'D', '9', 'E', '9', 'F',
+ 'A', '0', 'A', '1', 'A', '2', 'A', '3',
+ 'A', '4', 'A', '5', 'A', '6', 'A', '7',
+ 'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
+ 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
+ 'B', '0', 'B', '1', 'B', '2', 'B', '3',
+ 'B', '4', 'B', '5', 'B', '6', 'B', '7',
+ 'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
+ 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
+ 'C', '0', 'C', '1', 'C', '2', 'C', '3',
+ 'C', '4', 'C', '5', 'C', '6', 'C', '7',
+ 'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
+ 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
+ 'D', '0', 'D', '1', 'D', '2', 'D', '3',
+ 'D', '4', 'D', '5', 'D', '6', 'D', '7',
+ 'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
+ 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
+ 'E', '0', 'E', '1', 'E', '2', 'E', '3',
+ 'E', '4', 'E', '5', 'E', '6', 'E', '7',
+ 'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
+ 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
+ 'F', '0', 'F', '1', 'F', '2', 'F', '3',
+ 'F', '4', 'F', '5', 'F', '6', 'F', '7',
+ 'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
+ 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
+};
+
+/** Escaped single character table. (generate with misc/make_tables.c) */
+yyjson_align(2)
+static const u8 esc_single_char_table[512] = {
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
+ '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
+};
+
+/** Returns the encode table with options. */
+static_inline const char_enc_type *get_enc_table_with_flag(
+ yyjson_write_flag flg) {
+ if (has_flg(ESCAPE_UNICODE)) {
+ if (has_flg(ESCAPE_SLASHES)) {
+ return enc_table_esc_slash;
+ } else {
+ return enc_table_esc;
+ }
+ } else {
+ if (has_flg(ESCAPE_SLASHES)) {
+ return enc_table_cpy_slash;
+ } else {
+ return enc_table_cpy;
+ }
+ }
+}
+
+/** Write raw string. */
+static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
+ memcpy(cur, raw, raw_len);
+ return cur + raw_len;
+}
+
+/**
+ Write string no-escape.
+ @param cur Buffer cursor.
+ @param str A UTF-8 string, null-terminator is not required.
+ @param str_len Length of string in bytes.
+ @return The buffer cursor after string.
+ */
+static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
+ *cur++ = '"';
+ while (str_len >= 16) {
+ byte_copy_16(cur, str);
+ cur += 16;
+ str += 16;
+ str_len -= 16;
+ }
+ while (str_len >= 4) {
+ byte_copy_4(cur, str);
+ cur += 4;
+ str += 4;
+ str_len -= 4;
+ }
+ while (str_len) {
+ *cur++ = *str++;
+ str_len -= 1;
+ }
+ *cur++ = '"';
+ return cur;
+}
+
+/**
+ Write UTF-8 string (requires len * 6 + 2 bytes buffer).
+ @param cur Buffer cursor.
+ @param esc Escape unicode.
+ @param inv Allow invalid unicode.
+ @param str A UTF-8 string, null-terminator is not required.
+ @param str_len Length of string in bytes.
+ @param enc_table Encode type table for character.
+ @return The buffer cursor after string, or NULL on invalid unicode.
+ */
+static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
+ const u8 *str, usize str_len,
+ const char_enc_type *enc_table) {
+ /* The replacement character U+FFFD, used to indicate invalid character. */
+ const v32 rep = {{ 'F', 'F', 'F', 'D' }};
+ const v32 pre = {{ '\\', 'u', '0', '0' }};
+
+ const u8 *src = str;
+ const u8 *end = str + str_len;
+ *cur++ = '"';
+
+copy_ascii:
+ /*
+ Copy continuous ASCII, loop unrolling, same as the following code:
+
+ while (end > src) (
+ if (unlikely(enc_table[*src])) break;
+ *cur++ = *src++;
+ );
+ */
+#define expr_jump(i) \
+ if (unlikely(enc_table[src[i]])) goto stop_char_##i;
+
+#define expr_stop(i) \
+ stop_char_##i: \
+ memcpy(cur, src, i); \
+ cur += i; src += i; goto copy_utf8;
+
+ while (end - src >= 16) {
+ repeat16_incr(expr_jump)
+ byte_copy_16(cur, src);
+ cur += 16; src += 16;
+ }
+
+ while (end - src >= 4) {
+ repeat4_incr(expr_jump)
+ byte_copy_4(cur, src);
+ cur += 4; src += 4;
+ }
+
+ while (end > src) {
+ expr_jump(0)
+ *cur++ = *src++;
+ }
+
+ *cur++ = '"';
+ return cur;
+
+ repeat16_incr(expr_stop)
+
+#undef expr_jump
+#undef expr_stop
+
+copy_utf8:
+ if (unlikely(src + 4 > end)) {
+ if (end == src) goto copy_end;
+ if (end - src < enc_table[*src] / 2) goto err_one;
+ }
+ switch (enc_table[*src]) {
+ case CHAR_ENC_CPY_1: {
+ *cur++ = *src++;
+ goto copy_ascii;
+ }
+ case CHAR_ENC_CPY_2: {
+#if YYJSON_DISABLE_UTF8_VALIDATION
+ byte_copy_2(cur, src);
+#else
+ u32 uni = 0;
+ byte_copy_2(&uni, src);
+ if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
+ byte_copy_2(cur, &uni);
+#endif
+ cur += 2;
+ src += 2;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_CPY_3: {
+#if YYJSON_DISABLE_UTF8_VALIDATION
+ if (likely(src + 4 <= end)) {
+ byte_copy_4(cur, src);
+ } else {
+ byte_copy_2(cur, src);
+ cur[2] = src[2];
+ }
+#else
+ u32 uni, tmp;
+ if (likely(src + 4 <= end)) {
+ uni = byte_load_4(src);
+ if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
+ byte_copy_4(cur, src);
+ } else {
+ uni = byte_load_3(src);
+ if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
+ byte_copy_4(cur, &uni);
+ }
+#endif
+ cur += 3;
+ src += 3;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_CPY_4: {
+#if YYJSON_DISABLE_UTF8_VALIDATION
+ byte_copy_4(cur, src);
+#else
+ u32 uni, tmp;
+ uni = byte_load_4(src);
+ if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
+ byte_copy_4(cur, src);
+#endif
+ cur += 4;
+ src += 4;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ESC_A: {
+ byte_copy_2(cur, &esc_single_char_table[*src * 2]);
+ cur += 2;
+ src += 1;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ESC_1: {
+ byte_copy_4(cur + 0, &pre);
+ byte_copy_2(cur + 4, &esc_hex_char_table[*src * 2]);
+ cur += 6;
+ src += 1;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ESC_2: {
+ u16 u;
+#if !YYJSON_DISABLE_UTF8_VALIDATION
+ u32 v4 = 0;
+ u16 v2 = byte_load_2(src);
+ byte_copy_2(&v4, &v2);
+ if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
+#endif
+ u = (u16)(((u16)(src[0] & 0x1F) << 6) |
+ ((u16)(src[1] & 0x3F) << 0));
+ byte_copy_2(cur + 0, &pre);
+ byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
+ byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
+ cur += 6;
+ src += 2;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ESC_3: {
+ u16 u;
+ u32 v, tmp;
+#if !YYJSON_DISABLE_UTF8_VALIDATION
+ v = byte_load_3(src);
+ if (unlikely(!is_utf8_seq3(v))) goto err_esc;
+#endif
+ u = (u16)(((u16)(src[0] & 0x0F) << 12) |
+ ((u16)(src[1] & 0x3F) << 6) |
+ ((u16)(src[2] & 0x3F) << 0));
+ byte_copy_2(cur + 0, &pre);
+ byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
+ byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
+ cur += 6;
+ src += 3;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ESC_4: {
+ u32 hi, lo, u, v, tmp;
+#if !YYJSON_DISABLE_UTF8_VALIDATION
+ v = byte_load_4(src);
+ if (unlikely(!is_utf8_seq4(v))) goto err_esc;
+#endif
+ u = ((u32)(src[0] & 0x07) << 18) |
+ ((u32)(src[1] & 0x3F) << 12) |
+ ((u32)(src[2] & 0x3F) << 6) |
+ ((u32)(src[3] & 0x3F) << 0);
+ u -= 0x10000;
+ hi = (u >> 10) + 0xD800;
+ lo = (u & 0x3FF) + 0xDC00;
+ byte_copy_2(cur + 0, &pre);
+ byte_copy_2(cur + 2, &esc_hex_char_table[(hi >> 8) * 2]);
+ byte_copy_2(cur + 4, &esc_hex_char_table[(hi & 0xFF) * 2]);
+ byte_copy_2(cur + 6, &pre);
+ byte_copy_2(cur + 8, &esc_hex_char_table[(lo >> 8) * 2]);
+ byte_copy_2(cur + 10, &esc_hex_char_table[(lo & 0xFF) * 2]);
+ cur += 12;
+ src += 4;
+ goto copy_utf8;
+ }
+ case CHAR_ENC_ERR_1: {
+ goto err_one;
+ }
+ default: break; /* unreachable */
+ }
+
+copy_end:
+ *cur++ = '"';
+ return cur;
+
+err_one:
+ if (esc) goto err_esc;
+ else goto err_cpy;
+
+err_cpy:
+ if (!inv) return NULL;
+ *cur++ = *src++;
+ goto copy_utf8;
+
+err_esc:
+ if (!inv) return NULL;
+ byte_copy_2(cur + 0, &pre);
+ byte_copy_4(cur + 2, &rep);
+ cur += 6;
+ src += 1;
+ goto copy_utf8;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Writer Utilities (Private)
+ *============================================================================*/
+
+/** Write null (requires 8 bytes buffer). */
+static_inline u8 *write_null(u8 *cur) {
+ v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
+ byte_copy_8(cur, &v);
+ return cur + 4;
+}
+
+/** Write bool (requires 8 bytes buffer). */
+static_inline u8 *write_bool(u8 *cur, bool val) {
+ v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
+ v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
+ if (val) {
+ byte_copy_8(cur, &v1);
+ } else {
+ byte_copy_8(cur, &v0);
+ }
+ return cur + 5 - val;
+}
+
+/** Write indent (requires level x 4 bytes buffer).
+ Param spaces should not larger than 4. */
+static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
+ while (level-- > 0) {
+ byte_copy_4(cur, " ");
+ cur += spaces;
+ }
+ return cur;
+}
+
+/** Write data to file pointer. */
+static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
+ yyjson_write_err *err) {
+ if (fwrite(dat, len, 1, fp) != 1) {
+ err->msg = "file writing failed";
+ err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
+ return false;
+ }
+ return true;
+}
+
+/** Write data to file. */
+static bool write_dat_to_file(const char *path, u8 *dat, usize len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ err->msg = _msg; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ if (file) fclose(file); \
+ return false; \
+} while (false)
+
+ FILE *file = fopen_writeonly(path);
+ if (file == NULL) {
+ return_err(FILE_OPEN, MSG_FOPEN);
+ }
+ if (fwrite(dat, len, 1, file) != 1) {
+ return_err(FILE_WRITE, MSG_FWRITE);
+ }
+ if (fclose(file) != 0) {
+ file = NULL;
+ return_err(FILE_WRITE, MSG_FCLOSE);
+ }
+ return true;
+
+#undef return_err
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Writer Implementation (Private)
+ *============================================================================*/
+
+typedef struct yyjson_write_ctx {
+ usize tag;
+} yyjson_write_ctx;
+
+static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
+ usize size, bool is_obj) {
+ ctx->tag = (size << 1) | (usize)is_obj;
+}
+
+static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
+ usize *size, bool *is_obj) {
+ usize tag = ctx->tag;
+ *size = tag >> 1;
+ *is_obj = (bool)(tag & 1);
+}
+
+/** Write single JSON value. */
+static_inline u8 *yyjson_write_single(yyjson_val *val,
+ yyjson_write_flag flg,
+ yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ if (hdr) alc.free(alc.ctx, (void *)hdr); \
+ *dat_len = 0; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ err->msg = _msg; \
+ return NULL; \
+} while (false)
+
+#define incr_len(_len) do { \
+ hdr = (u8 *)alc.malloc(alc.ctx, _len); \
+ if (!hdr) goto fail_alloc; \
+ cur = hdr; \
+} while (false)
+
+#define check_str_len(_len) do { \
+ if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
+ goto fail_alloc; \
+} while (false)
+
+ u8 *hdr = NULL, *cur;
+ usize str_len;
+ const u8 *str_ptr;
+ const char_enc_type *enc_table = get_enc_table_with_flag(flg);
+ bool cpy = (enc_table == enc_table_cpy);
+ bool esc = has_flg(ESCAPE_UNICODE) != 0;
+ bool inv = has_allow(INVALID_UNICODE) != 0;
+ bool newline = has_flg(NEWLINE_AT_END) != 0;
+ const usize end_len = 2; /* '\n' and '\0' */
+
+ switch (unsafe_yyjson_get_type(val)) {
+ case YYJSON_TYPE_RAW:
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len + end_len);
+ cur = write_raw(cur, str_ptr, str_len);
+ break;
+
+ case YYJSON_TYPE_STR:
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len * 6 + 2 + end_len);
+ if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
+ cur = write_str_noesc(cur, str_ptr, str_len);
+ } else {
+ cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
+ if (unlikely(!cur)) goto fail_str;
+ }
+ break;
+
+ case YYJSON_TYPE_NUM:
+ incr_len(FP_BUF_LEN + end_len);
+ cur = write_num(cur, val, flg);
+ if (unlikely(!cur)) goto fail_num;
+ break;
+
+ case YYJSON_TYPE_BOOL:
+ incr_len(8);
+ cur = write_bool(cur, unsafe_yyjson_get_bool(val));
+ break;
+
+ case YYJSON_TYPE_NULL:
+ incr_len(8);
+ cur = write_null(cur);
+ break;
+
+ case YYJSON_TYPE_ARR:
+ incr_len(2 + end_len);
+ byte_copy_2(cur, "[]");
+ cur += 2;
+ break;
+
+ case YYJSON_TYPE_OBJ:
+ incr_len(2 + end_len);
+ byte_copy_2(cur, "{}");
+ cur += 2;
+ break;
+
+ default:
+ goto fail_type;
+ }
+
+ if (newline) *cur++ = '\n';
+ *cur = '\0';
+ *dat_len = (usize)(cur - hdr);
+ memset(err, 0, sizeof(yyjson_write_err));
+ return hdr;
+
+fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
+fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
+fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
+
+#undef return_err
+#undef check_str_len
+#undef incr_len
+}
+
+/** Write JSON document minify.
+ The root of this document should be a non-empty container. */
+static_inline u8 *yyjson_write_minify(const yyjson_val *root,
+ const yyjson_write_flag flg,
+ const yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ *dat_len = 0; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ err->msg = _msg; \
+ if (hdr) alc.free(alc.ctx, hdr); \
+ return NULL; \
+} while (false)
+
+#define incr_len(_len) do { \
+ ext_len = (usize)(_len); \
+ if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
+ usize ctx_pos = (usize)((u8 *)ctx - hdr); \
+ usize cur_pos = (usize)(cur - hdr); \
+ ctx_len = (usize)(end - (u8 *)ctx); \
+ alc_inc = yyjson_max(alc_len / 2, ext_len); \
+ alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
+ if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
+ goto fail_alloc; \
+ alc_len += alc_inc; \
+ tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
+ if (unlikely(!tmp)) goto fail_alloc; \
+ ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
+ memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
+ ctx = ctx_tmp; \
+ cur = tmp + cur_pos; \
+ end = tmp + alc_len; \
+ hdr = tmp; \
+ } \
+} while (false)
+
+#define check_str_len(_len) do { \
+ if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
+ goto fail_alloc; \
+} while (false)
+
+ yyjson_val *val;
+ yyjson_type val_type;
+ usize ctn_len, ctn_len_tmp;
+ bool ctn_obj, ctn_obj_tmp, is_key;
+ u8 *hdr, *cur, *end, *tmp;
+ yyjson_write_ctx *ctx, *ctx_tmp;
+ usize alc_len, alc_inc, ctx_len, ext_len, str_len;
+ const u8 *str_ptr;
+ const char_enc_type *enc_table = get_enc_table_with_flag(flg);
+ bool cpy = (enc_table == enc_table_cpy);
+ bool esc = has_flg(ESCAPE_UNICODE) != 0;
+ bool inv = has_allow(INVALID_UNICODE) != 0;
+ bool newline = has_flg(NEWLINE_AT_END) != 0;
+
+ alc_len = root->uni.ofs / sizeof(yyjson_val);
+ alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
+ alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
+ hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+ if (!hdr) goto fail_alloc;
+ cur = hdr;
+ end = hdr + alc_len;
+ ctx = (yyjson_write_ctx *)(void *)end;
+
+doc_begin:
+ val = constcast(yyjson_val *)root;
+ val_type = unsafe_yyjson_get_type(val);
+ ctn_obj = (val_type == YYJSON_TYPE_OBJ);
+ ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ val++;
+
+val_begin:
+ val_type = unsafe_yyjson_get_type(val);
+ if (val_type == YYJSON_TYPE_STR) {
+ is_key = ((u8)ctn_obj & (u8)~ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len * 6 + 16);
+ if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
+ cur = write_str_noesc(cur, str_ptr, str_len);
+ } else {
+ cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
+ if (unlikely(!cur)) goto fail_str;
+ }
+ *cur++ = is_key ? ':' : ',';
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NUM) {
+ incr_len(FP_BUF_LEN);
+ cur = write_num(cur, val, flg);
+ if (unlikely(!cur)) goto fail_num;
+ *cur++ = ',';
+ goto val_end;
+ }
+ if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
+ (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
+ ctn_len_tmp = unsafe_yyjson_get_len(val);
+ ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+ incr_len(16);
+ if (unlikely(ctn_len_tmp == 0)) {
+ /* write empty container */
+ *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = ',';
+ goto val_end;
+ } else {
+ /* push context, setup new container */
+ yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
+ ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
+ ctn_obj = ctn_obj_tmp;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ val++;
+ goto val_begin;
+ }
+ }
+ if (val_type == YYJSON_TYPE_BOOL) {
+ incr_len(16);
+ cur = write_bool(cur, unsafe_yyjson_get_bool(val));
+ cur++;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NULL) {
+ incr_len(16);
+ cur = write_null(cur);
+ cur++;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_RAW) {
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len + 2);
+ cur = write_raw(cur, str_ptr, str_len);
+ *cur++ = ',';
+ goto val_end;
+ }
+ goto fail_type;
+
+val_end:
+ val++;
+ ctn_len--;
+ if (unlikely(ctn_len == 0)) goto ctn_end;
+ goto val_begin;
+
+ctn_end:
+ cur--;
+ *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
+ *cur++ = ',';
+ if (unlikely((u8 *)ctx >= end)) goto doc_end;
+ yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
+ ctn_len--;
+ if (likely(ctn_len > 0)) {
+ goto val_begin;
+ } else {
+ goto ctn_end;
+ }
+
+doc_end:
+ if (newline) {
+ incr_len(2);
+ *(cur - 1) = '\n';
+ cur++;
+ }
+ *--cur = '\0';
+ *dat_len = (usize)(cur - hdr);
+ memset(err, 0, sizeof(yyjson_write_err));
+ return hdr;
+
+fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
+fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
+fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
+
+#undef return_err
+#undef incr_len
+#undef check_str_len
+}
+
+/** Write JSON document pretty.
+ The root of this document should be a non-empty container. */
+static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
+ const yyjson_write_flag flg,
+ const yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ *dat_len = 0; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ err->msg = _msg; \
+ if (hdr) alc.free(alc.ctx, hdr); \
+ return NULL; \
+} while (false)
+
+#define incr_len(_len) do { \
+ ext_len = (usize)(_len); \
+ if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
+ usize ctx_pos = (usize)((u8 *)ctx - hdr); \
+ usize cur_pos = (usize)(cur - hdr); \
+ ctx_len = (usize)(end - (u8 *)ctx); \
+ alc_inc = yyjson_max(alc_len / 2, ext_len); \
+ alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
+ if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
+ goto fail_alloc; \
+ alc_len += alc_inc; \
+ tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
+ if (unlikely(!tmp)) goto fail_alloc; \
+ ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
+ memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
+ ctx = ctx_tmp; \
+ cur = tmp + cur_pos; \
+ end = tmp + alc_len; \
+ hdr = tmp; \
+ } \
+} while (false)
+
+#define check_str_len(_len) do { \
+ if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
+ goto fail_alloc; \
+} while (false)
+
+ yyjson_val *val;
+ yyjson_type val_type;
+ usize ctn_len, ctn_len_tmp;
+ bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
+ u8 *hdr, *cur, *end, *tmp;
+ yyjson_write_ctx *ctx, *ctx_tmp;
+ usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
+ const u8 *str_ptr;
+ const char_enc_type *enc_table = get_enc_table_with_flag(flg);
+ bool cpy = (enc_table == enc_table_cpy);
+ bool esc = has_flg(ESCAPE_UNICODE) != 0;
+ bool inv = has_allow(INVALID_UNICODE) != 0;
+ usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
+ bool newline = has_flg(NEWLINE_AT_END) != 0;
+
+ alc_len = root->uni.ofs / sizeof(yyjson_val);
+ alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
+ alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
+ hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+ if (!hdr) goto fail_alloc;
+ cur = hdr;
+ end = hdr + alc_len;
+ ctx = (yyjson_write_ctx *)(void *)end;
+
+doc_begin:
+ val = constcast(yyjson_val *)root;
+ val_type = unsafe_yyjson_get_type(val);
+ ctn_obj = (val_type == YYJSON_TYPE_OBJ);
+ ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ *cur++ = '\n';
+ val++;
+ level = 1;
+
+val_begin:
+ val_type = unsafe_yyjson_get_type(val);
+ if (val_type == YYJSON_TYPE_STR) {
+ is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
+ cur = write_str_noesc(cur, str_ptr, str_len);
+ } else {
+ cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
+ if (unlikely(!cur)) goto fail_str;
+ }
+ *cur++ = is_key ? ':' : ',';
+ *cur++ = is_key ? ' ' : '\n';
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NUM) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_num(cur, val, flg);
+ if (unlikely(!cur)) goto fail_num;
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ }
+ if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
+ (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ ctn_len_tmp = unsafe_yyjson_get_len(val);
+ ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+ if (unlikely(ctn_len_tmp == 0)) {
+ /* write empty container */
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ } else {
+ /* push context, setup new container */
+ incr_len(32 + (no_indent ? 0 : level * 4));
+ yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
+ ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
+ ctn_obj = ctn_obj_tmp;
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ level++;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ *cur++ = '\n';
+ val++;
+ goto val_begin;
+ }
+ }
+ if (val_type == YYJSON_TYPE_BOOL) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_bool(cur, unsafe_yyjson_get_bool(val));
+ cur += 2;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NULL) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_null(cur);
+ cur += 2;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_RAW) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_raw(cur, str_ptr, str_len);
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ }
+ goto fail_type;
+
+val_end:
+ val++;
+ ctn_len--;
+ if (unlikely(ctn_len == 0)) goto ctn_end;
+ goto val_begin;
+
+ctn_end:
+ cur -= 2;
+ *cur++ = '\n';
+ incr_len(level * 4);
+ cur = write_indent(cur, --level, spaces);
+ *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
+ if (unlikely((u8 *)ctx >= end)) goto doc_end;
+ yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
+ ctn_len--;
+ *cur++ = ',';
+ *cur++ = '\n';
+ if (likely(ctn_len > 0)) {
+ goto val_begin;
+ } else {
+ goto ctn_end;
+ }
+
+doc_end:
+ if (newline) {
+ incr_len(2);
+ *cur++ = '\n';
+ }
+ *cur = '\0';
+ *dat_len = (usize)(cur - hdr);
+ memset(err, 0, sizeof(yyjson_write_err));
+ return hdr;
+
+fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
+fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
+fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
+
+#undef return_err
+#undef incr_len
+#undef check_str_len
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Writer (Public)
+ *============================================================================*/
+
+char *yyjson_val_write_opts(const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ usize tmp_dat_len;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ yyjson_val *root = constcast(yyjson_val *)val;
+
+ if (!err) err = &tmp_err;
+ if (!dat_len) dat_len = &tmp_dat_len;
+
+ if (unlikely(!root)) {
+ *dat_len = 0;
+ err->msg = "input JSON is NULL";
+ err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
+ return (char *)yyjson_write_single(root, flg, alc, dat_len, err);
+ } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
+ return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err);
+ } else {
+ return (char *)yyjson_write_minify(root, flg, alc, dat_len, err);
+ }
+}
+
+char *yyjson_write_opts(const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ yyjson_val *root = doc ? doc->root : NULL;
+ return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err);
+}
+
+bool yyjson_val_write_file(const char *path,
+ const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ u8 *dat;
+ usize dat_len = 0;
+ yyjson_val *root = constcast(yyjson_val *)val;
+ bool suc;
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!path || !*path)) {
+ err->msg = "input path is invalid";
+ err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
+ return false;
+ }
+
+ dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
+ if (unlikely(!dat)) return false;
+ suc = write_dat_to_file(path, dat, dat_len, err);
+ alc.free(alc.ctx, dat);
+ return suc;
+}
+
+bool yyjson_val_write_fp(FILE *fp,
+ const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ u8 *dat;
+ usize dat_len = 0;
+ yyjson_val *root = constcast(yyjson_val *)val;
+ bool suc;
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!fp)) {
+ err->msg = "input fp is invalid";
+ err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
+ return false;
+ }
+
+ dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
+ if (unlikely(!dat)) return false;
+ suc = write_dat_to_fp(fp, dat, dat_len, err);
+ alc.free(alc.ctx, dat);
+ return suc;
+}
+
+bool yyjson_write_file(const char *path,
+ const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_val *root = doc ? doc->root : NULL;
+ return yyjson_val_write_file(path, root, flg, alc_ptr, err);
+}
+
+bool yyjson_write_fp(FILE *fp,
+ const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_val *root = doc ? doc->root : NULL;
+ return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Writer Implementation (Private)
+ *============================================================================*/
+
+typedef struct yyjson_mut_write_ctx {
+ usize tag;
+ yyjson_mut_val *ctn;
+} yyjson_mut_write_ctx;
+
+static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
+ yyjson_mut_val *ctn,
+ usize size, bool is_obj) {
+ ctx->tag = (size << 1) | (usize)is_obj;
+ ctx->ctn = ctn;
+}
+
+static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
+ yyjson_mut_val **ctn,
+ usize *size, bool *is_obj) {
+ usize tag = ctx->tag;
+ *size = tag >> 1;
+ *is_obj = (bool)(tag & 1);
+ *ctn = ctx->ctn;
+}
+
+/** Get the estimated number of values for the mutable JSON document. */
+static_inline usize yyjson_mut_doc_estimated_val_num(
+ const yyjson_mut_doc *doc) {
+ usize sum = 0;
+ yyjson_val_chunk *chunk = doc->val_pool.chunks;
+ while (chunk) {
+ sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
+ if (chunk == doc->val_pool.chunks) {
+ sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
+ }
+ chunk = chunk->next;
+ }
+ return sum;
+}
+
+/** Write single JSON value. */
+static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err);
+}
+
+/** Write JSON document minify.
+ The root of this document should be a non-empty container. */
+static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
+ usize estimated_val_num,
+ yyjson_write_flag flg,
+ yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ *dat_len = 0; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ err->msg = _msg; \
+ if (hdr) alc.free(alc.ctx, hdr); \
+ return NULL; \
+} while (false)
+
+#define incr_len(_len) do { \
+ ext_len = (usize)(_len); \
+ if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
+ usize ctx_pos = (usize)((u8 *)ctx - hdr); \
+ usize cur_pos = (usize)(cur - hdr); \
+ ctx_len = (usize)(end - (u8 *)ctx); \
+ alc_inc = yyjson_max(alc_len / 2, ext_len); \
+ alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
+ if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
+ goto fail_alloc; \
+ alc_len += alc_inc; \
+ tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
+ if (unlikely(!tmp)) goto fail_alloc; \
+ ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
+ memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
+ ctx = ctx_tmp; \
+ cur = tmp + cur_pos; \
+ end = tmp + alc_len; \
+ hdr = tmp; \
+ } \
+} while (false)
+
+#define check_str_len(_len) do { \
+ if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
+ goto fail_alloc; \
+} while (false)
+
+ yyjson_mut_val *val, *ctn;
+ yyjson_type val_type;
+ usize ctn_len, ctn_len_tmp;
+ bool ctn_obj, ctn_obj_tmp, is_key;
+ u8 *hdr, *cur, *end, *tmp;
+ yyjson_mut_write_ctx *ctx, *ctx_tmp;
+ usize alc_len, alc_inc, ctx_len, ext_len, str_len;
+ const u8 *str_ptr;
+ const char_enc_type *enc_table = get_enc_table_with_flag(flg);
+ bool cpy = (enc_table == enc_table_cpy);
+ bool esc = has_flg(ESCAPE_UNICODE) != 0;
+ bool inv = has_allow(INVALID_UNICODE) != 0;
+ bool newline = has_flg(NEWLINE_AT_END) != 0;
+
+ alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
+ alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
+ hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+ if (!hdr) goto fail_alloc;
+ cur = hdr;
+ end = hdr + alc_len;
+ ctx = (yyjson_mut_write_ctx *)(void *)end;
+
+doc_begin:
+ val = constcast(yyjson_mut_val *)root;
+ val_type = unsafe_yyjson_get_type(val);
+ ctn_obj = (val_type == YYJSON_TYPE_OBJ);
+ ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ ctn = val;
+ val = (yyjson_mut_val *)val->uni.ptr; /* tail */
+ val = ctn_obj ? val->next->next : val->next;
+
+val_begin:
+ val_type = unsafe_yyjson_get_type(val);
+ if (val_type == YYJSON_TYPE_STR) {
+ is_key = ((u8)ctn_obj & (u8)~ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len * 6 + 16);
+ if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
+ cur = write_str_noesc(cur, str_ptr, str_len);
+ } else {
+ cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
+ if (unlikely(!cur)) goto fail_str;
+ }
+ *cur++ = is_key ? ':' : ',';
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NUM) {
+ incr_len(FP_BUF_LEN);
+ cur = write_num(cur, (yyjson_val *)val, flg);
+ if (unlikely(!cur)) goto fail_num;
+ *cur++ = ',';
+ goto val_end;
+ }
+ if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
+ (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
+ ctn_len_tmp = unsafe_yyjson_get_len(val);
+ ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+ incr_len(16);
+ if (unlikely(ctn_len_tmp == 0)) {
+ /* write empty container */
+ *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = ',';
+ goto val_end;
+ } else {
+ /* push context, setup new container */
+ yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
+ ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
+ ctn_obj = ctn_obj_tmp;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ ctn = val;
+ val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
+ val = ctn_obj ? val->next->next : val->next;
+ goto val_begin;
+ }
+ }
+ if (val_type == YYJSON_TYPE_BOOL) {
+ incr_len(16);
+ cur = write_bool(cur, unsafe_yyjson_get_bool(val));
+ cur++;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NULL) {
+ incr_len(16);
+ cur = write_null(cur);
+ cur++;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_RAW) {
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len + 2);
+ cur = write_raw(cur, str_ptr, str_len);
+ *cur++ = ',';
+ goto val_end;
+ }
+ goto fail_type;
+
+val_end:
+ ctn_len--;
+ if (unlikely(ctn_len == 0)) goto ctn_end;
+ val = val->next;
+ goto val_begin;
+
+ctn_end:
+ cur--;
+ *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
+ *cur++ = ',';
+ if (unlikely((u8 *)ctx >= end)) goto doc_end;
+ val = ctn->next;
+ yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
+ ctn_len--;
+ if (likely(ctn_len > 0)) {
+ goto val_begin;
+ } else {
+ goto ctn_end;
+ }
+
+doc_end:
+ if (newline) {
+ incr_len(2);
+ *(cur - 1) = '\n';
+ cur++;
+ }
+ *--cur = '\0';
+ *dat_len = (usize)(cur - hdr);
+ err->code = YYJSON_WRITE_SUCCESS;
+ err->msg = NULL;
+ return hdr;
+
+fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
+fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
+fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
+
+#undef return_err
+#undef incr_len
+#undef check_str_len
+}
+
+/** Write JSON document pretty.
+ The root of this document should be a non-empty container. */
+static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
+ usize estimated_val_num,
+ yyjson_write_flag flg,
+ yyjson_alc alc,
+ usize *dat_len,
+ yyjson_write_err *err) {
+#define return_err(_code, _msg) do { \
+ *dat_len = 0; \
+ err->code = YYJSON_WRITE_ERROR_##_code; \
+ err->msg = _msg; \
+ if (hdr) alc.free(alc.ctx, hdr); \
+ return NULL; \
+} while (false)
+
+#define incr_len(_len) do { \
+ ext_len = (usize)(_len); \
+ if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
+ usize ctx_pos = (usize)((u8 *)ctx - hdr); \
+ usize cur_pos = (usize)(cur - hdr); \
+ ctx_len = (usize)(end - (u8 *)ctx); \
+ alc_inc = yyjson_max(alc_len / 2, ext_len); \
+ alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
+ if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
+ goto fail_alloc; \
+ alc_len += alc_inc; \
+ tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
+ if (unlikely(!tmp)) goto fail_alloc; \
+ ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
+ memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
+ ctx = ctx_tmp; \
+ cur = tmp + cur_pos; \
+ end = tmp + alc_len; \
+ hdr = tmp; \
+ } \
+} while (false)
+
+#define check_str_len(_len) do { \
+ if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
+ goto fail_alloc; \
+} while (false)
+
+ yyjson_mut_val *val, *ctn;
+ yyjson_type val_type;
+ usize ctn_len, ctn_len_tmp;
+ bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
+ u8 *hdr, *cur, *end, *tmp;
+ yyjson_mut_write_ctx *ctx, *ctx_tmp;
+ usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
+ const u8 *str_ptr;
+ const char_enc_type *enc_table = get_enc_table_with_flag(flg);
+ bool cpy = (enc_table == enc_table_cpy);
+ bool esc = has_flg(ESCAPE_UNICODE) != 0;
+ bool inv = has_allow(INVALID_UNICODE) != 0;
+ usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
+ bool newline = has_flg(NEWLINE_AT_END) != 0;
+
+ alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
+ alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
+ hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+ if (!hdr) goto fail_alloc;
+ cur = hdr;
+ end = hdr + alc_len;
+ ctx = (yyjson_mut_write_ctx *)(void *)end;
+
+doc_begin:
+ val = constcast(yyjson_mut_val *)root;
+ val_type = unsafe_yyjson_get_type(val);
+ ctn_obj = (val_type == YYJSON_TYPE_OBJ);
+ ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ *cur++ = '\n';
+ ctn = val;
+ val = (yyjson_mut_val *)val->uni.ptr; /* tail */
+ val = ctn_obj ? val->next->next : val->next;
+ level = 1;
+
+val_begin:
+ val_type = unsafe_yyjson_get_type(val);
+ if (val_type == YYJSON_TYPE_STR) {
+ is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
+ cur = write_str_noesc(cur, str_ptr, str_len);
+ } else {
+ cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
+ if (unlikely(!cur)) goto fail_str;
+ }
+ *cur++ = is_key ? ':' : ',';
+ *cur++ = is_key ? ' ' : '\n';
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NUM) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_num(cur, (yyjson_val *)val, flg);
+ if (unlikely(!cur)) goto fail_num;
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ }
+ if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
+ (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ ctn_len_tmp = unsafe_yyjson_get_len(val);
+ ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+ if (unlikely(ctn_len_tmp == 0)) {
+ /* write empty container */
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ } else {
+ /* push context, setup new container */
+ incr_len(32 + (no_indent ? 0 : level * 4));
+ yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
+ ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
+ ctn_obj = ctn_obj_tmp;
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ level++;
+ *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
+ *cur++ = '\n';
+ ctn = val;
+ val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
+ val = ctn_obj ? val->next->next : val->next;
+ goto val_begin;
+ }
+ }
+ if (val_type == YYJSON_TYPE_BOOL) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_bool(cur, unsafe_yyjson_get_bool(val));
+ cur += 2;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_NULL) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ incr_len(16 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_null(cur);
+ cur += 2;
+ goto val_end;
+ }
+ if (val_type == YYJSON_TYPE_RAW) {
+ no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
+ str_len = unsafe_yyjson_get_len(val);
+ str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
+ check_str_len(str_len);
+ incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
+ cur = write_indent(cur, no_indent ? 0 : level, spaces);
+ cur = write_raw(cur, str_ptr, str_len);
+ *cur++ = ',';
+ *cur++ = '\n';
+ goto val_end;
+ }
+ goto fail_type;
+
+val_end:
+ ctn_len--;
+ if (unlikely(ctn_len == 0)) goto ctn_end;
+ val = val->next;
+ goto val_begin;
+
+ctn_end:
+ cur -= 2;
+ *cur++ = '\n';
+ incr_len(level * 4);
+ cur = write_indent(cur, --level, spaces);
+ *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
+ if (unlikely((u8 *)ctx >= end)) goto doc_end;
+ val = ctn->next;
+ yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
+ ctn_len--;
+ *cur++ = ',';
+ *cur++ = '\n';
+ if (likely(ctn_len > 0)) {
+ goto val_begin;
+ } else {
+ goto ctn_end;
+ }
+
+doc_end:
+ if (newline) {
+ incr_len(2);
+ *cur++ = '\n';
+ }
+ *cur = '\0';
+ *dat_len = (usize)(cur - hdr);
+ err->code = YYJSON_WRITE_SUCCESS;
+ err->msg = NULL;
+ return hdr;
+
+fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
+fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
+fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
+fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
+
+#undef return_err
+#undef incr_len
+#undef check_str_len
+}
+
+static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
+ usize estimated_val_num,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ usize tmp_dat_len;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
+
+ if (!err) err = &tmp_err;
+ if (!dat_len) dat_len = &tmp_dat_len;
+
+ if (unlikely(!root)) {
+ *dat_len = 0;
+ err->msg = "input JSON is NULL";
+ err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
+ return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err);
+ } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
+ return (char *)yyjson_mut_write_pretty(root, estimated_val_num,
+ flg, alc, dat_len, err);
+ } else {
+ return (char *)yyjson_mut_write_minify(root, estimated_val_num,
+ flg, alc, dat_len, err);
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Writer (Public)
+ *============================================================================*/
+
+char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err);
+}
+
+char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ usize *dat_len,
+ yyjson_write_err *err) {
+ yyjson_mut_val *root;
+ usize estimated_val_num;
+ if (likely(doc)) {
+ root = doc->root;
+ estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
+ } else {
+ root = NULL;
+ estimated_val_num = 0;
+ }
+ return yyjson_mut_write_opts_impl(root, estimated_val_num,
+ flg, alc_ptr, dat_len, err);
+}
+
+bool yyjson_mut_val_write_file(const char *path,
+ const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ u8 *dat;
+ usize dat_len = 0;
+ yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
+ bool suc;
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!path || !*path)) {
+ err->msg = "input path is invalid";
+ err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
+ return false;
+ }
+
+ dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
+ if (unlikely(!dat)) return false;
+ suc = write_dat_to_file(path, dat, dat_len, err);
+ alc.free(alc.ctx, dat);
+ return suc;
+}
+
+bool yyjson_mut_val_write_fp(FILE *fp,
+ const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_write_err tmp_err;
+ yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
+ u8 *dat;
+ usize dat_len = 0;
+ yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
+ bool suc;
+
+ if (!err) err = &tmp_err;
+ if (unlikely(!fp)) {
+ err->msg = "input fp is invalid";
+ err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
+ return false;
+ }
+
+ dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
+ if (unlikely(!dat)) return false;
+ suc = write_dat_to_fp(fp, dat, dat_len, err);
+ alc.free(alc.ctx, dat);
+ return suc;
+}
+
+bool yyjson_mut_write_file(const char *path,
+ const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_mut_val *root = doc ? doc->root : NULL;
+ return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
+}
+
+bool yyjson_mut_write_fp(FILE *fp,
+ const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc_ptr,
+ yyjson_write_err *err) {
+ yyjson_mut_val *root = doc ? doc->root : NULL;
+ return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
+}
+
+#undef has_flg
+#undef has_allow
+#endif /* YYJSON_DISABLE_WRITER */
+
+
+
+#if !YYJSON_DISABLE_UTILS
+
+/*==============================================================================
+ * MARK: - JSON Pointer API (RFC 6901) (Public)
+ *============================================================================*/
+
+/**
+ Get a token from JSON pointer string.
+ @param ptr [in] string that points to current token prefix `/`
+ [out] string that points to next token prefix `/`, or string end
+ @param end [in] end of the entire JSON Pointer string
+ @param len [out] unescaped token length
+ @param esc [out] number of escaped characters in this token
+ @return head of the token, or NULL if syntax error
+ */
+static_inline const char *ptr_next_token(const char **ptr, const char *end,
+ usize *len, usize *esc) {
+ const char *hdr = *ptr + 1;
+ const char *cur = hdr;
+ /* skip unescaped characters */
+ while (cur < end && *cur != '/' && *cur != '~') cur++;
+ if (likely(cur == end || *cur != '~')) {
+ /* no escaped characters, return */
+ *ptr = cur;
+ *len = (usize)(cur - hdr);
+ *esc = 0;
+ return hdr;
+ } else {
+ /* handle escaped characters */
+ usize esc_num = 0;
+ while (cur < end && *cur != '/') {
+ if (*cur++ == '~') {
+ if (cur == end || (*cur != '0' && *cur != '1')) {
+ *ptr = cur - 1;
+ return NULL;
+ }
+ esc_num++;
+ }
+ }
+ *ptr = cur;
+ *len = (usize)(cur - hdr) - esc_num;
+ *esc = esc_num;
+ return hdr;
+ }
+}
+
+/**
+ Convert token string to index.
+ @param cur [in] token head
+ @param len [in] token length
+ @param idx [out] the index number, or USIZE_MAX if token is '-'
+ @return true if token is a valid array index
+ */
+static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
+ const char *end = cur + len;
+ usize num = 0, add;
+ if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
+ if (*cur == '0') {
+ if (unlikely(len > 1)) return false;
+ *idx = 0;
+ return true;
+ }
+ if (*cur == '-') {
+ if (unlikely(len > 1)) return false;
+ *idx = USIZE_MAX;
+ return true;
+ }
+ for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
+ num = num * 10 + add;
+ }
+ if (unlikely(num == 0 || cur < end)) return false;
+ *idx = num;
+ return true;
+}
+
+/**
+ Compare JSON key with token.
+ @param key a string key (yyjson_val or yyjson_mut_val)
+ @param token a JSON pointer token
+ @param len unescaped token length
+ @param esc number of escaped characters in this token
+ @return true if `str` is equals to `token`
+ */
+static_inline bool ptr_token_eq(void *key,
+ const char *token, usize len, usize esc) {
+ yyjson_val *val = (yyjson_val *)key;
+ if (unsafe_yyjson_get_len(val) != len) return false;
+ if (likely(!esc)) {
+ return memcmp(val->uni.str, token, len) == 0;
+ } else {
+ const char *str = val->uni.str;
+ for (; len-- > 0; token++, str++) {
+ if (*token == '~') {
+ if (*str != (*++token == '0' ? '~' : '/')) return false;
+ } else {
+ if (*str != *token) return false;
+ }
+ }
+ return true;
+ }
+}
+
+/**
+ Get a value from array by token.
+ @param arr an array, should not be NULL or non-array type
+ @param token a JSON pointer token
+ @param len unescaped token length
+ @param esc number of escaped characters in this token
+ @return value at index, or NULL if token is not index or index is out of range
+ */
+static_inline yyjson_val *ptr_arr_get(yyjson_val *arr, const char *token,
+ usize len, usize esc) {
+ yyjson_val *val = unsafe_yyjson_get_first(arr);
+ usize num = unsafe_yyjson_get_len(arr), idx = 0;
+ if (unlikely(num == 0)) return NULL;
+ if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
+ if (unlikely(idx >= num)) return NULL;
+ if (unsafe_yyjson_arr_is_flat(arr)) {
+ return val + idx;
+ } else {
+ while (idx-- > 0) val = unsafe_yyjson_get_next(val);
+ return val;
+ }
+}
+
+/**
+ Get a value from object by token.
+ @param obj [in] an object, should not be NULL or non-object type
+ @param token [in] a JSON pointer token
+ @param len [in] unescaped token length
+ @param esc [in] number of escaped characters in this token
+ @return value associated with the token, or NULL if no value
+ */
+static_inline yyjson_val *ptr_obj_get(yyjson_val *obj, const char *token,
+ usize len, usize esc) {
+ yyjson_val *key = unsafe_yyjson_get_first(obj);
+ usize num = unsafe_yyjson_get_len(obj);
+ if (unlikely(num == 0)) return NULL;
+ for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
+ if (ptr_token_eq(key, token, len, esc)) return key + 1;
+ }
+ return NULL;
+}
+
+/**
+ Get a value from array by token.
+ @param arr [in] an array, should not be NULL or non-array type
+ @param token [in] a JSON pointer token
+ @param len [in] unescaped token length
+ @param esc [in] number of escaped characters in this token
+ @param pre [out] previous (sibling) value of the returned value
+ @param last [out] whether index is last
+ @return value at index, or NULL if token is not index or index is out of range
+ */
+static_inline yyjson_mut_val *ptr_mut_arr_get(yyjson_mut_val *arr,
+ const char *token,
+ usize len, usize esc,
+ yyjson_mut_val **pre,
+ bool *last) {
+ yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
+ usize num = unsafe_yyjson_get_len(arr), idx;
+ if (last) *last = false;
+ if (pre) *pre = NULL;
+ if (unlikely(num == 0)) {
+ if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
+ return NULL;
+ }
+ if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
+ if (last) *last = (idx == num || idx == USIZE_MAX);
+ if (unlikely(idx >= num)) return NULL;
+ while (idx-- > 0) val = val->next;
+ if (pre) *pre = val;
+ return val->next;
+}
+
+/**
+ Get a value from object by token.
+ @param obj [in] an object, should not be NULL or non-object type
+ @param token [in] a JSON pointer token
+ @param len [in] unescaped token length
+ @param esc [in] number of escaped characters in this token
+ @param pre [out] previous (sibling) key of the returned value's key
+ @return value associated with the token, or NULL if no value
+ */
+static_inline yyjson_mut_val *ptr_mut_obj_get(yyjson_mut_val *obj,
+ const char *token,
+ usize len, usize esc,
+ yyjson_mut_val **pre) {
+ yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
+ usize num = unsafe_yyjson_get_len(obj);
+ if (pre) *pre = NULL;
+ if (unlikely(num == 0)) return NULL;
+ for (; num > 0; num--, pre_key = key) {
+ key = pre_key->next->next;
+ if (ptr_token_eq(key, token, len, esc)) {
+ if (pre) *pre = pre_key;
+ return key->next;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Create a string value with JSON pointer token.
+ @param token [in] a JSON pointer token
+ @param len [in] unescaped token length
+ @param esc [in] number of escaped characters in this token
+ @param doc [in] used for memory allocation when creating value
+ @return new string value, or NULL if memory allocation failed
+ */
+static_inline yyjson_mut_val *ptr_new_key(const char *token,
+ usize len, usize esc,
+ yyjson_mut_doc *doc) {
+ const char *src = token;
+ if (likely(!esc)) {
+ return yyjson_mut_strncpy(doc, src, len);
+ } else {
+ const char *end = src + len + esc;
+ char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
+ char *str = dst;
+ if (unlikely(!dst)) return NULL;
+ for (; src < end; src++, dst++) {
+ if (*src != '~') *dst = *src;
+ else *dst = (*++src == '0' ? '~' : '/');
+ }
+ *dst = '\0';
+ return yyjson_mut_strn(doc, str, len);
+ }
+}
+
+/* macros for yyjson_ptr */
+#define return_err(_ret, _code, _pos, _msg) do { \
+ if (err) { \
+ err->code = YYJSON_PTR_ERR_##_code; \
+ err->msg = _msg; \
+ err->pos = (usize)(_pos); \
+ } \
+ return _ret; \
+} while (false)
+
+#define return_err_resolve(_ret, _pos) \
+ return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
+#define return_err_syntax(_ret, _pos) \
+ return_err(_ret, SYNTAX, _pos, "invalid escaped character")
+#define return_err_alloc(_ret) \
+ return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
+
+yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val,
+ const char *ptr, size_t ptr_len,
+ yyjson_ptr_err *err) {
+
+ const char *hdr = ptr, *end = ptr + ptr_len, *token;
+ usize len, esc;
+ yyjson_type type;
+
+ while (true) {
+ token = ptr_next_token(&ptr, end, &len, &esc);
+ if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
+ type = unsafe_yyjson_get_type(val);
+ if (type == YYJSON_TYPE_OBJ) {
+ val = ptr_obj_get(val, token, len, esc);
+ } else if (type == YYJSON_TYPE_ARR) {
+ val = ptr_arr_get(val, token, len, esc);
+ } else {
+ val = NULL;
+ }
+ if (!val) return_err_resolve(NULL, token - hdr);
+ if (ptr == end) return val;
+ }
+}
+
+yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(
+ yyjson_mut_val *val, const char *ptr, size_t ptr_len,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ const char *hdr = ptr, *end = ptr + ptr_len, *token;
+ usize len, esc;
+ yyjson_mut_val *ctn, *pre = NULL;
+ yyjson_type type;
+ bool idx_is_last = false;
+
+ while (true) {
+ token = ptr_next_token(&ptr, end, &len, &esc);
+ if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
+ ctn = val;
+ type = unsafe_yyjson_get_type(val);
+ if (type == YYJSON_TYPE_OBJ) {
+ val = ptr_mut_obj_get(val, token, len, esc, &pre);
+ } else if (type == YYJSON_TYPE_ARR) {
+ val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
+ } else {
+ val = NULL;
+ }
+ if (ctx && (ptr == end)) {
+ if (type == YYJSON_TYPE_OBJ ||
+ (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
+ ctx->ctn = ctn;
+ ctx->pre = pre;
+ }
+ }
+ if (!val) return_err_resolve(NULL, token - hdr);
+ if (ptr == end) return val;
+ }
+}
+
+bool unsafe_yyjson_mut_ptr_putx(
+ yyjson_mut_val *val, const char *ptr, size_t ptr_len,
+ yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
+ bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ const char *hdr = ptr, *end = ptr + ptr_len, *token;
+ usize token_len, esc, ctn_len;
+ yyjson_mut_val *ctn, *key, *pre = NULL;
+ yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
+ yyjson_type ctn_type;
+ bool idx_is_last = false;
+
+ /* skip exist parent nodes */
+ while (true) {
+ token = ptr_next_token(&ptr, end, &token_len, &esc);
+ if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
+ ctn = val;
+ ctn_type = unsafe_yyjson_get_type(ctn);
+ if (ctn_type == YYJSON_TYPE_OBJ) {
+ val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
+ } else if (ctn_type == YYJSON_TYPE_ARR) {
+ val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
+ &idx_is_last);
+ } else return_err_resolve(false, token - hdr);
+ if (!val) break;
+ if (ptr == end) break; /* is last token */
+ }
+
+ /* create parent nodes if not exist */
+ if (unlikely(ptr != end)) { /* not last token */
+ if (!create_parent) return_err_resolve(false, token - hdr);
+
+ /* add value at last index if container is array */
+ if (ctn_type == YYJSON_TYPE_ARR) {
+ if (!idx_is_last || !insert_new) {
+ return_err_resolve(false, token - hdr);
+ }
+ val = yyjson_mut_obj(doc);
+ if (!val) return_err_alloc(false);
+
+ /* delay attaching until all operations are completed */
+ sep_ctn = ctn;
+ sep_key = NULL;
+ sep_val = val;
+
+ /* move to next token */
+ ctn = val;
+ val = NULL;
+ ctn_type = YYJSON_TYPE_OBJ;
+ token = ptr_next_token(&ptr, end, &token_len, &esc);
+ if (unlikely(!token)) return_err_resolve(false, token - hdr);
+ }
+
+ /* container is object, create parent nodes */
+ while (ptr != end) { /* not last token */
+ key = ptr_new_key(token, token_len, esc, doc);
+ if (!key) return_err_alloc(false);
+ val = yyjson_mut_obj(doc);
+ if (!val) return_err_alloc(false);
+
+ /* delay attaching until all operations are completed */
+ if (!sep_ctn) {
+ sep_ctn = ctn;
+ sep_key = key;
+ sep_val = val;
+ } else {
+ yyjson_mut_obj_add(ctn, key, val);
+ }
+
+ /* move to next token */
+ ctn = val;
+ val = NULL;
+ token = ptr_next_token(&ptr, end, &token_len, &esc);
+ if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
+ }
+ }
+
+ /* JSON pointer is resolved, insert or replace target value */
+ ctn_len = unsafe_yyjson_get_len(ctn);
+ if (ctn_type == YYJSON_TYPE_OBJ) {
+ if (ctx) ctx->ctn = ctn;
+ if (!val || insert_new) {
+ /* insert new key-value pair */
+ key = ptr_new_key(token, token_len, esc, doc);
+ if (unlikely(!key)) return_err_alloc(false);
+ if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
+ unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
+ } else {
+ /* replace exist value */
+ key = pre->next->next;
+ if (ctx) ctx->pre = pre;
+ if (ctx) ctx->old = val;
+ yyjson_mut_obj_put(ctn, key, new_val);
+ }
+ } else {
+ /* array */
+ if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
+ if (insert_new) {
+ /* append new value */
+ if (val) {
+ pre->next = new_val;
+ new_val->next = val;
+ if (ctx) ctx->pre = pre;
+ unsafe_yyjson_set_len(ctn, ctn_len + 1);
+ } else if (idx_is_last) {
+ if (ctx) ctx->pre = ctn_len ?
+ (yyjson_mut_val *)ctn->uni.ptr : new_val;
+ yyjson_mut_arr_append(ctn, new_val);
+ } else {
+ return_err_resolve(false, token - hdr);
+ }
+ } else {
+ /* replace exist value */
+ if (!val) return_err_resolve(false, token - hdr);
+ if (ctn_len > 1) {
+ new_val->next = val->next;
+ pre->next = new_val;
+ if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
+ } else {
+ new_val->next = new_val;
+ ctn->uni.ptr = new_val;
+ pre = new_val;
+ }
+ if (ctx) ctx->pre = pre;
+ if (ctx) ctx->old = val;
+ }
+ }
+
+ /* all operations are completed, attach the new components to the target */
+ if (unlikely(sep_ctn)) {
+ if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
+ else yyjson_mut_arr_append(sep_ctn, sep_val);
+ }
+ return true;
+}
+
+yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ yyjson_mut_val *cur_val;
+ yyjson_ptr_ctx cur_ctx;
+ memset(&cur_ctx, 0, sizeof(cur_ctx));
+ if (!ctx) ctx = &cur_ctx;
+ cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
+ if (!cur_val) return NULL;
+
+ if (yyjson_mut_is_obj(ctx->ctn)) {
+ yyjson_mut_val *key = ctx->pre->next->next;
+ yyjson_mut_obj_put(ctx->ctn, key, new_val);
+ } else {
+ yyjson_ptr_ctx_replace(ctx, new_val);
+ }
+ ctx->old = cur_val;
+ return cur_val;
+}
+
+yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(
+ yyjson_mut_val *val, const char *ptr, size_t len,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ yyjson_mut_val *cur_val;
+ yyjson_ptr_ctx cur_ctx;
+ memset(&cur_ctx, 0, sizeof(cur_ctx));
+ if (!ctx) ctx = &cur_ctx;
+ cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
+ if (cur_val) {
+ if (yyjson_mut_is_obj(ctx->ctn)) {
+ yyjson_mut_val *key = ctx->pre->next->next;
+ yyjson_mut_obj_put(ctx->ctn, key, NULL);
+ } else {
+ yyjson_ptr_ctx_remove(ctx);
+ }
+ ctx->pre = NULL;
+ ctx->old = cur_val;
+ }
+ return cur_val;
+}
+
+/* macros for yyjson_ptr */
+#undef return_err
+#undef return_err_resolve
+#undef return_err_syntax
+#undef return_err_alloc
+
+
+
+/*==============================================================================
+ * MARK: - JSON Patch API (RFC 6902) (Public)
+ *============================================================================*/
+
+/* JSON Patch operation */
+typedef enum patch_op {
+ PATCH_OP_ADD, /* path, value */
+ PATCH_OP_REMOVE, /* path */
+ PATCH_OP_REPLACE, /* path, value */
+ PATCH_OP_MOVE, /* from, path */
+ PATCH_OP_COPY, /* from, path */
+ PATCH_OP_TEST, /* path, value */
+ PATCH_OP_NONE /* invalid */
+} patch_op;
+
+static patch_op patch_op_get(yyjson_val *op) {
+ const char *str = op->uni.str;
+ switch (unsafe_yyjson_get_len(op)) {
+ case 3:
+ if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
+ return PATCH_OP_NONE;
+ case 4:
+ if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
+ if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
+ if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
+ return PATCH_OP_NONE;
+ case 6:
+ if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
+ return PATCH_OP_NONE;
+ case 7:
+ if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
+ return PATCH_OP_NONE;
+ default:
+ return PATCH_OP_NONE;
+ }
+}
+
+/* macros for yyjson_patch */
+#define return_err(_code, _msg) do { \
+ if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
+ err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
+ err->msg = _msg; \
+ memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
+ } else { \
+ err->code = YYJSON_PATCH_ERROR_##_code; \
+ err->msg = _msg; \
+ err->idx = iter.idx ? iter.idx - 1 : 0; \
+ } \
+ return NULL; \
+} while (false)
+
+#define return_err_copy() \
+ return_err(MEMORY_ALLOCATION, "failed to copy value")
+#define return_err_key(_key) \
+ return_err(MISSING_KEY, "missing key " _key)
+#define return_err_val(_key) \
+ return_err(INVALID_MEMBER, "invalid member " _key)
+
+#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
+ root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
+#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
+ root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
+#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
+ root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
+#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
+ root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
+
+yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
+ yyjson_val *orig,
+ yyjson_val *patch,
+ yyjson_patch_err *err) {
+
+ yyjson_mut_val *root;
+ yyjson_val *obj;
+ yyjson_arr_iter iter;
+ yyjson_patch_err err_tmp;
+ if (!err) err = &err_tmp;
+ memset(err, 0, sizeof(*err));
+ memset(&iter, 0, sizeof(iter));
+
+ if (unlikely(!doc || !orig || !patch)) {
+ return_err(INVALID_PARAMETER, "input parameter is NULL");
+ }
+ if (unlikely(!yyjson_is_arr(patch))) {
+ return_err(INVALID_PARAMETER, "input patch is not array");
+ }
+ root = yyjson_val_mut_copy(doc, orig);
+ if (unlikely(!root)) return_err_copy();
+
+ /* iterate through the patch array */
+ yyjson_arr_iter_init(patch, &iter);
+ while ((obj = yyjson_arr_iter_next(&iter))) {
+ patch_op op_enum;
+ yyjson_val *op, *path, *from = NULL, *value;
+ yyjson_mut_val *val = NULL, *test;
+ usize path_len, from_len = 0;
+ if (unlikely(!unsafe_yyjson_is_obj(obj))) {
+ return_err(INVALID_OPERATION, "JSON patch operation is not object");
+ }
+
+ /* get required member: op */
+ op = yyjson_obj_get(obj, "op");
+ if (unlikely(!op)) return_err_key("`op`");
+ if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
+ op_enum = patch_op_get(op);
+
+ /* get required member: path */
+ path = yyjson_obj_get(obj, "path");
+ if (unlikely(!path)) return_err_key("`path`");
+ if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
+ path_len = unsafe_yyjson_get_len(path);
+
+ /* get required member: value, from */
+ switch ((int)op_enum) {
+ case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
+ value = yyjson_obj_get(obj, "value");
+ if (unlikely(!value)) return_err_key("`value`");
+ val = yyjson_val_mut_copy(doc, value);
+ if (unlikely(!val)) return_err_copy();
+ break;
+ case PATCH_OP_MOVE: case PATCH_OP_COPY:
+ from = yyjson_obj_get(obj, "from");
+ if (unlikely(!from)) return_err_key("`from`");
+ if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
+ from_len = unsafe_yyjson_get_len(from);
+ break;
+ default:
+ break;
+ }
+
+ /* perform an operation */
+ switch ((int)op_enum) {
+ case PATCH_OP_ADD: /* add(path, val) */
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_REMOVE: /* remove(path) */
+ if (unlikely(!ptr_remove(path))) {
+ return_err(POINTER, "failed to remove `path`");
+ }
+ break;
+ case PATCH_OP_REPLACE: /* replace(path, val) */
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_replace(path, val))) {
+ return_err(POINTER, "failed to replace `path`");
+ }
+ break;
+ case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
+ if (unlikely(from_len == 0 && path_len == 0)) break;
+ val = ptr_remove(from);
+ if (unlikely(!val)) {
+ return_err(POINTER, "failed to remove `from`");
+ }
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
+ val = ptr_get(from);
+ if (unlikely(!val)) {
+ return_err(POINTER, "failed to get `from`");
+ }
+ if (unlikely(path_len == 0)) { root = val; break; }
+ val = yyjson_mut_val_mut_copy(doc, val);
+ if (unlikely(!val)) return_err_copy();
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
+ test = ptr_get(path);
+ if (unlikely(!test)) {
+ return_err(POINTER, "failed to get `path`");
+ }
+ if (unlikely(!yyjson_mut_equals(val, test))) {
+ return_err(EQUAL, "failed to test equal");
+ }
+ break;
+ default:
+ return_err(INVALID_MEMBER, "unsupported `op`");
+ }
+ }
+ return root;
+}
+
+yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
+ yyjson_mut_val *orig,
+ yyjson_mut_val *patch,
+ yyjson_patch_err *err) {
+ yyjson_mut_val *root, *obj;
+ yyjson_mut_arr_iter iter;
+ yyjson_patch_err err_tmp;
+ if (!err) err = &err_tmp;
+ memset(err, 0, sizeof(*err));
+ memset(&iter, 0, sizeof(iter));
+
+ if (unlikely(!doc || !orig || !patch)) {
+ return_err(INVALID_PARAMETER, "input parameter is NULL");
+ }
+ if (unlikely(!yyjson_mut_is_arr(patch))) {
+ return_err(INVALID_PARAMETER, "input patch is not array");
+ }
+ root = yyjson_mut_val_mut_copy(doc, orig);
+ if (unlikely(!root)) return_err_copy();
+
+ /* iterate through the patch array */
+ yyjson_mut_arr_iter_init(patch, &iter);
+ while ((obj = yyjson_mut_arr_iter_next(&iter))) {
+ patch_op op_enum;
+ yyjson_mut_val *op, *path, *from = NULL, *value;
+ yyjson_mut_val *val = NULL, *test;
+ usize path_len, from_len = 0;
+ if (!unsafe_yyjson_is_obj(obj)) {
+ return_err(INVALID_OPERATION, "JSON patch operation is not object");
+ }
+
+ /* get required member: op */
+ op = yyjson_mut_obj_get(obj, "op");
+ if (unlikely(!op)) return_err_key("`op`");
+ if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
+ op_enum = patch_op_get((yyjson_val *)(void *)op);
+
+ /* get required member: path */
+ path = yyjson_mut_obj_get(obj, "path");
+ if (unlikely(!path)) return_err_key("`path`");
+ if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
+ path_len = unsafe_yyjson_get_len(path);
+
+ /* get required member: value, from */
+ switch ((int)op_enum) {
+ case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
+ value = yyjson_mut_obj_get(obj, "value");
+ if (unlikely(!value)) return_err_key("`value`");
+ val = yyjson_mut_val_mut_copy(doc, value);
+ if (unlikely(!val)) return_err_copy();
+ break;
+ case PATCH_OP_MOVE: case PATCH_OP_COPY:
+ from = yyjson_mut_obj_get(obj, "from");
+ if (unlikely(!from)) return_err_key("`from`");
+ if (unlikely(!yyjson_mut_is_str(from))) {
+ return_err_val("`from`");
+ }
+ from_len = unsafe_yyjson_get_len(from);
+ break;
+ default:
+ break;
+ }
+
+ /* perform an operation */
+ switch ((int)op_enum) {
+ case PATCH_OP_ADD: /* add(path, val) */
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_REMOVE: /* remove(path) */
+ if (unlikely(!ptr_remove(path))) {
+ return_err(POINTER, "failed to remove `path`");
+ }
+ break;
+ case PATCH_OP_REPLACE: /* replace(path, val) */
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_replace(path, val))) {
+ return_err(POINTER, "failed to replace `path`");
+ }
+ break;
+ case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
+ if (unlikely(from_len == 0 && path_len == 0)) break;
+ val = ptr_remove(from);
+ if (unlikely(!val)) {
+ return_err(POINTER, "failed to remove `from`");
+ }
+ if (unlikely(path_len == 0)) { root = val; break; }
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
+ val = ptr_get(from);
+ if (unlikely(!val)) {
+ return_err(POINTER, "failed to get `from`");
+ }
+ if (unlikely(path_len == 0)) { root = val; break; }
+ val = yyjson_mut_val_mut_copy(doc, val);
+ if (unlikely(!val)) return_err_copy();
+ if (unlikely(!ptr_add(path, val))) {
+ return_err(POINTER, "failed to add `path`");
+ }
+ break;
+ case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
+ test = ptr_get(path);
+ if (unlikely(!test)) {
+ return_err(POINTER, "failed to get `path`");
+ }
+ if (unlikely(!yyjson_mut_equals(val, test))) {
+ return_err(EQUAL, "failed to test equal");
+ }
+ break;
+ default:
+ return_err(INVALID_MEMBER, "unsupported `op`");
+ }
+ }
+ return root;
+}
+
+/* macros for yyjson_patch */
+#undef return_err
+#undef return_err_copy
+#undef return_err_key
+#undef return_err_val
+#undef ptr_get
+#undef ptr_add
+#undef ptr_remove
+#undef ptr_replace
+
+
+
+/*==============================================================================
+ * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
+ *============================================================================*/
+
+yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
+ yyjson_val *orig,
+ yyjson_val *patch) {
+ usize idx, max;
+ yyjson_val *key, *orig_val, *patch_val, local_orig;
+ yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
+
+ if (unlikely(!yyjson_is_obj(patch))) {
+ return yyjson_val_mut_copy(doc, patch);
+ }
+
+ builder = yyjson_mut_obj(doc);
+ if (unlikely(!builder)) return NULL;
+
+ memset(&local_orig, 0, sizeof(local_orig));
+ if (!yyjson_is_obj(orig)) {
+ orig = &local_orig;
+ orig->tag = builder->tag;
+ orig->uni = builder->uni;
+ }
+
+ /* If orig is contributing, copy any items not modified by the patch */
+ if (orig != &local_orig) {
+ yyjson_obj_foreach(orig, idx, max, key, orig_val) {
+ patch_val = yyjson_obj_getn(patch,
+ unsafe_yyjson_get_str(key),
+ unsafe_yyjson_get_len(key));
+ if (!patch_val) {
+ mut_key = yyjson_val_mut_copy(doc, key);
+ mut_val = yyjson_val_mut_copy(doc, orig_val);
+ if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
+ }
+ }
+ }
+
+ /* Merge items modified by the patch. */
+ yyjson_obj_foreach(patch, idx, max, key, patch_val) {
+ /* null indicates the field is removed. */
+ if (unsafe_yyjson_is_null(patch_val)) {
+ continue;
+ }
+ mut_key = yyjson_val_mut_copy(doc, key);
+ orig_val = yyjson_obj_getn(orig,
+ unsafe_yyjson_get_str(key),
+ unsafe_yyjson_get_len(key));
+ merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
+ if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
+ }
+
+ return builder;
+}
+
+yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
+ yyjson_mut_val *orig,
+ yyjson_mut_val *patch) {
+ usize idx, max;
+ yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
+ yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
+
+ if (unlikely(!yyjson_mut_is_obj(patch))) {
+ return yyjson_mut_val_mut_copy(doc, patch);
+ }
+
+ builder = yyjson_mut_obj(doc);
+ if (unlikely(!builder)) return NULL;
+
+ memset(&local_orig, 0, sizeof(local_orig));
+ if (!yyjson_mut_is_obj(orig)) {
+ orig = &local_orig;
+ orig->tag = builder->tag;
+ orig->uni = builder->uni;
+ }
+
+ /* If orig is contributing, copy any items not modified by the patch */
+ if (orig != &local_orig) {
+ yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
+ patch_val = yyjson_mut_obj_getn(patch,
+ unsafe_yyjson_get_str(key),
+ unsafe_yyjson_get_len(key));
+ if (!patch_val) {
+ mut_key = yyjson_mut_val_mut_copy(doc, key);
+ mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
+ if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
+ }
+ }
+ }
+
+ /* Merge items modified by the patch. */
+ yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
+ /* null indicates the field is removed. */
+ if (unsafe_yyjson_is_null(patch_val)) {
+ continue;
+ }
+ mut_key = yyjson_mut_val_mut_copy(doc, key);
+ orig_val = yyjson_mut_obj_getn(orig,
+ unsafe_yyjson_get_str(key),
+ unsafe_yyjson_get_len(key));
+ merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
+ if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
+ }
+
+ return builder;
+}
+
+#endif /* YYJSON_DISABLE_UTILS */
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.h b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.h
new file mode 100644
index 0000000..5eb6d46
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/sources/vendor/yyjson/yyjson.h
@@ -0,0 +1,8230 @@
+/*==============================================================================
+ Copyright (c) 2020 YaoYuan <[email protected]>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ *============================================================================*/
+
+/**
+ @file yyjson.h
+ @date 2019-03-09
+ @author YaoYuan
+ */
+
+#ifndef YYJSON_H
+#define YYJSON_H
+
+
+
+/*==============================================================================
+ * MARK: - Header Files
+ *============================================================================*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#include <string.h>
+#include <float.h>
+
+
+
+/*==============================================================================
+ * MARK: - Compile-time Options
+ *============================================================================*/
+
+/*
+ Define as 1 to disable JSON reader at compile-time.
+ This disables functions with "read" in their name.
+ Reduces binary size by about 60%.
+ */
+#ifndef YYJSON_DISABLE_READER
+#endif
+
+/*
+ Define as 1 to disable JSON writer at compile-time.
+ This disables functions with "write" in their name.
+ Reduces binary size by about 30%.
+ */
+#ifndef YYJSON_DISABLE_WRITER
+#endif
+
+/*
+ Define as 1 to disable JSON incremental reader at compile-time.
+ This disables functions with "incr" in their name.
+ */
+#ifndef YYJSON_DISABLE_INCR_READER
+#endif
+
+/*
+ Define as 1 to disable JSON Pointer, JSON Patch and JSON Merge Patch supports.
+ This disables functions with "ptr" or "patch" in their name.
+ */
+#ifndef YYJSON_DISABLE_UTILS
+#endif
+
+/*
+ Define as 1 to disable the fast floating-point number conversion in yyjson.
+ Libc's `strtod/snprintf` will be used instead.
+
+ This reduces binary size by about 30%, but significantly slows down the
+ floating-point read/write speed.
+ */
+#ifndef YYJSON_DISABLE_FAST_FP_CONV
+#endif
+
+/*
+ Define as 1 to disable non-standard JSON features support at compile-time,
+ such as YYJSON_READ_ALLOW_XXX and YYJSON_WRITE_ALLOW_XXX.
+
+ This reduces binary size by about 10%, and slightly improves performance.
+ */
+#ifndef YYJSON_DISABLE_NON_STANDARD
+#endif
+
+/*
+ Define as 1 to disable UTF-8 validation at compile-time.
+
+ Use this if all input strings are guaranteed to be valid UTF-8
+ (e.g. language-level String types are already validated).
+
+ Disabling UTF-8 validation improves performance for non-ASCII strings by about
+ 3% to 7%.
+
+ Note: If this flag is enabled while passing illegal UTF-8 strings,
+ the following errors may occur:
+ - Escaped characters may be ignored when parsing JSON strings.
+ - Ending quotes may be ignored when parsing JSON strings, causing the
+ string to merge with the next value.
+ - When serializing with `yyjson_mut_val`, the string's end may be accessed
+ out of bounds, potentially causing a segmentation fault.
+ */
+#ifndef YYJSON_DISABLE_UTF8_VALIDATION
+#endif
+
+/*
+ Define as 1 to improve performance on architectures that do not support
+ unaligned memory access.
+
+ Normally, this does not need to be set manually. See the C file for details.
+ */
+#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
+#endif
+
+/* Define as 1 to export symbols when building this library as a Windows DLL. */
+#ifndef YYJSON_EXPORTS
+#endif
+
+/* Define as 1 to import symbols when using this library as a Windows DLL. */
+#ifndef YYJSON_IMPORTS
+#endif
+
+/* Define as 1 to include <stdint.h> for compilers without C99 support. */
+#ifndef YYJSON_HAS_STDINT_H
+#endif
+
+/* Define as 1 to include <stdbool.h> for compilers without C99 support. */
+#ifndef YYJSON_HAS_STDBOOL_H
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Compiler Macros
+ *============================================================================*/
+
+/** compiler version (MSVC) */
+#ifdef _MSC_VER
+# define YYJSON_MSC_VER _MSC_VER
+#else
+# define YYJSON_MSC_VER 0
+#endif
+
+/** compiler version (GCC) */
+#ifdef __GNUC__
+# define YYJSON_GCC_VER __GNUC__
+# if defined(__GNUC_PATCHLEVEL__)
+# define yyjson_gcc_available(major, minor, patch) \
+ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
+ >= (major * 10000 + minor * 100 + patch))
+# else
+# define yyjson_gcc_available(major, minor, patch) \
+ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) \
+ >= (major * 10000 + minor * 100 + patch))
+# endif
+#else
+# define YYJSON_GCC_VER 0
+# define yyjson_gcc_available(major, minor, patch) 0
+#endif
+
+/** real gcc check */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+ !defined(__clang__) && !defined(__llvm__) && \
+ !defined(__INTEL_COMPILER) && !defined(__ICC) && \
+ !defined(__NVCC__) && !defined(__PGI) && !defined(__TINYC__)
+# define YYJSON_IS_REAL_GCC 1
+#else
+# define YYJSON_IS_REAL_GCC 0
+#endif
+
+/** C version (STDC) */
+#if defined(__STDC__) && (__STDC__ >= 1) && defined(__STDC_VERSION__)
+# define YYJSON_STDC_VER __STDC_VERSION__
+#else
+# define YYJSON_STDC_VER 0
+#endif
+
+/** C++ version */
+#if defined(__cplusplus)
+# define YYJSON_CPP_VER __cplusplus
+#else
+# define YYJSON_CPP_VER 0
+#endif
+
+/** compiler builtin check (since gcc 10.0, clang 2.6, icc 2021) */
+#ifndef yyjson_has_builtin
+# ifdef __has_builtin
+# define yyjson_has_builtin(x) __has_builtin(x)
+# else
+# define yyjson_has_builtin(x) 0
+# endif
+#endif
+
+/** compiler attribute check (since gcc 5.0, clang 2.9, icc 17) */
+#ifndef yyjson_has_attribute
+# ifdef __has_attribute
+# define yyjson_has_attribute(x) __has_attribute(x)
+# else
+# define yyjson_has_attribute(x) 0
+# endif
+#endif
+
+/** compiler feature check (since clang 2.6, icc 17) */
+#ifndef yyjson_has_feature
+# ifdef __has_feature
+# define yyjson_has_feature(x) __has_feature(x)
+# else
+# define yyjson_has_feature(x) 0
+# endif
+#endif
+
+/** include check (since gcc 5.0, clang 2.7, icc 16, msvc 2017 15.3) */
+#ifndef yyjson_has_include
+# ifdef __has_include
+# define yyjson_has_include(x) __has_include(x)
+# else
+# define yyjson_has_include(x) 0
+# endif
+#endif
+
+/** inline for compiler */
+#ifndef yyjson_inline
+# if YYJSON_MSC_VER >= 1200
+# define yyjson_inline __forceinline
+# elif defined(_MSC_VER)
+# define yyjson_inline __inline
+# elif yyjson_has_attribute(always_inline) || YYJSON_GCC_VER >= 4
+# define yyjson_inline __inline__ __attribute__((always_inline))
+# elif defined(__clang__) || defined(__GNUC__)
+# define yyjson_inline __inline__
+# elif defined(__cplusplus) || YYJSON_STDC_VER >= 199901L
+# define yyjson_inline inline
+# else
+# define yyjson_inline
+# endif
+#endif
+
+/** noinline for compiler */
+#ifndef yyjson_noinline
+# if YYJSON_MSC_VER >= 1400
+# define yyjson_noinline __declspec(noinline)
+# elif yyjson_has_attribute(noinline) || YYJSON_GCC_VER >= 4
+# define yyjson_noinline __attribute__((noinline))
+# else
+# define yyjson_noinline
+# endif
+#endif
+
+/** align for compiler */
+#ifndef yyjson_align
+# if YYJSON_MSC_VER >= 1300
+# define yyjson_align(x) __declspec(align(x))
+# elif yyjson_has_attribute(aligned) || defined(__GNUC__)
+# define yyjson_align(x) __attribute__((aligned(x)))
+# elif YYJSON_CPP_VER >= 201103L
+# define yyjson_align(x) alignas(x)
+# else
+# define yyjson_align(x)
+# endif
+#endif
+
+/** likely for compiler */
+#ifndef yyjson_likely
+# if yyjson_has_builtin(__builtin_expect) || \
+ (YYJSON_GCC_VER >= 4 && YYJSON_GCC_VER != 5)
+# define yyjson_likely(expr) __builtin_expect(!!(expr), 1)
+# else
+# define yyjson_likely(expr) (expr)
+# endif
+#endif
+
+/** unlikely for compiler */
+#ifndef yyjson_unlikely
+# if yyjson_has_builtin(__builtin_expect) || \
+ (YYJSON_GCC_VER >= 4 && YYJSON_GCC_VER != 5)
+# define yyjson_unlikely(expr) __builtin_expect(!!(expr), 0)
+# else
+# define yyjson_unlikely(expr) (expr)
+# endif
+#endif
+
+/** compile-time constant check for compiler */
+#ifndef yyjson_constant_p
+# if yyjson_has_builtin(__builtin_constant_p) || (YYJSON_GCC_VER >= 3)
+# define YYJSON_HAS_CONSTANT_P 1
+# define yyjson_constant_p(value) __builtin_constant_p(value)
+# else
+# define YYJSON_HAS_CONSTANT_P 0
+# define yyjson_constant_p(value) 0
+# endif
+#endif
+
+/** deprecate warning */
+#ifndef yyjson_deprecated
+# if YYJSON_MSC_VER >= 1400
+# define yyjson_deprecated(msg) __declspec(deprecated(msg))
+# elif yyjson_has_feature(attribute_deprecated_with_message) || \
+ (YYJSON_GCC_VER > 4 || (YYJSON_GCC_VER == 4 && __GNUC_MINOR__ >= 5))
+# define yyjson_deprecated(msg) __attribute__((deprecated(msg)))
+# elif YYJSON_GCC_VER >= 3
+# define yyjson_deprecated(msg) __attribute__((deprecated))
+# else
+# define yyjson_deprecated(msg)
+# endif
+#endif
+
+/** function export */
+#ifndef yyjson_api
+# if defined(_WIN32)
+# if defined(YYJSON_EXPORTS) && YYJSON_EXPORTS
+# define yyjson_api __declspec(dllexport)
+# elif defined(YYJSON_IMPORTS) && YYJSON_IMPORTS
+# define yyjson_api __declspec(dllimport)
+# else
+# define yyjson_api
+# endif
+# elif yyjson_has_attribute(visibility) || YYJSON_GCC_VER >= 4
+# define yyjson_api __attribute__((visibility("default")))
+# else
+# define yyjson_api
+# endif
+#endif
+
+/** inline function export */
+#ifndef yyjson_api_inline
+# define yyjson_api_inline static yyjson_inline
+#endif
+
+/** stdint (C89 compatible) */
+#if (defined(YYJSON_HAS_STDINT_H) && YYJSON_HAS_STDINT_H) || \
+ YYJSON_MSC_VER >= 1600 || YYJSON_STDC_VER >= 199901L || \
+ defined(_STDINT_H) || defined(_STDINT_H_) || \
+ defined(__CLANG_STDINT_H) || defined(_STDINT_H_INCLUDED) || \
+ yyjson_has_include(<stdint.h>)
+# include <stdint.h>
+#elif defined(_MSC_VER)
+# if _MSC_VER < 1300
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+ typedef signed __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+ typedef signed __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# endif
+#else
+# if UCHAR_MAX == 0xFFU
+ typedef signed char int8_t;
+ typedef unsigned char uint8_t;
+# else
+# error cannot find 8-bit integer type
+# endif
+# if USHRT_MAX == 0xFFFFU
+ typedef unsigned short uint16_t;
+ typedef signed short int16_t;
+# elif UINT_MAX == 0xFFFFU
+ typedef unsigned int uint16_t;
+ typedef signed int int16_t;
+# else
+# error cannot find 16-bit integer type
+# endif
+# if UINT_MAX == 0xFFFFFFFFUL
+ typedef unsigned int uint32_t;
+ typedef signed int int32_t;
+# elif ULONG_MAX == 0xFFFFFFFFUL
+ typedef unsigned long uint32_t;
+ typedef signed long int32_t;
+# elif USHRT_MAX == 0xFFFFFFFFUL
+ typedef unsigned short uint32_t;
+ typedef signed short int32_t;
+# else
+# error cannot find 32-bit integer type
+# endif
+# if defined(__INT64_TYPE__) && defined(__UINT64_TYPE__)
+ typedef __INT64_TYPE__ int64_t;
+ typedef __UINT64_TYPE__ uint64_t;
+# elif defined(__GNUC__) || defined(__clang__)
+# if !defined(_SYS_TYPES_H) && !defined(__int8_t_defined)
+ __extension__ typedef long long int64_t;
+# endif
+ __extension__ typedef unsigned long long uint64_t;
+# elif defined(_LONG_LONG) || defined(__MWERKS__) || defined(_CRAYC) || \
+ defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+# elif (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || \
+ defined(__WATCOM_INT64__) || defined (__alpha) || defined (__DECC)
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# else
+# error cannot find 64-bit integer type
+# endif
+#endif
+
+/** stdbool (C89 compatible) */
+#if (defined(YYJSON_HAS_STDBOOL_H) && YYJSON_HAS_STDBOOL_H) || \
+ (yyjson_has_include(<stdbool.h>) && !defined(__STRICT_ANSI__)) || \
+ YYJSON_MSC_VER >= 1800 || YYJSON_STDC_VER >= 199901L
+# include <stdbool.h>
+#elif !defined(__bool_true_false_are_defined)
+# define __bool_true_false_are_defined 1
+# if defined(__cplusplus)
+# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+# define _Bool bool
+# if __cplusplus < 201103L
+# define bool bool
+# define false false
+# define true true
+# endif
+# endif
+# else
+# define bool unsigned char
+# define true 1
+# define false 0
+# endif
+#endif
+
+/** char bit check */
+#if defined(CHAR_BIT)
+# if CHAR_BIT != 8
+# error non 8-bit char is not supported
+# endif
+#endif
+
+/**
+ Microsoft Visual C++ 6.0 doesn't support converting number from u64 to f64:
+ error C2520: conversion from unsigned __int64 to double not implemented.
+ */
+#ifndef YYJSON_U64_TO_F64_NO_IMPL
+# if (0 < YYJSON_MSC_VER) && (YYJSON_MSC_VER <= 1200)
+# define YYJSON_U64_TO_F64_NO_IMPL 1
+# else
+# define YYJSON_U64_TO_F64_NO_IMPL 0
+# endif
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Compile Hint Begin
+ *============================================================================*/
+
+/* extern "C" begin */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* warning suppress begin */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunused-function"
+# pragma clang diagnostic ignored "-Wunused-parameter"
+#elif defined(__GNUC__)
+# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# pragma GCC diagnostic push
+# endif
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+#elif defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable:4800) /* 'int': forcing value to 'true' or 'false' */
+#endif
+
+
+
+/*==============================================================================
+ * MARK: - Version
+ *============================================================================*/
+
+/** The major version of yyjson. */
+#define YYJSON_VERSION_MAJOR 0
+
+/** The minor version of yyjson. */
+#define YYJSON_VERSION_MINOR 12
+
+/** The patch version of yyjson. */
+#define YYJSON_VERSION_PATCH 0
+
+/** The version of yyjson in hex: `(major << 16) | (minor << 8) | (patch)`. */
+#define YYJSON_VERSION_HEX 0x000C00
+
+/** The version string of yyjson. */
+#define YYJSON_VERSION_STRING "0.12.0"
+
+/** The version of yyjson in hex, same as `YYJSON_VERSION_HEX`. */
+yyjson_api uint32_t yyjson_version(void);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Types
+ *============================================================================*/
+
+/** Type of a JSON value (3 bit). */
+typedef uint8_t yyjson_type;
+/** No type, invalid. */
+#define YYJSON_TYPE_NONE ((uint8_t)0) /* _____000 */
+/** Raw string type, no subtype. */
+#define YYJSON_TYPE_RAW ((uint8_t)1) /* _____001 */
+/** Null type: `null` literal, no subtype. */
+#define YYJSON_TYPE_NULL ((uint8_t)2) /* _____010 */
+/** Boolean type, subtype: TRUE, FALSE. */
+#define YYJSON_TYPE_BOOL ((uint8_t)3) /* _____011 */
+/** Number type, subtype: UINT, SINT, REAL. */
+#define YYJSON_TYPE_NUM ((uint8_t)4) /* _____100 */
+/** String type, subtype: NONE, NOESC. */
+#define YYJSON_TYPE_STR ((uint8_t)5) /* _____101 */
+/** Array type, no subtype. */
+#define YYJSON_TYPE_ARR ((uint8_t)6) /* _____110 */
+/** Object type, no subtype. */
+#define YYJSON_TYPE_OBJ ((uint8_t)7) /* _____111 */
+
+/** Subtype of a JSON value (2 bit). */
+typedef uint8_t yyjson_subtype;
+/** No subtype. */
+#define YYJSON_SUBTYPE_NONE ((uint8_t)(0 << 3)) /* ___00___ */
+/** False subtype: `false` literal. */
+#define YYJSON_SUBTYPE_FALSE ((uint8_t)(0 << 3)) /* ___00___ */
+/** True subtype: `true` literal. */
+#define YYJSON_SUBTYPE_TRUE ((uint8_t)(1 << 3)) /* ___01___ */
+/** Unsigned integer subtype: `uint64_t`. */
+#define YYJSON_SUBTYPE_UINT ((uint8_t)(0 << 3)) /* ___00___ */
+/** Signed integer subtype: `int64_t`. */
+#define YYJSON_SUBTYPE_SINT ((uint8_t)(1 << 3)) /* ___01___ */
+/** Real number subtype: `double`. */
+#define YYJSON_SUBTYPE_REAL ((uint8_t)(2 << 3)) /* ___10___ */
+/** String that do not need to be escaped for writing (internal use). */
+#define YYJSON_SUBTYPE_NOESC ((uint8_t)(1 << 3)) /* ___01___ */
+
+/** The mask used to extract the type of a JSON value. */
+#define YYJSON_TYPE_MASK ((uint8_t)0x07) /* _____111 */
+/** The number of bits used by the type. */
+#define YYJSON_TYPE_BIT ((uint8_t)3)
+/** The mask used to extract the subtype of a JSON value. */
+#define YYJSON_SUBTYPE_MASK ((uint8_t)0x18) /* ___11___ */
+/** The number of bits used by the subtype. */
+#define YYJSON_SUBTYPE_BIT ((uint8_t)2)
+/** The mask used to extract the reserved bits of a JSON value. */
+#define YYJSON_RESERVED_MASK ((uint8_t)0xE0) /* 111_____ */
+/** The number of reserved bits. */
+#define YYJSON_RESERVED_BIT ((uint8_t)3)
+/** The mask used to extract the tag of a JSON value. */
+#define YYJSON_TAG_MASK ((uint8_t)0xFF) /* 11111111 */
+/** The number of bits used by the tag. */
+#define YYJSON_TAG_BIT ((uint8_t)8)
+
+/** Padding size for JSON reader. */
+#define YYJSON_PADDING_SIZE 4
+
+
+
+/*==============================================================================
+ * MARK: - Allocator
+ *============================================================================*/
+
+/**
+ A memory allocator.
+
+ Typically you don't need to use it, unless you want to customize your own
+ memory allocator.
+ */
+typedef struct yyjson_alc {
+ /** Same as libc's malloc(size), should not be NULL. */
+ void *(*malloc)(void *ctx, size_t size);
+ /** Same as libc's realloc(ptr, size), should not be NULL. */
+ void *(*realloc)(void *ctx, void *ptr, size_t old_size, size_t size);
+ /** Same as libc's free(ptr), should not be NULL. */
+ void (*free)(void *ctx, void *ptr);
+ /** A context for malloc/realloc/free, can be NULL. */
+ void *ctx;
+} yyjson_alc;
+
+/**
+ A pool allocator uses fixed length pre-allocated memory.
+
+ This allocator may be used to avoid malloc/realloc calls. The pre-allocated
+ memory should be held by the caller. The maximum amount of memory required to
+ read a JSON can be calculated using the `yyjson_read_max_memory_usage()`
+ function, but the amount of memory required to write a JSON cannot be directly
+ calculated.
+
+ This is not a general-purpose allocator. It is designed to handle a single JSON
+ data at a time. If it is used for overly complex memory tasks, such as parsing
+ multiple JSON documents using the same allocator but releasing only a few of
+ them, it may cause memory fragmentation, resulting in performance degradation
+ and memory waste.
+
+ @param alc The allocator to be initialized.
+ If this parameter is NULL, the function will fail and return false.
+ If `buf` or `size` is invalid, this will be set to an empty allocator.
+ @param buf The buffer memory for this allocator.
+ If this parameter is NULL, the function will fail and return false.
+ @param size The size of `buf`, in bytes.
+ If this parameter is less than 8 words (32/64 bytes on 32/64-bit OS), the
+ function will fail and return false.
+ @return true if the `alc` has been successfully initialized.
+
+ @b Example
+ @code
+ // parse JSON with stack memory
+ char buf[1024];
+ yyjson_alc alc;
+ yyjson_alc_pool_init(&alc, buf, 1024);
+
+ const char *json = "{\"name\":\"Helvetica\",\"size\":16}"
+ yyjson_doc *doc = yyjson_read_opts(json, strlen(json), 0, &alc, NULL);
+ // the memory of `doc` is on the stack
+ @endcode
+
+ @warning This Allocator is not thread-safe.
+ */
+yyjson_api bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, size_t size);
+
+/**
+ A dynamic allocator.
+
+ This allocator has a similar usage to the pool allocator above. However, when
+ there is not enough memory, this allocator will dynamically request more memory
+ using libc's `malloc` function, and frees it all at once when it is destroyed.
+
+ @return A new dynamic allocator, or NULL if memory allocation failed.
+ @note The returned value should be freed with `yyjson_alc_dyn_free()`.
+
+ @warning This Allocator is not thread-safe.
+ */
+yyjson_api yyjson_alc *yyjson_alc_dyn_new(void);
+
+/**
+ Free a dynamic allocator which is created by `yyjson_alc_dyn_new()`.
+ @param alc The dynamic allocator to be destroyed.
+ */
+yyjson_api void yyjson_alc_dyn_free(yyjson_alc *alc);
+
+
+
+/*==============================================================================
+ * MARK: - Text Locating
+ *============================================================================*/
+
+/**
+ Locate the line and column number for a byte position in a string.
+ This can be used to get better description for error position.
+
+ @param str The input string.
+ @param len The byte length of the input string.
+ @param pos The byte position within the input string.
+ @param line A pointer to receive the line number, starting from 1.
+ @param col A pointer to receive the column number, starting from 1.
+ @param chr A pointer to receive the character index, starting from 0.
+ @return true on success, false if `str` is NULL or `pos` is out of bounds.
+ @note Line/column/character are calculated based on Unicode characters for
+ compatibility with text editors. For multi-byte UTF-8 characters,
+ the returned value may not directly correspond to the byte position.
+ */
+yyjson_api bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
+ size_t *line, size_t *col, size_t *chr);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Structure
+ *============================================================================*/
+
+/**
+ An immutable document for reading JSON.
+ This document holds memory for all its JSON values and strings. When it is no
+ longer used, the user should call `yyjson_doc_free()` to free its memory.
+ */
+typedef struct yyjson_doc yyjson_doc;
+
+/**
+ An immutable value for reading JSON.
+ A JSON Value has the same lifetime as its document. The memory is held by its
+ document and and cannot be freed alone.
+ */
+typedef struct yyjson_val yyjson_val;
+
+/**
+ A mutable document for building JSON.
+ This document holds memory for all its JSON values and strings. When it is no
+ longer used, the user should call `yyjson_mut_doc_free()` to free its memory.
+ */
+typedef struct yyjson_mut_doc yyjson_mut_doc;
+
+/**
+ A mutable value for building JSON.
+ A JSON Value has the same lifetime as its document. The memory is held by its
+ document and and cannot be freed alone.
+ */
+typedef struct yyjson_mut_val yyjson_mut_val;
+
+
+
+/*==============================================================================
+ * MARK: - JSON Reader API
+ *============================================================================*/
+
+/** Run-time options for JSON reader. */
+typedef uint32_t yyjson_read_flag;
+
+/** Default option (RFC 8259 compliant):
+ - Read positive integer as uint64_t.
+ - Read negative integer as int64_t.
+ - Read floating-point number as double with round-to-nearest mode.
+ - Read integer which cannot fit in uint64_t or int64_t as double.
+ - Report error if double number is infinity.
+ - Report error if string contains invalid UTF-8 character or BOM.
+ - Report error on trailing commas, comments, inf and nan literals. */
+static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
+
+/** Read the input data in-situ.
+ This option allows the reader to modify and use input data to store string
+ values, which can increase reading speed slightly.
+ The caller should hold the input data before free the document.
+ The input data must be padded by at least `YYJSON_PADDING_SIZE` bytes.
+ For example: `[1,2]` should be `[1,2]\0\0\0\0`, input length should be 5. */
+static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0;
+
+/** Stop when done instead of issuing an error if there's additional content
+ after a JSON document. This option may be used to parse small pieces of JSON
+ in larger data, such as `NDJSON`. */
+static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1;
+
+/** Allow single trailing comma at the end of an object or array,
+ such as `[1,2,3,]`, `{"a":1,"b":2,}` (non-standard). */
+static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2;
+
+/** Allow C-style single-line and mult-line comments (non-standard). */
+static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3;
+
+/** Allow inf/nan number and literal, case-insensitive,
+ such as 1e999, NaN, inf, -Infinity (non-standard). */
+static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4;
+
+/** Read all numbers as raw strings (value with `YYJSON_TYPE_RAW` type),
+ inf/nan literal is also read as raw with `ALLOW_INF_AND_NAN` flag. */
+static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
+
+/** Allow reading invalid unicode when parsing string values (non-standard).
+ Invalid characters will be allowed to appear in the string values, but
+ invalid escape sequences will still be reported as errors.
+ This flag does not affect the performance of correctly encoded strings.
+
+ @warning Strings in JSON values may contain incorrect encoding when this
+ option is used, you need to handle these strings carefully to avoid security
+ risks. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6;
+
+/** Read big numbers as raw strings. These big numbers include integers that
+ cannot be represented by `int64_t` and `uint64_t`, and floating-point
+ numbers that cannot be represented by finite `double`.
+ The flag will be overridden by `YYJSON_READ_NUMBER_AS_RAW` flag. */
+static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7;
+
+/** Allow UTF-8 BOM and skip it before parsing if any (non-standard). */
+static const yyjson_read_flag YYJSON_READ_ALLOW_BOM = 1 << 8;
+
+/** Allow extended number formats (non-standard):
+ - Hexadecimal numbers, such as `0x7B`.
+ - Numbers with leading or trailing decimal point, such as `.123`, `123.`.
+ - Numbers with a leading plus sign, such as `+123`. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_NUMBER = 1 << 9;
+
+/** Allow extended escape sequences in strings (non-standard):
+ - Additional escapes: `\a`, `\e`, `\v`, ``\'``, `\?`, `\0`.
+ - Hex escapes: `\xNN`, such as `\x7B`.
+ - Line continuation: backslash followed by line terminator sequences.
+ - Unknown escape: if backslash is followed by an unsupported character,
+ the backslash will be removed and the character will be kept as-is.
+ However, `\1`-`\9` will still trigger an error. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_ESCAPE = 1 << 10;
+
+/** Allow extended whitespace characters (non-standard):
+ - Vertical tab `\v` and form feed `\f`.
+ - Line separator `\u2028` and paragraph separator `\u2029`.
+ - Non-breaking space `\xA0`.
+ - Byte order mark: `\uFEFF`.
+ - Other Unicode characters in the Zs (Separator, space) category. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_WHITESPACE = 1 << 11;
+
+/** Allow strings enclosed in single quotes (non-standard), such as ``'ab'``. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_SINGLE_QUOTED_STR = 1 << 12;
+
+/** Allow object keys without quotes (non-standard), such as `{a:1,b:2}`.
+ This extends the ECMAScript IdentifierName rule by allowing any
+ non-whitespace character with code point above `U+007F`. */
+static const yyjson_read_flag YYJSON_READ_ALLOW_UNQUOTED_KEY = 1 << 13;
+
+/** Allow JSON5 format, see: [https://json5.org].
+ This flag supports all JSON5 features with some additional extensions:
+ - Accepts more escape sequences than JSON5 (e.g. `\a`, `\e`).
+ - Unquoted keys are not limited to ECMAScript IdentifierName.
+ - Allow case-insensitive `NaN`, `Inf` and `Infinity` literals. */
+static const yyjson_read_flag YYJSON_READ_JSON5 =
+ (1 << 2) | /* YYJSON_READ_ALLOW_TRAILING_COMMAS */
+ (1 << 3) | /* YYJSON_READ_ALLOW_COMMENTS */
+ (1 << 4) | /* YYJSON_READ_ALLOW_INF_AND_NAN */
+ (1 << 9) | /* YYJSON_READ_ALLOW_EXT_NUMBER */
+ (1 << 10) | /* YYJSON_READ_ALLOW_EXT_ESCAPE */
+ (1 << 11) | /* YYJSON_READ_ALLOW_EXT_WHITESPACE */
+ (1 << 12) | /* YYJSON_READ_ALLOW_SINGLE_QUOTED_STR */
+ (1 << 13); /* YYJSON_READ_ALLOW_UNQUOTED_KEY */
+
+
+
+/** Result code for JSON reader. */
+typedef uint32_t yyjson_read_code;
+
+/** Success, no error. */
+static const yyjson_read_code YYJSON_READ_SUCCESS = 0;
+
+/** Invalid parameter, such as NULL input string or 0 input length. */
+static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER = 1;
+
+/** Memory allocation failed. */
+static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION = 2;
+
+/** Input JSON string is empty. */
+static const yyjson_read_code YYJSON_READ_ERROR_EMPTY_CONTENT = 3;
+
+/** Unexpected content after document, such as `[123]abc`. */
+static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT = 4;
+
+/** Unexpected end of input, the parsed part is valid, such as `[123`. */
+static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END = 5;
+
+/** Unexpected character inside the document, such as `[abc]`. */
+static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER = 6;
+
+/** Invalid JSON structure, such as `[1,]`. */
+static const yyjson_read_code YYJSON_READ_ERROR_JSON_STRUCTURE = 7;
+
+/** Invalid comment, deprecated, use `UNEXPECTED_END` for unclosed comment. */
+static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT = 8;
+
+/** Invalid number, such as `123.e12`, `000`. */
+static const yyjson_read_code YYJSON_READ_ERROR_INVALID_NUMBER = 9;
+
+/** Invalid string, such as invalid escaped character inside a string. */
+static const yyjson_read_code YYJSON_READ_ERROR_INVALID_STRING = 10;
+
+/** Invalid JSON literal, such as `truu`. */
+static const yyjson_read_code YYJSON_READ_ERROR_LITERAL = 11;
+
+/** Failed to open a file. */
+static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN = 12;
+
+/** Failed to read a file. */
+static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ = 13;
+
+/** Incomplete input during incremental parsing; parsing state is preserved. */
+static const yyjson_read_code YYJSON_READ_ERROR_MORE = 14;
+
+/** Error information for JSON reader. */
+typedef struct yyjson_read_err {
+ /** Error code, see `yyjson_read_code` for all possible values. */
+ yyjson_read_code code;
+ /** Error message, constant, no need to free (NULL if success). */
+ const char *msg;
+ /** Error byte position for input data (0 if success). */
+ size_t pos;
+} yyjson_read_err;
+
+
+
+#if !defined(YYJSON_DISABLE_READER) || !YYJSON_DISABLE_READER
+
+/**
+ Read JSON with options.
+
+ This function is thread-safe when:
+ 1. The `dat` is not modified by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param dat The JSON data (UTF-8 without BOM), null-terminator is not required.
+ If this parameter is NULL, the function will fail and return NULL.
+ The `dat` will not be modified without the flag `YYJSON_READ_INSITU`, so you
+ can pass a `const char *` string and case it to `char *` if you don't use
+ the `YYJSON_READ_INSITU` flag.
+ @param len The length of JSON data in bytes.
+ If this parameter is 0, the function will fail and return NULL.
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON reader.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON document, or NULL if an error occurs.
+ When it's no longer needed, it should be freed with `yyjson_doc_free()`.
+ */
+yyjson_api yyjson_doc *yyjson_read_opts(char *dat,
+ size_t len,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err);
+
+/**
+ Read a JSON file.
+
+ This function is thread-safe when:
+ 1. The file is not modified by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param path The JSON file's path.
+ This should be a null-terminated string using the system's native encoding.
+ If this path is NULL or invalid, the function will fail and return NULL.
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON reader.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON document, or NULL if an error occurs.
+ When it's no longer needed, it should be freed with `yyjson_doc_free()`.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to read.
+ */
+yyjson_api yyjson_doc *yyjson_read_file(const char *path,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err);
+
+/**
+ Read JSON from a file pointer.
+
+ @param fp The file pointer.
+ The data will be read from the current position of the FILE to the end.
+ If this fp is NULL or invalid, the function will fail and return NULL.
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON reader.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON document, or NULL if an error occurs.
+ When it's no longer needed, it should be freed with `yyjson_doc_free()`.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to read.
+ */
+yyjson_api yyjson_doc *yyjson_read_fp(FILE *fp,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err);
+
+/**
+ Read a JSON string.
+
+ This function is thread-safe.
+
+ @param dat The JSON data (UTF-8 without BOM), null-terminator is not required.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param len The length of JSON data in bytes.
+ If this parameter is 0, the function will fail and return NULL.
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @return A new JSON document, or NULL if an error occurs.
+ When it's no longer needed, it should be freed with `yyjson_doc_free()`.
+ */
+yyjson_api_inline yyjson_doc *yyjson_read(const char *dat,
+ size_t len,
+ yyjson_read_flag flg) {
+ flg &= ~YYJSON_READ_INSITU; /* const string cannot be modified */
+ return yyjson_read_opts((char *)(void *)(size_t)(const void *)dat,
+ len, flg, NULL, NULL);
+}
+
+
+
+#if !defined(YYJSON_DISABLE_INCR_READER) || !YYJSON_DISABLE_INCR_READER
+
+/** Opaque state for incremental JSON reader. */
+typedef struct yyjson_incr_state yyjson_incr_state;
+
+/**
+ Initialize state for incremental read.
+
+ To read a large JSON document incrementally:
+ 1. Call `yyjson_incr_new()` to create the state for incremental reading.
+ 2. Call `yyjson_incr_read()` repeatedly.
+ 3. Call `yyjson_incr_free()` to free the state.
+
+ Note: The incremental JSON reader only supports standard JSON.
+ Flags for non-standard features (e.g. comments, trailing commas) are ignored.
+
+ @param buf The JSON data, null-terminator is not required.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param buf_len The length of the JSON data in `buf`.
+ If use `YYJSON_READ_INSITU`, `buf_len` should not include the padding size.
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator.
+ @param alc The memory allocator used by JSON reader.
+ Pass NULL to use the libc's default allocator.
+ @return A state for incremental reading.
+ It should be freed with `yyjson_incr_free()`.
+ NULL is returned if memory allocation fails.
+*/
+yyjson_api yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc);
+
+/**
+ Performs incremental read of up to `len` bytes.
+
+ If NULL is returned and `err->code` is set to `YYJSON_READ_ERROR_MORE`, it
+ indicates that more data is required to continue parsing. Then, call this
+ function again with incremented `len`. Continue until a document is returned or
+ an error other than `YYJSON_READ_ERROR_MORE` is returned.
+
+ Note: Parsing in very small increments is not efficient. An increment of
+ several kilobytes or megabytes is recommended.
+
+ @param state The state for incremental reading, created using
+ `yyjson_incr_new()`.
+ @param len The number of bytes of JSON data available to parse.
+ If this parameter is 0, the function will fail and return NULL.
+ @param err A pointer to receive error information.
+ @return A new JSON document, or NULL if an error occurs.
+ When the document is no longer needed, it should be freed with
+ `yyjson_doc_free()`.
+*/
+yyjson_api yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
+ yyjson_read_err *err);
+
+/** Release the incremental read state and free the memory. */
+yyjson_api void yyjson_incr_free(yyjson_incr_state *state);
+
+#endif /* YYJSON_DISABLE_INCR_READER */
+
+/**
+ Returns the size of maximum memory usage to read a JSON data.
+
+ You may use this value to avoid malloc() or calloc() call inside the reader
+ to get better performance, or read multiple JSON with one piece of memory.
+
+ @param len The length of JSON data in bytes.
+ @param flg The JSON read options.
+ @return The maximum memory size to read this JSON, or 0 if overflow.
+
+ @b Example
+ @code
+ // read multiple JSON with same pre-allocated memory
+
+ char *dat1, *dat2, *dat3; // JSON data
+ size_t len1, len2, len3; // JSON length
+ size_t max_len = MAX(len1, MAX(len2, len3));
+ yyjson_doc *doc;
+
+ // use one allocator for multiple JSON
+ size_t size = yyjson_read_max_memory_usage(max_len, 0);
+ void *buf = malloc(size);
+ yyjson_alc alc;
+ yyjson_alc_pool_init(&alc, buf, size);
+
+ // no more alloc() or realloc() call during reading
+ doc = yyjson_read_opts(dat1, len1, 0, &alc, NULL);
+ yyjson_doc_free(doc);
+ doc = yyjson_read_opts(dat2, len2, 0, &alc, NULL);
+ yyjson_doc_free(doc);
+ doc = yyjson_read_opts(dat3, len3, 0, &alc, NULL);
+ yyjson_doc_free(doc);
+
+ free(buf);
+ @endcode
+ @see yyjson_alc_pool_init()
+ */
+yyjson_api_inline size_t yyjson_read_max_memory_usage(size_t len,
+ yyjson_read_flag flg) {
+ /*
+ 1. The max value count is (json_size / 2 + 1),
+ for example: "[1,2,3,4]" size is 9, value count is 5.
+ 2. Some broken JSON may cost more memory during reading, but fail at end,
+ for example: "[[[[[[[[".
+ 3. yyjson use 16 bytes per value, see struct yyjson_val.
+ 4. yyjson use dynamic memory with a growth factor of 1.5.
+
+ The max memory size is (json_size / 2 * 16 * 1.5 + padding).
+ */
+ size_t mul = (size_t)12 + !(flg & YYJSON_READ_INSITU);
+ size_t pad = 256;
+ size_t max = (size_t)(~(size_t)0);
+ if (flg & YYJSON_READ_STOP_WHEN_DONE) len = len < 256 ? 256 : len;
+ if (len >= (max - pad - mul) / mul) return 0;
+ return len * mul + pad;
+}
+
+/**
+ Read a JSON number.
+
+ This function is thread-safe when data is not modified by other threads.
+
+ @param dat The JSON data (UTF-8 without BOM), null-terminator is required.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param val The output value where result is stored.
+ If this parameter is NULL, the function will fail and return NULL.
+ The value will hold either UINT or SINT or REAL number;
+ @param flg The JSON read options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`.
+ @param alc The memory allocator used for long number.
+ It is only used when the built-in floating point reader is disabled.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return If successful, a pointer to the character after the last character
+ used in the conversion, NULL if an error occurs.
+ */
+yyjson_api const char *yyjson_read_number(const char *dat,
+ yyjson_val *val,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err);
+
+/** Same as `yyjson_read_number()`. */
+yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
+ yyjson_mut_val *val,
+ yyjson_read_flag flg,
+ const yyjson_alc *alc,
+ yyjson_read_err *err) {
+ return yyjson_read_number(dat, (yyjson_val *)val, flg, alc, err);
+}
+
+#endif /* YYJSON_DISABLE_READER) */
+
+
+
+/*==============================================================================
+ * MARK: - JSON Writer API
+ *============================================================================*/
+
+/** Run-time options for JSON writer. */
+typedef uint32_t yyjson_write_flag;
+
+/** Default option:
+ - Write JSON minify.
+ - Report error on inf or nan number.
+ - Report error on invalid UTF-8 string.
+ - Do not escape unicode or slash. */
+static const yyjson_write_flag YYJSON_WRITE_NOFLAG = 0;
+
+/** Write JSON pretty with 4 space indent. */
+static const yyjson_write_flag YYJSON_WRITE_PRETTY = 1 << 0;
+
+/** Escape unicode as `uXXXX`, make the output ASCII only. */
+static const yyjson_write_flag YYJSON_WRITE_ESCAPE_UNICODE = 1 << 1;
+
+/** Escape '/' as '\/'. */
+static const yyjson_write_flag YYJSON_WRITE_ESCAPE_SLASHES = 1 << 2;
+
+/** Write inf and nan number as 'Infinity' and 'NaN' literal (non-standard). */
+static const yyjson_write_flag YYJSON_WRITE_ALLOW_INF_AND_NAN = 1 << 3;
+
+/** Write inf and nan number as null literal.
+ This flag will override `YYJSON_WRITE_ALLOW_INF_AND_NAN` flag. */
+static const yyjson_write_flag YYJSON_WRITE_INF_AND_NAN_AS_NULL = 1 << 4;
+
+/** Allow invalid unicode when encoding string values (non-standard).
+ Invalid characters in string value will be copied byte by byte.
+ If `YYJSON_WRITE_ESCAPE_UNICODE` flag is also set, invalid character will be
+ escaped as `U+FFFD` (replacement character).
+ This flag does not affect the performance of correctly encoded strings. */
+static const yyjson_write_flag YYJSON_WRITE_ALLOW_INVALID_UNICODE = 1 << 5;
+
+/** Write JSON pretty with 2 space indent.
+ This flag will override `YYJSON_WRITE_PRETTY` flag. */
+static const yyjson_write_flag YYJSON_WRITE_PRETTY_TWO_SPACES = 1 << 6;
+
+/** Adds a newline character `\n` at the end of the JSON.
+ This can be helpful for text editors or NDJSON. */
+static const yyjson_write_flag YYJSON_WRITE_NEWLINE_AT_END = 1 << 7;
+
+
+
+/** The highest 8 bits of `yyjson_write_flag` and real number value's `tag`
+ are reserved for controlling the output format of floating-point numbers. */
+#define YYJSON_WRITE_FP_FLAG_BITS 8
+
+/** The highest 4 bits of flag are reserved for precision value. */
+#define YYJSON_WRITE_FP_PREC_BITS 4
+
+/** Write floating-point number using fixed-point notation.
+ - This is similar to ECMAScript `Number.prototype.toFixed(prec)`,
+ but with trailing zeros removed. The `prec` ranges from 1 to 15.
+ - This will produce shorter output but may lose some precision. */
+#define YYJSON_WRITE_FP_TO_FIXED(prec) ((yyjson_write_flag)( \
+ (uint32_t)((uint32_t)(prec)) << (32 - 4) ))
+
+/** Write floating-point numbers using single-precision (float).
+ - This casts `double` to `float` before serialization.
+ - This will produce shorter output, but may lose some precision.
+ - This flag is ignored if `YYJSON_WRITE_FP_TO_FIXED(prec)` is also used. */
+#define YYJSON_WRITE_FP_TO_FLOAT ((yyjson_write_flag)(1 << (32 - 5)))
+
+
+
+/** Result code for JSON writer */
+typedef uint32_t yyjson_write_code;
+
+/** Success, no error. */
+static const yyjson_write_code YYJSON_WRITE_SUCCESS = 0;
+
+/** Invalid parameter, such as NULL document. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_PARAMETER = 1;
+
+/** Memory allocation failure occurs. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_MEMORY_ALLOCATION = 2;
+
+/** Invalid value type in JSON document. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_VALUE_TYPE = 3;
+
+/** NaN or Infinity number occurs. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_NAN_OR_INF = 4;
+
+/** Failed to open a file. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_FILE_OPEN = 5;
+
+/** Failed to write a file. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_FILE_WRITE = 6;
+
+/** Invalid unicode in string. */
+static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_STRING = 7;
+
+/** Error information for JSON writer. */
+typedef struct yyjson_write_err {
+ /** Error code, see `yyjson_write_code` for all possible values. */
+ yyjson_write_code code;
+ /** Error message, constant, no need to free (NULL if success). */
+ const char *msg;
+} yyjson_write_err;
+
+
+
+#if !defined(YYJSON_DISABLE_WRITER) || !YYJSON_DISABLE_WRITER
+
+/*==============================================================================
+ * MARK: - JSON Document Writer API
+ *============================================================================*/
+
+/**
+ Write a document to JSON string with options.
+
+ This function is thread-safe when:
+ The `alc` is thread-safe or NULL.
+
+ @param doc The JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free() or alc->free().
+ */
+yyjson_api char *yyjson_write_opts(const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ size_t *len,
+ yyjson_write_err *err);
+
+/**
+ Write a document to JSON file with options.
+
+ This function is thread-safe when:
+ 1. The file is not accessed by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param path The JSON file's path.
+ This should be a null-terminated string using the system's native encoding.
+ If this path is NULL or invalid, the function will fail and return false.
+ If this file is not empty, the content will be discarded.
+ @param doc The JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_write_file(const char *path,
+ const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a document to file pointer with options.
+
+ @param fp The file pointer.
+ The data will be written to the current position of the file.
+ If this fp is NULL or invalid, the function will fail and return false.
+ @param doc The JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_write_fp(FILE *fp,
+ const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a document to JSON string.
+
+ This function is thread-safe.
+
+ @param doc The JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free().
+ */
+yyjson_api_inline char *yyjson_write(const yyjson_doc *doc,
+ yyjson_write_flag flg,
+ size_t *len) {
+ return yyjson_write_opts(doc, flg, NULL, len, NULL);
+}
+
+
+
+/**
+ Write a document to JSON string with options.
+
+ This function is thread-safe when:
+ 1. The `doc` is not modified by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param doc The mutable JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free() or alc->free().
+ */
+yyjson_api char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ size_t *len,
+ yyjson_write_err *err);
+
+/**
+ Write a document to JSON file with options.
+
+ This function is thread-safe when:
+ 1. The file is not accessed by other threads.
+ 2. The `doc` is not modified by other threads.
+ 3. The `alc` is thread-safe or NULL.
+
+ @param path The JSON file's path.
+ This should be a null-terminated string using the system's native encoding.
+ If this path is NULL or invalid, the function will fail and return false.
+ If this file is not empty, the content will be discarded.
+ @param doc The mutable JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+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);
+
+/**
+ Write a document to file pointer with options.
+
+ @param fp The file pointer.
+ The data will be written to the current position of the file.
+ If this fp is NULL or invalid, the function will fail and return false.
+ @param doc The mutable JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_mut_write_fp(FILE *fp,
+ const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a document to JSON string.
+
+ This function is thread-safe when:
+ The `doc` is not modified by other threads.
+
+ @param doc The JSON document.
+ If this doc is NULL or has no root, the function will fail and return false.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free().
+ */
+yyjson_api_inline char *yyjson_mut_write(const yyjson_mut_doc *doc,
+ yyjson_write_flag flg,
+ size_t *len) {
+ return yyjson_mut_write_opts(doc, flg, NULL, len, NULL);
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value Writer API
+ *============================================================================*/
+
+/**
+ Write a value to JSON string with options.
+
+ This function is thread-safe when:
+ The `alc` is thread-safe or NULL.
+
+ @param val The JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free() or alc->free().
+ */
+yyjson_api char *yyjson_val_write_opts(const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ size_t *len,
+ yyjson_write_err *err);
+
+/**
+ Write a value to JSON file with options.
+
+ This function is thread-safe when:
+ 1. The file is not accessed by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param path The JSON file's path.
+ This should be a null-terminated string using the system's native encoding.
+ If this path is NULL or invalid, the function will fail and return false.
+ If this file is not empty, the content will be discarded.
+ @param val The JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_val_write_file(const char *path,
+ const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a value to file pointer with options.
+
+ @param fp The file pointer.
+ The data will be written to the current position of the file.
+ If this path is NULL or invalid, the function will fail and return false.
+ @param val The JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_val_write_fp(FILE *fp,
+ const yyjson_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a value to JSON string.
+
+ This function is thread-safe.
+
+ @param val The JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free().
+ */
+yyjson_api_inline char *yyjson_val_write(const yyjson_val *val,
+ yyjson_write_flag flg,
+ size_t *len) {
+ return yyjson_val_write_opts(val, flg, NULL, len, NULL);
+}
+
+/**
+ Write a value to JSON string with options.
+
+ This function is thread-safe when:
+ 1. The `val` is not modified by other threads.
+ 2. The `alc` is thread-safe or NULL.
+
+ @param val The mutable JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free() or alc->free().
+ */
+yyjson_api char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ size_t *len,
+ yyjson_write_err *err);
+
+/**
+ Write a value to JSON file with options.
+
+ This function is thread-safe when:
+ 1. The file is not accessed by other threads.
+ 2. The `val` is not modified by other threads.
+ 3. The `alc` is thread-safe or NULL.
+
+ @param path The JSON file's path.
+ This should be a null-terminated string using the system's native encoding.
+ If this path is NULL or invalid, the function will fail and return false.
+ If this file is not empty, the content will be discarded.
+ @param val The mutable JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_mut_val_write_file(const char *path,
+ const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a value to JSON file with options.
+
+ @param fp The file pointer.
+ The data will be written to the current position of the file.
+ If this path is NULL or invalid, the function will fail and return false.
+ @param val The mutable JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param alc The memory allocator used by JSON writer.
+ Pass NULL to use the libc's default allocator.
+ @param err A pointer to receive error information.
+ Pass NULL if you don't need error information.
+ @return true if successful, false if an error occurs.
+
+ @warning On 32-bit operating system, files larger than 2GB may fail to write.
+ */
+yyjson_api bool yyjson_mut_val_write_fp(FILE *fp,
+ const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ const yyjson_alc *alc,
+ yyjson_write_err *err);
+
+/**
+ Write a value to JSON string.
+
+ This function is thread-safe when:
+ The `val` is not modified by other threads.
+
+ @param val The JSON root value.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param flg The JSON write options.
+ Multiple options can be combined with `|` operator. 0 means no options.
+ @param len A pointer to receive output length in bytes (not including the
+ null-terminator). Pass NULL if you don't need length information.
+ @return A new JSON string, or NULL if an error occurs.
+ This string is encoded as UTF-8 with a null-terminator.
+ When it's no longer needed, it should be freed with free().
+ */
+yyjson_api_inline char *yyjson_mut_val_write(const yyjson_mut_val *val,
+ yyjson_write_flag flg,
+ size_t *len) {
+ return yyjson_mut_val_write_opts(val, flg, NULL, len, NULL);
+}
+
+/**
+ Write a JSON number.
+
+ @param val A JSON number value to be converted to a string.
+ If this parameter is invalid, the function will fail and return NULL.
+ @param buf A buffer to store the resulting null-terminated string.
+ If this parameter is NULL, the function will fail and return NULL.
+ For integer values, the buffer must be at least 21 bytes.
+ For floating-point values, the buffer must be at least 40 bytes.
+ @return On success, returns a pointer to the character after the last
+ written character. On failure, returns NULL.
+ @note
+ - This function is thread-safe and does not allocate memory
+ (when `YYJSON_DISABLE_FAST_FP_CONV` is not defined).
+ - This function will fail and return NULL only in the following cases:
+ 1) `val` or `buf` is NULL;
+ 2) `val` is not a number type;
+ 3) `val` is `inf` or `nan`, and non-standard JSON is explicitly disabled
+ via the `YYJSON_DISABLE_NON_STANDARD` flag.
+ */
+yyjson_api char *yyjson_write_number(const yyjson_val *val, char *buf);
+
+/** Same as `yyjson_write_number()`. */
+yyjson_api_inline char *yyjson_mut_write_number(const yyjson_mut_val *val,
+ char *buf) {
+ return yyjson_write_number((const yyjson_val *)val, buf);
+}
+
+#endif /* YYJSON_DISABLE_WRITER */
+
+
+
+/*==============================================================================
+ * MARK: - JSON Document API
+ *============================================================================*/
+
+/** Returns the root value of this JSON document.
+ Returns NULL if `doc` is NULL. */
+yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc);
+
+/** Returns read size of input JSON data.
+ Returns 0 if `doc` is NULL.
+ For example: the read size of `[1,2,3]` is 7 bytes. */
+yyjson_api_inline size_t yyjson_doc_get_read_size(yyjson_doc *doc);
+
+/** Returns total value count in this JSON document.
+ Returns 0 if `doc` is NULL.
+ For example: the value count of `[1,2,3]` is 4. */
+yyjson_api_inline size_t yyjson_doc_get_val_count(yyjson_doc *doc);
+
+/** Release the JSON document and free the memory.
+ After calling this function, the `doc` and all values from the `doc` are no
+ longer available. This function will do nothing if the `doc` is NULL. */
+yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value Type API
+ *============================================================================*/
+
+/** Returns whether the JSON value is raw.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_raw(yyjson_val *val);
+
+/** Returns whether the JSON value is `null`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_null(yyjson_val *val);
+
+/** Returns whether the JSON value is `true`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_true(yyjson_val *val);
+
+/** Returns whether the JSON value is `false`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_false(yyjson_val *val);
+
+/** Returns whether the JSON value is bool (true/false).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_bool(yyjson_val *val);
+
+/** Returns whether the JSON value is unsigned integer (uint64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_uint(yyjson_val *val);
+
+/** Returns whether the JSON value is signed integer (int64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_sint(yyjson_val *val);
+
+/** Returns whether the JSON value is integer (uint64_t/int64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_int(yyjson_val *val);
+
+/** Returns whether the JSON value is real number (double).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_real(yyjson_val *val);
+
+/** Returns whether the JSON value is number (uint64_t/int64_t/double).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_num(yyjson_val *val);
+
+/** Returns whether the JSON value is string.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_str(yyjson_val *val);
+
+/** Returns whether the JSON value is array.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_arr(yyjson_val *val);
+
+/** Returns whether the JSON value is object.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_obj(yyjson_val *val);
+
+/** Returns whether the JSON value is container (array/object).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value Content API
+ *============================================================================*/
+
+/** Returns the JSON value's type.
+ Returns YYJSON_TYPE_NONE if `val` is NULL. */
+yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val);
+
+/** Returns the JSON value's subtype.
+ Returns YYJSON_SUBTYPE_NONE if `val` is NULL. */
+yyjson_api_inline yyjson_subtype yyjson_get_subtype(yyjson_val *val);
+
+/** Returns the JSON value's tag.
+ Returns 0 if `val` is NULL. */
+yyjson_api_inline uint8_t yyjson_get_tag(yyjson_val *val);
+
+/** Returns the JSON value's type description.
+ The return value should be one of these strings: "raw", "null", "string",
+ "array", "object", "true", "false", "uint", "sint", "real", "unknown". */
+yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val);
+
+/** Returns the content if the value is raw.
+ Returns NULL if `val` is NULL or type is not raw. */
+yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val);
+
+/** Returns the content if the value is bool.
+ Returns false if `val` is NULL or type is not bool. */
+yyjson_api_inline bool yyjson_get_bool(yyjson_val *val);
+
+/** Returns the content and cast to uint64_t.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline uint64_t yyjson_get_uint(yyjson_val *val);
+
+/** Returns the content and cast to int64_t.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline int64_t yyjson_get_sint(yyjson_val *val);
+
+/** Returns the content and cast to int.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline int yyjson_get_int(yyjson_val *val);
+
+/** Returns the content if the value is real number, or 0.0 on error.
+ Returns 0.0 if `val` is NULL or type is not real(double). */
+yyjson_api_inline double yyjson_get_real(yyjson_val *val);
+
+/** Returns the content and typecast to `double` if the value is number.
+ Returns 0.0 if `val` is NULL or type is not number(uint/sint/real). */
+yyjson_api_inline double yyjson_get_num(yyjson_val *val);
+
+/** Returns the content if the value is string.
+ Returns NULL if `val` is NULL or type is not string. */
+yyjson_api_inline const char *yyjson_get_str(yyjson_val *val);
+
+/** Returns the content length (string length, array size, object size.
+ Returns 0 if `val` is NULL or type is not string/array/object. */
+yyjson_api_inline size_t yyjson_get_len(yyjson_val *val);
+
+/** Returns whether the JSON value is equals to a string.
+ Returns false if input is NULL or type is not string. */
+yyjson_api_inline bool yyjson_equals_str(yyjson_val *val, const char *str);
+
+/** Returns whether the JSON value is equals to a string.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+ Returns false if input is NULL or type is not string. */
+yyjson_api_inline bool yyjson_equals_strn(yyjson_val *val, const char *str,
+ size_t len);
+
+/** Returns whether two JSON values are equal (deep compare).
+ Returns false if input is NULL.
+ @note the result may be inaccurate if object has duplicate keys.
+ @warning This function is recursive and may cause a stack overflow
+ if the object level is too deep. */
+yyjson_api_inline bool yyjson_equals(yyjson_val *lhs, yyjson_val *rhs);
+
+/** Set the value to raw.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_raw(yyjson_val *val,
+ const char *raw, size_t len);
+
+/** Set the value to null.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_null(yyjson_val *val);
+
+/** Set the value to bool.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_bool(yyjson_val *val, bool num);
+
+/** Set the value to uint.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_uint(yyjson_val *val, uint64_t num);
+
+/** Set the value to sint.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_sint(yyjson_val *val, int64_t num);
+
+/** Set the value to int.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_int(yyjson_val *val, int num);
+
+/** Set the value to float.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_float(yyjson_val *val, float num);
+
+/** Set the value to double.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_double(yyjson_val *val, double num);
+
+/** Set the value to real.
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_real(yyjson_val *val, double num);
+
+/** Set the floating-point number's output format to fixed-point notation.
+ Returns false if input is NULL or `val` is not real type.
+ @see YYJSON_WRITE_FP_TO_FIXED flag.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_fp_to_fixed(yyjson_val *val, int prec);
+
+/** Set the floating-point number's output format to single-precision.
+ Returns false if input is NULL or `val` is not real type.
+ @see YYJSON_WRITE_FP_TO_FLOAT flag.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_fp_to_float(yyjson_val *val, bool flt);
+
+/** Set the value to string (null-terminated).
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_str(yyjson_val *val, const char *str);
+
+/** Set the value to string (with length).
+ Returns false if input is NULL or `val` is object or array.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_strn(yyjson_val *val,
+ const char *str, size_t len);
+
+/** Marks this string as not needing to be escaped during JSON writing.
+ This can be used to avoid the overhead of escaping if the string contains
+ only characters that do not require escaping.
+ Returns false if input is NULL or `val` is not string.
+ @see YYJSON_SUBTYPE_NOESC subtype.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Array API
+ *============================================================================*/
+
+/** Returns the number of elements in this array.
+ Returns 0 if `arr` is NULL or type is not array. */
+yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr);
+
+/** Returns the element at the specified position in this array.
+ Returns NULL if array is NULL/empty or the index is out of bounds.
+ @warning This function takes a linear search time if array is not flat.
+ For example: `[1,{},3]` is flat, `[1,[2],3]` is not flat. */
+yyjson_api_inline yyjson_val *yyjson_arr_get(yyjson_val *arr, size_t idx);
+
+/** Returns the first element of this array.
+ Returns NULL if `arr` is NULL/empty or type is not array. */
+yyjson_api_inline yyjson_val *yyjson_arr_get_first(yyjson_val *arr);
+
+/** Returns the last element of this array.
+ Returns NULL if `arr` is NULL/empty or type is not array.
+ @warning This function takes a linear search time if array is not flat.
+ For example: `[1,{},3]` is flat, `[1,[2],3]` is not flat.*/
+yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Array Iterator API
+ *============================================================================*/
+
+/**
+ A JSON array iterator.
+
+ @b Example
+ @code
+ yyjson_val *val;
+ yyjson_arr_iter iter = yyjson_arr_iter_with(arr);
+ while ((val = yyjson_arr_iter_next(&iter))) {
+ your_func(val);
+ }
+ @endcode
+ */
+typedef struct yyjson_arr_iter {
+ size_t idx; /**< next value's index */
+ size_t max; /**< maximum index (arr.size) */
+ yyjson_val *cur; /**< next value */
+} yyjson_arr_iter;
+
+/**
+ Initialize an iterator for this array.
+
+ @param arr The array to be iterated over.
+ If this parameter is NULL or not an array, `iter` will be set to empty.
+ @param iter The iterator to be initialized.
+ If this parameter is NULL, the function will fail and return false.
+ @return true if the `iter` has been successfully initialized.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr,
+ yyjson_arr_iter *iter);
+
+/**
+ Create an iterator with an array , same as `yyjson_arr_iter_init()`.
+
+ @param arr The array to be iterated over.
+ If this parameter is NULL or not an array, an empty iterator will returned.
+ @return A new iterator for the array.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline yyjson_arr_iter yyjson_arr_iter_with(yyjson_val *arr);
+
+/**
+ Returns whether the iteration has more elements.
+ If `iter` is NULL, this function will return false.
+ */
+yyjson_api_inline bool yyjson_arr_iter_has_next(yyjson_arr_iter *iter);
+
+/**
+ Returns the next element in the iteration, or NULL on end.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter);
+
+/**
+ Macro for iterating over an array.
+ It works like iterator, but with a more intuitive API.
+
+ @b Example
+ @code
+ size_t idx, max;
+ yyjson_val *val;
+ yyjson_arr_foreach(arr, idx, max, val) {
+ your_func(idx, val);
+ }
+ @endcode
+ */
+#define yyjson_arr_foreach(arr, idx, max, val) \
+ for ((idx) = 0, \
+ (max) = yyjson_arr_size(arr), \
+ (val) = yyjson_arr_get_first(arr); \
+ (idx) < (max); \
+ (idx)++, \
+ (val) = unsafe_yyjson_get_next(val))
+
+
+
+/*==============================================================================
+ * MARK: - JSON Object API
+ *============================================================================*/
+
+/** Returns the number of key-value pairs in this object.
+ Returns 0 if `obj` is NULL or type is not object. */
+yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj);
+
+/** Returns the value to which the specified key is mapped.
+ Returns NULL if this object contains no mapping for the key.
+ Returns NULL if `obj/key` is NULL, or type is not object.
+
+ The `key` should be a null-terminated UTF-8 string.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_val *yyjson_obj_get(yyjson_val *obj, const char *key);
+
+/** Returns the value to which the specified key is mapped.
+ Returns NULL if this object contains no mapping for the key.
+ Returns NULL if `obj/key` is NULL, or type is not object.
+
+ The `key` should be a UTF-8 string, null-terminator is not required.
+ The `key_len` should be the length of the key, in bytes.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj, const char *key,
+ size_t key_len);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Object Iterator API
+ *============================================================================*/
+
+/**
+ A JSON object iterator.
+
+ @b Example
+ @code
+ yyjson_val *key, *val;
+ yyjson_obj_iter iter = yyjson_obj_iter_with(obj);
+ while ((key = yyjson_obj_iter_next(&iter))) {
+ val = yyjson_obj_iter_get_val(key);
+ your_func(key, val);
+ }
+ @endcode
+
+ If the ordering of the keys is known at compile-time, you can use this method
+ to speed up value lookups:
+ @code
+ // {"k1":1, "k2": 3, "k3": 3}
+ yyjson_val *key, *val;
+ yyjson_obj_iter iter = yyjson_obj_iter_with(obj);
+ yyjson_val *v1 = yyjson_obj_iter_get(&iter, "k1");
+ yyjson_val *v3 = yyjson_obj_iter_get(&iter, "k3");
+ @endcode
+ @see yyjson_obj_iter_get() and yyjson_obj_iter_getn()
+ */
+typedef struct yyjson_obj_iter {
+ size_t idx; /**< next key's index */
+ size_t max; /**< maximum key index (obj.size) */
+ yyjson_val *cur; /**< next key */
+ yyjson_val *obj; /**< the object being iterated */
+} yyjson_obj_iter;
+
+/**
+ Initialize an iterator for this object.
+
+ @param obj The object to be iterated over.
+ If this parameter is NULL or not an object, `iter` will be set to empty.
+ @param iter The iterator to be initialized.
+ If this parameter is NULL, the function will fail and return false.
+ @return true if the `iter` has been successfully initialized.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj,
+ yyjson_obj_iter *iter);
+
+/**
+ Create an iterator with an object, same as `yyjson_obj_iter_init()`.
+
+ @param obj The object to be iterated over.
+ If this parameter is NULL or not an object, an empty iterator will returned.
+ @return A new iterator for the object.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline yyjson_obj_iter yyjson_obj_iter_with(yyjson_val *obj);
+
+/**
+ Returns whether the iteration has more elements.
+ If `iter` is NULL, this function will return false.
+ */
+yyjson_api_inline bool yyjson_obj_iter_has_next(yyjson_obj_iter *iter);
+
+/**
+ Returns the next key in the iteration, or NULL on end.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_val *yyjson_obj_iter_next(yyjson_obj_iter *iter);
+
+/**
+ Returns the value for key inside the iteration.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_val *yyjson_obj_iter_get_val(yyjson_val *key);
+
+/**
+ Iterates to a specified key and returns the value.
+
+ This function does the same thing as `yyjson_obj_get()`, but is much faster
+ if the ordering of the keys is known at compile-time and you are using the same
+ order to look up the values. If the key exists in this object, then the
+ iterator will stop at the next key, otherwise the iterator will not change and
+ NULL is returned.
+
+ @param iter The object iterator, should not be NULL.
+ @param key The key, should be a UTF-8 string with null-terminator.
+ @return The value to which the specified key is mapped.
+ NULL if this object contains no mapping for the key or input is invalid.
+
+ @warning This function takes a linear search time if the key is not nearby.
+ */
+yyjson_api_inline yyjson_val *yyjson_obj_iter_get(yyjson_obj_iter *iter,
+ const char *key);
+
+/**
+ Iterates to a specified key and returns the value.
+
+ This function does the same thing as `yyjson_obj_getn()`, but is much faster
+ if the ordering of the keys is known at compile-time and you are using the same
+ order to look up the values. If the key exists in this object, then the
+ iterator will stop at the next key, otherwise the iterator will not change and
+ NULL is returned.
+
+ @param iter The object iterator, should not be NULL.
+ @param key The key, should be a UTF-8 string, null-terminator is not required.
+ @param key_len The the length of `key`, in bytes.
+ @return The value to which the specified key is mapped.
+ NULL if this object contains no mapping for the key or input is invalid.
+
+ @warning This function takes a linear search time if the key is not nearby.
+ */
+yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
+ const char *key,
+ size_t key_len);
+
+/**
+ Macro for iterating over an object.
+ It works like iterator, but with a more intuitive API.
+
+ @b Example
+ @code
+ size_t idx, max;
+ yyjson_val *key, *val;
+ yyjson_obj_foreach(obj, idx, max, key, val) {
+ your_func(key, val);
+ }
+ @endcode
+ */
+#define yyjson_obj_foreach(obj, idx, max, key, val) \
+ for ((idx) = 0, \
+ (max) = yyjson_obj_size(obj), \
+ (key) = (obj) ? unsafe_yyjson_get_first(obj) : NULL, \
+ (val) = (key) + 1; \
+ (idx) < (max); \
+ (idx)++, \
+ (key) = unsafe_yyjson_get_next(val), \
+ (val) = (key) + 1)
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Document API
+ *============================================================================*/
+
+/** Returns the root value of this JSON document.
+ Returns NULL if `doc` is NULL. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc);
+
+/** Sets the root value of this JSON document.
+ Pass NULL to clear root value of the document. */
+yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc,
+ yyjson_mut_val *root);
+
+/**
+ Set the string pool size for a mutable document.
+ This function does not allocate memory immediately, but uses the size when
+ the next memory allocation is needed.
+
+ If the caller knows the approximate bytes of strings that the document needs to
+ store (e.g. copy string with `yyjson_mut_strcpy` function), setting a larger
+ size can avoid multiple memory allocations and improve performance.
+
+ @param doc The mutable document.
+ @param len The desired string pool size in bytes (total string length).
+ @return true if successful, false if size is 0 or overflow.
+ */
+yyjson_api bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc,
+ size_t len);
+
+/**
+ Set the value pool size for a mutable document.
+ This function does not allocate memory immediately, but uses the size when
+ the next memory allocation is needed.
+
+ If the caller knows the approximate number of values that the document needs to
+ store (e.g. create new value with `yyjson_mut_xxx` functions), setting a larger
+ size can avoid multiple memory allocations and improve performance.
+
+ @param doc The mutable document.
+ @param count The desired value pool size (number of `yyjson_mut_val`).
+ @return true if successful, false if size is 0 or overflow.
+ */
+yyjson_api bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc,
+ size_t count);
+
+/** Release the JSON document and free the memory.
+ After calling this function, the `doc` and all values from the `doc` are no
+ longer available. This function will do nothing if the `doc` is NULL. */
+yyjson_api void yyjson_mut_doc_free(yyjson_mut_doc *doc);
+
+/** Creates and returns a new mutable JSON document, returns NULL on error.
+ If allocator is NULL, the default allocator will be used. */
+yyjson_api yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc);
+
+/** Copies and returns a new mutable document from input, returns NULL on error.
+ This makes a `deep-copy` on the immutable document.
+ If allocator is NULL, the default allocator will be used.
+ @note `imut_doc` -> `mut_doc`. */
+yyjson_api yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc,
+ const yyjson_alc *alc);
+
+/** Copies and returns a new mutable document from input, returns NULL on error.
+ This makes a `deep-copy` on the mutable document.
+ If allocator is NULL, the default allocator will be used.
+ @note `mut_doc` -> `mut_doc`. */
+yyjson_api yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc,
+ const yyjson_alc *alc);
+
+/** Copies and returns a new mutable value from input, returns NULL on error.
+ This makes a `deep-copy` on the immutable value.
+ The memory was managed by mutable document.
+ @note `imut_val` -> `mut_val`. */
+yyjson_api yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *doc,
+ yyjson_val *val);
+
+/** Copies and returns a new mutable value from input, returns NULL on error.
+ This makes a `deep-copy` on the mutable value.
+ The memory was managed by mutable document.
+ @note `mut_val` -> `mut_val`.
+ @warning This function is recursive and may cause a stack overflow
+ if the object level is too deep. */
+yyjson_api yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
+ yyjson_mut_val *val);
+
+/** Copies and returns a new immutable document from input,
+ returns NULL on error. This makes a `deep-copy` on the mutable document.
+ The returned document should be freed with `yyjson_doc_free()`.
+ @note `mut_doc` -> `imut_doc`.
+ @warning This function is recursive and may cause a stack overflow
+ if the object level is too deep. */
+yyjson_api yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *doc,
+ const yyjson_alc *alc);
+
+/** Copies and returns a new immutable document from input,
+ returns NULL on error. This makes a `deep-copy` on the mutable value.
+ The returned document should be freed with `yyjson_doc_free()`.
+ @note `mut_val` -> `imut_doc`.
+ @warning This function is recursive and may cause a stack overflow
+ if the object level is too deep. */
+yyjson_api yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *val,
+ const yyjson_alc *alc);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Type API
+ *============================================================================*/
+
+/** Returns whether the JSON value is raw.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is `null`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_null(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is `true`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_true(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is `false`.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_false(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is bool (true/false).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_bool(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is unsigned integer (uint64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_uint(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is signed integer (int64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_sint(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is integer (uint64_t/int64_t).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_int(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is real number (double).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_real(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is number (uint/sint/real).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_num(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is string.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_str(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is array.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_arr(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is object.
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_obj(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is container (array/object).
+ Returns false if `val` is NULL. */
+yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Content API
+ *============================================================================*/
+
+/** Returns the JSON value's type.
+ Returns `YYJSON_TYPE_NONE` if `val` is NULL. */
+yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val);
+
+/** Returns the JSON value's subtype.
+ Returns `YYJSON_SUBTYPE_NONE` if `val` is NULL. */
+yyjson_api_inline yyjson_subtype yyjson_mut_get_subtype(yyjson_mut_val *val);
+
+/** Returns the JSON value's tag.
+ Returns 0 if `val` is NULL. */
+yyjson_api_inline uint8_t yyjson_mut_get_tag(yyjson_mut_val *val);
+
+/** Returns the JSON value's type description.
+ The return value should be one of these strings: "raw", "null", "string",
+ "array", "object", "true", "false", "uint", "sint", "real", "unknown". */
+yyjson_api_inline const char *yyjson_mut_get_type_desc(yyjson_mut_val *val);
+
+/** Returns the content if the value is raw.
+ Returns NULL if `val` is NULL or type is not raw. */
+yyjson_api_inline const char *yyjson_mut_get_raw(yyjson_mut_val *val);
+
+/** Returns the content if the value is bool.
+ Returns NULL if `val` is NULL or type is not bool. */
+yyjson_api_inline bool yyjson_mut_get_bool(yyjson_mut_val *val);
+
+/** Returns the content and cast to uint64_t.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline uint64_t yyjson_mut_get_uint(yyjson_mut_val *val);
+
+/** Returns the content and cast to int64_t.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline int64_t yyjson_mut_get_sint(yyjson_mut_val *val);
+
+/** Returns the content and cast to int.
+ Returns 0 if `val` is NULL or type is not integer(sint/uint). */
+yyjson_api_inline int yyjson_mut_get_int(yyjson_mut_val *val);
+
+/** Returns the content if the value is real number.
+ Returns 0.0 if `val` is NULL or type is not real(double). */
+yyjson_api_inline double yyjson_mut_get_real(yyjson_mut_val *val);
+
+/** Returns the content and typecast to `double` if the value is number.
+ Returns 0.0 if `val` is NULL or type is not number(uint/sint/real). */
+yyjson_api_inline double yyjson_mut_get_num(yyjson_mut_val *val);
+
+/** Returns the content if the value is string.
+ Returns NULL if `val` is NULL or type is not string. */
+yyjson_api_inline const char *yyjson_mut_get_str(yyjson_mut_val *val);
+
+/** Returns the content length (string length, array size, object size.
+ Returns 0 if `val` is NULL or type is not string/array/object. */
+yyjson_api_inline size_t yyjson_mut_get_len(yyjson_mut_val *val);
+
+/** Returns whether the JSON value is equals to a string.
+ The `str` should be a null-terminated UTF-8 string.
+ Returns false if input is NULL or type is not string. */
+yyjson_api_inline bool yyjson_mut_equals_str(yyjson_mut_val *val,
+ const char *str);
+
+/** Returns whether the JSON value is equals to a string.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+ Returns false if input is NULL or type is not string. */
+yyjson_api_inline bool yyjson_mut_equals_strn(yyjson_mut_val *val,
+ const char *str, size_t len);
+
+/** Returns whether two JSON values are equal (deep compare).
+ Returns false if input is NULL.
+ @note the result may be inaccurate if object has duplicate keys.
+ @warning This function is recursive and may cause a stack overflow
+ if the object level is too deep. */
+yyjson_api_inline bool yyjson_mut_equals(yyjson_mut_val *lhs,
+ yyjson_mut_val *rhs);
+
+/** Set the value to raw.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_raw(yyjson_mut_val *val,
+ const char *raw, size_t len);
+
+/** Set the value to null.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_null(yyjson_mut_val *val);
+
+/** Set the value to bool.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_bool(yyjson_mut_val *val, bool num);
+
+/** Set the value to uint.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_uint(yyjson_mut_val *val, uint64_t num);
+
+/** Set the value to sint.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_sint(yyjson_mut_val *val, int64_t num);
+
+/** Set the value to int.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_int(yyjson_mut_val *val, int num);
+
+/** Set the value to float.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_float(yyjson_mut_val *val, float num);
+
+/** Set the value to double.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_double(yyjson_mut_val *val, double num);
+
+/** Set the value to real.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_real(yyjson_mut_val *val, double num);
+
+/** Set the floating-point number's output format to fixed-point notation.
+ Returns false if input is NULL or `val` is not real type.
+ @see YYJSON_WRITE_FP_TO_FIXED flag.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_mut_set_fp_to_fixed(yyjson_mut_val *val,
+ int prec);
+
+/** Set the floating-point number's output format to single-precision.
+ Returns false if input is NULL or `val` is not real type.
+ @see YYJSON_WRITE_FP_TO_FLOAT flag.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_mut_set_fp_to_float(yyjson_mut_val *val,
+ bool flt);
+
+/** Set the value to string (null-terminated).
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_str(yyjson_mut_val *val, const char *str);
+
+/** Set the value to string (with length).
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_strn(yyjson_mut_val *val,
+ const char *str, size_t len);
+
+/** Marks this string as not needing to be escaped during JSON writing.
+ This can be used to avoid the overhead of escaping if the string contains
+ only characters that do not require escaping.
+ Returns false if input is NULL or `val` is not string.
+ @see YYJSON_SUBTYPE_NOESC subtype.
+ @warning This will modify the `immutable` value, use with caution. */
+yyjson_api_inline bool yyjson_mut_set_str_noesc(yyjson_mut_val *val,
+ bool noesc);
+
+/** Set the value to array.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_arr(yyjson_mut_val *val);
+
+/** Set the value to array.
+ Returns false if input is NULL.
+ @warning This function should not be used on an existing object or array. */
+yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Creation API
+ *============================================================================*/
+
+/** Creates and returns a raw value, returns NULL on error.
+ The `str` should be a null-terminated UTF-8 string.
+
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_raw(yyjson_mut_doc *doc,
+ const char *str);
+
+/** Creates and returns a raw value, returns NULL on error.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawn(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len);
+
+/** Creates and returns a raw value, returns NULL on error.
+ The `str` should be a null-terminated UTF-8 string.
+ The input string is copied and held by the document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawcpy(yyjson_mut_doc *doc,
+ const char *str);
+
+/** Creates and returns a raw value, returns NULL on error.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+ The input string is copied and held by the document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawncpy(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len);
+
+/** Creates and returns a null value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_null(yyjson_mut_doc *doc);
+
+/** Creates and returns a true value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_true(yyjson_mut_doc *doc);
+
+/** Creates and returns a false value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_false(yyjson_mut_doc *doc);
+
+/** Creates and returns a bool value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_bool(yyjson_mut_doc *doc,
+ bool val);
+
+/** Creates and returns an unsigned integer value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_uint(yyjson_mut_doc *doc,
+ uint64_t num);
+
+/** Creates and returns a signed integer value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_sint(yyjson_mut_doc *doc,
+ int64_t num);
+
+/** Creates and returns a signed integer value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_int(yyjson_mut_doc *doc,
+ int64_t num);
+
+/** Creates and returns a float number value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_float(yyjson_mut_doc *doc,
+ float num);
+
+/** Creates and returns a double number value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_double(yyjson_mut_doc *doc,
+ double num);
+
+/** Creates and returns a real number value, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_real(yyjson_mut_doc *doc,
+ double num);
+
+/** Creates and returns a string value, returns NULL on error.
+ The `str` should be a null-terminated UTF-8 string.
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_str(yyjson_mut_doc *doc,
+ const char *str);
+
+/** Creates and returns a string value, returns NULL on error.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strn(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len);
+
+/** Creates and returns a string value, returns NULL on error.
+ The `str` should be a null-terminated UTF-8 string.
+ The input string is copied and held by the document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strcpy(yyjson_mut_doc *doc,
+ const char *str);
+
+/** Creates and returns a string value, returns NULL on error.
+ The `str` should be a UTF-8 string, null-terminator is not required.
+ The input string is copied and held by the document. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array API
+ *============================================================================*/
+
+/** Returns the number of elements in this array.
+ Returns 0 if `arr` is NULL or type is not array. */
+yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr);
+
+/** Returns the element at the specified position in this array.
+ Returns NULL if array is NULL/empty or the index is out of bounds.
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get(yyjson_mut_val *arr,
+ size_t idx);
+
+/** Returns the first element of this array.
+ Returns NULL if `arr` is NULL/empty or type is not array. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_first(yyjson_mut_val *arr);
+
+/** Returns the last element of this array.
+ Returns NULL if `arr` is NULL/empty or type is not array. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(yyjson_mut_val *arr);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Iterator API
+ *============================================================================*/
+
+/**
+ A mutable JSON array iterator.
+
+ @warning You should not modify the array while iterating over it, but you can
+ use `yyjson_mut_arr_iter_remove()` to remove current value.
+
+ @b Example
+ @code
+ yyjson_mut_val *val;
+ yyjson_mut_arr_iter iter = yyjson_mut_arr_iter_with(arr);
+ while ((val = yyjson_mut_arr_iter_next(&iter))) {
+ your_func(val);
+ if (your_val_is_unused(val)) {
+ yyjson_mut_arr_iter_remove(&iter);
+ }
+ }
+ @endcode
+ */
+typedef struct yyjson_mut_arr_iter {
+ size_t idx; /**< next value's index */
+ size_t max; /**< maximum index (arr.size) */
+ yyjson_mut_val *cur; /**< current value */
+ yyjson_mut_val *pre; /**< previous value */
+ yyjson_mut_val *arr; /**< the array being iterated */
+} yyjson_mut_arr_iter;
+
+/**
+ Initialize an iterator for this array.
+
+ @param arr The array to be iterated over.
+ If this parameter is NULL or not an array, `iter` will be set to empty.
+ @param iter The iterator to be initialized.
+ If this parameter is NULL, the function will fail and return false.
+ @return true if the `iter` has been successfully initialized.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr,
+ yyjson_mut_arr_iter *iter);
+
+/**
+ Create an iterator with an array , same as `yyjson_mut_arr_iter_init()`.
+
+ @param arr The array to be iterated over.
+ If this parameter is NULL or not an array, an empty iterator will returned.
+ @return A new iterator for the array.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline yyjson_mut_arr_iter yyjson_mut_arr_iter_with(
+ yyjson_mut_val *arr);
+
+/**
+ Returns whether the iteration has more elements.
+ If `iter` is NULL, this function will return false.
+ */
+yyjson_api_inline bool yyjson_mut_arr_iter_has_next(
+ yyjson_mut_arr_iter *iter);
+
+/**
+ Returns the next element in the iteration, or NULL on end.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_next(
+ yyjson_mut_arr_iter *iter);
+
+/**
+ Removes and returns current element in the iteration.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
+ yyjson_mut_arr_iter *iter);
+
+/**
+ Macro for iterating over an array.
+ It works like iterator, but with a more intuitive API.
+
+ @warning You should not modify the array while iterating over it.
+
+ @b Example
+ @code
+ size_t idx, max;
+ yyjson_mut_val *val;
+ yyjson_mut_arr_foreach(arr, idx, max, val) {
+ your_func(idx, val);
+ }
+ @endcode
+ */
+#define yyjson_mut_arr_foreach(arr, idx, max, val) \
+ for ((idx) = 0, \
+ (max) = yyjson_mut_arr_size(arr), \
+ (val) = yyjson_mut_arr_get_first(arr); \
+ (idx) < (max); \
+ (idx)++, \
+ (val) = (val)->next)
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Creation API
+ *============================================================================*/
+
+/**
+ Creates and returns an empty mutable array.
+ @param doc A mutable document, used for memory allocation only.
+ @return The new array. NULL if input is NULL or memory allocation failed.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc);
+
+/**
+ Creates and returns a new mutable array with the given boolean values.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of boolean values.
+ @param count The value count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const bool vals[3] = { true, false, true };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_bool(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_bool(
+ yyjson_mut_doc *doc, const bool *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given sint numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of sint numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const int64_t vals[3] = { -1, 0, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_sint64(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint(
+ yyjson_mut_doc *doc, const int64_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given uint numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of uint numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const uint64_t vals[3] = { 0, 1, 0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_uint(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint(
+ yyjson_mut_doc *doc, const uint64_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given real numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of real numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const double vals[3] = { 0.1, 0.2, 0.3 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_real(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_real(
+ yyjson_mut_doc *doc, const double *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given int8 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of int8 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const int8_t vals[3] = { -1, 0, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_sint8(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint8(
+ yyjson_mut_doc *doc, const int8_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given int16 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of int16 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const int16_t vals[3] = { -1, 0, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_sint16(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint16(
+ yyjson_mut_doc *doc, const int16_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given int32 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of int32 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const int32_t vals[3] = { -1, 0, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_sint32(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint32(
+ yyjson_mut_doc *doc, const int32_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given int64 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of int64 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const int64_t vals[3] = { -1, 0, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_sint64(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint64(
+ yyjson_mut_doc *doc, const int64_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given uint8 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of uint8 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const uint8_t vals[3] = { 0, 1, 0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_uint8(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint8(
+ yyjson_mut_doc *doc, const uint8_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given uint16 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of uint16 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const uint16_t vals[3] = { 0, 1, 0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_uint16(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint16(
+ yyjson_mut_doc *doc, const uint16_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given uint32 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of uint32 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const uint32_t vals[3] = { 0, 1, 0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_uint32(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint32(
+ yyjson_mut_doc *doc, const uint32_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given uint64 numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of uint64 numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const uint64_t vals[3] = { 0, 1, 0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_uint64(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint64(
+ yyjson_mut_doc *doc, const uint64_t *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given float numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of float numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const float vals[3] = { -1.0f, 0.0f, 1.0f };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_float(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_float(
+ yyjson_mut_doc *doc, const float *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given double numbers.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of double numbers.
+ @param count The number count. If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const double vals[3] = { -1.0, 0.0, 1.0 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_double(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_double(
+ yyjson_mut_doc *doc, const double *vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given strings, these strings
+ will not be copied.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of UTF-8 null-terminator strings.
+ If this array contains NULL, the function will fail and return NULL.
+ @param count The number of values in `vals`.
+ If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @warning The input strings are not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document. If these strings will be
+ modified, you should use `yyjson_mut_arr_with_strcpy()` instead.
+
+ @b Example
+ @code
+ const char *vals[3] = { "a", "b", "c" };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_str(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_str(
+ yyjson_mut_doc *doc, const char **vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given strings and string
+ lengths, these strings will not be copied.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of UTF-8 strings, null-terminator is not required.
+ If this array contains NULL, the function will fail and return NULL.
+ @param lens A C array of string lengths, in bytes.
+ @param count The number of strings in `vals`.
+ If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @warning The input strings are not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document. If these strings will be
+ modified, you should use `yyjson_mut_arr_with_strncpy()` instead.
+
+ @b Example
+ @code
+ const char *vals[3] = { "a", "bb", "c" };
+ const size_t lens[3] = { 1, 2, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_strn(doc, vals, lens, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strn(
+ yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given strings, these strings
+ will be copied.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of UTF-8 null-terminator strings.
+ If this array contains NULL, the function will fail and return NULL.
+ @param count The number of values in `vals`.
+ If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const char *vals[3] = { "a", "b", "c" };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_strcpy(doc, vals, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strcpy(
+ yyjson_mut_doc *doc, const char **vals, size_t count);
+
+/**
+ Creates and returns a new mutable array with the given strings and string
+ lengths, these strings will be copied.
+
+ @param doc A mutable document, used for memory allocation only.
+ If this parameter is NULL, the function will fail and return NULL.
+ @param vals A C array of UTF-8 strings, null-terminator is not required.
+ If this array contains NULL, the function will fail and return NULL.
+ @param lens A C array of string lengths, in bytes.
+ @param count The number of strings in `vals`.
+ If this value is 0, an empty array will return.
+ @return The new array. NULL if input is invalid or memory allocation failed.
+
+ @b Example
+ @code
+ const char *vals[3] = { "a", "bb", "c" };
+ const size_t lens[3] = { 1, 2, 1 };
+ yyjson_mut_val *arr = yyjson_mut_arr_with_strn(doc, vals, lens, 3);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
+ yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Modification API
+ *============================================================================*/
+
+/**
+ Inserts a value into an array at a given index.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param val The value to be inserted. Returns false if it is NULL.
+ @param idx The index to which to insert the new value.
+ Returns false if the index is out of range.
+ @return Whether successful.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr,
+ yyjson_mut_val *val, size_t idx);
+
+/**
+ Inserts a value at the end of the array.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param val The value to be inserted. Returns false if it is NULL.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_append(yyjson_mut_val *arr,
+ yyjson_mut_val *val);
+
+/**
+ Inserts a value at the head of the array.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param val The value to be inserted. Returns false if it is NULL.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_prepend(yyjson_mut_val *arr,
+ yyjson_mut_val *val);
+
+/**
+ Replaces a value at index and returns old value.
+ @param arr The array to which the value is to be replaced.
+ Returns false if it is NULL or not an array.
+ @param idx The index to which to replace the value.
+ Returns false if the index is out of range.
+ @param val The new value to replace. Returns false if it is NULL.
+ @return Old value, or NULL on error.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_replace(yyjson_mut_val *arr,
+ size_t idx,
+ yyjson_mut_val *val);
+
+/**
+ Removes and returns a value at index.
+ @param arr The array from which the value is to be removed.
+ Returns false if it is NULL or not an array.
+ @param idx The index from which to remove the value.
+ Returns false if the index is out of range.
+ @return Old value, or NULL on error.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove(yyjson_mut_val *arr,
+ size_t idx);
+
+/**
+ Removes and returns the first value in this array.
+ @param arr The array from which the value is to be removed.
+ Returns false if it is NULL or not an array.
+ @return The first value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_first(
+ yyjson_mut_val *arr);
+
+/**
+ Removes and returns the last value in this array.
+ @param arr The array from which the value is to be removed.
+ Returns false if it is NULL or not an array.
+ @return The last value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_last(
+ yyjson_mut_val *arr);
+
+/**
+ Removes all values within a specified range in the array.
+ @param arr The array from which the value is to be removed.
+ Returns false if it is NULL or not an array.
+ @param idx The start index of the range (0 is the first).
+ @param len The number of items in the range (can be 0).
+ @return Whether successful.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline bool yyjson_mut_arr_remove_range(yyjson_mut_val *arr,
+ size_t idx, size_t len);
+
+/**
+ Removes all values in this array.
+ @param arr The array from which all of the values are to be removed.
+ Returns false if it is NULL or not an array.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_clear(yyjson_mut_val *arr);
+
+/**
+ Rotates values in this array for the given number of times.
+ For example: `[1,2,3,4,5]` rotate 2 is `[3,4,5,1,2]`.
+ @param arr The array to be rotated.
+ @param idx Index (or times) to rotate.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
+ size_t idx);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Modification Convenience API
+ *============================================================================*/
+
+/**
+ Adds a value at the end of the array.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param val The value to be inserted. Returns false if it is NULL.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr,
+ yyjson_mut_val *val);
+
+/**
+ Adds a `null` value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_null(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr);
+
+/**
+ Adds a `true` value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_true(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr);
+
+/**
+ Adds a `false` value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_false(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr);
+
+/**
+ Adds a bool value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param val The bool value to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_bool(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ bool val);
+
+/**
+ Adds an unsigned integer value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_uint(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ uint64_t num);
+
+/**
+ Adds a signed integer value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_sint(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ int64_t num);
+
+/**
+ Adds an integer value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_int(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ int64_t num);
+
+/**
+ Adds a float value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_float(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ float num);
+
+/**
+ Adds a double value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_double(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ double num);
+
+/**
+ Adds a double value at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param num The number to be added.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_real(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ double num);
+
+/**
+ Adds a string value at the end of the array (no copy).
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param str A null-terminated UTF-8 string.
+ @return Whether successful.
+ @warning The input string is not copied, you should keep this string unmodified
+ for the lifetime of this JSON document.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_str(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str);
+
+/**
+ Adds a string value at the end of the array (no copy).
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param str A UTF-8 string, null-terminator is not required.
+ @param len The length of the string, in bytes.
+ @return Whether successful.
+ @warning The input string is not copied, you should keep this string unmodified
+ for the lifetime of this JSON document.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_strn(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str,
+ size_t len);
+
+/**
+ Adds a string value at the end of the array (copied).
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param str A null-terminated UTF-8 string.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_strcpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str);
+
+/**
+ Adds a string value at the end of the array (copied).
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @param str A UTF-8 string, null-terminator is not required.
+ @param len The length of the string, in bytes.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_arr_add_strncpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str,
+ size_t len);
+
+/**
+ Creates and adds a new array at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @return The new array, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_arr(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr);
+
+/**
+ Creates and adds a new object at the end of the array.
+ @param doc The `doc` is only used for memory allocation.
+ @param arr The array to which the value is to be inserted.
+ Returns false if it is NULL or not an array.
+ @return The new object, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object API
+ *============================================================================*/
+
+/** Returns the number of key-value pairs in this object.
+ Returns 0 if `obj` is NULL or type is not object. */
+yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj);
+
+/** Returns the value to which the specified key is mapped.
+ Returns NULL if this object contains no mapping for the key.
+ Returns NULL if `obj/key` is NULL, or type is not object.
+
+ The `key` should be a null-terminated UTF-8 string.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_get(yyjson_mut_val *obj,
+ const char *key);
+
+/** Returns the value to which the specified key is mapped.
+ Returns NULL if this object contains no mapping for the key.
+ Returns NULL if `obj/key` is NULL, or type is not object.
+
+ The `key` should be a UTF-8 string, null-terminator is not required.
+ The `key_len` should be the length of the key, in bytes.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
+ const char *key,
+ size_t key_len);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Iterator API
+ *============================================================================*/
+
+/**
+ A mutable JSON object iterator.
+
+ @warning You should not modify the object while iterating over it, but you can
+ use `yyjson_mut_obj_iter_remove()` to remove current value.
+
+ @b Example
+ @code
+ yyjson_mut_val *key, *val;
+ yyjson_mut_obj_iter iter = yyjson_mut_obj_iter_with(obj);
+ while ((key = yyjson_mut_obj_iter_next(&iter))) {
+ val = yyjson_mut_obj_iter_get_val(key);
+ your_func(key, val);
+ if (your_val_is_unused(key, val)) {
+ yyjson_mut_obj_iter_remove(&iter);
+ }
+ }
+ @endcode
+
+ If the ordering of the keys is known at compile-time, you can use this method
+ to speed up value lookups:
+ @code
+ // {"k1":1, "k2": 3, "k3": 3}
+ yyjson_mut_val *key, *val;
+ yyjson_mut_obj_iter iter = yyjson_mut_obj_iter_with(obj);
+ yyjson_mut_val *v1 = yyjson_mut_obj_iter_get(&iter, "k1");
+ yyjson_mut_val *v3 = yyjson_mut_obj_iter_get(&iter, "k3");
+ @endcode
+ @see `yyjson_mut_obj_iter_get()` and `yyjson_mut_obj_iter_getn()`
+ */
+typedef struct yyjson_mut_obj_iter {
+ size_t idx; /**< next key's index */
+ size_t max; /**< maximum key index (obj.size) */
+ yyjson_mut_val *cur; /**< current key */
+ yyjson_mut_val *pre; /**< previous key */
+ yyjson_mut_val *obj; /**< the object being iterated */
+} yyjson_mut_obj_iter;
+
+/**
+ Initialize an iterator for this object.
+
+ @param obj The object to be iterated over.
+ If this parameter is NULL or not an array, `iter` will be set to empty.
+ @param iter The iterator to be initialized.
+ If this parameter is NULL, the function will fail and return false.
+ @return true if the `iter` has been successfully initialized.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj,
+ yyjson_mut_obj_iter *iter);
+
+/**
+ Create an iterator with an object, same as `yyjson_obj_iter_init()`.
+
+ @param obj The object to be iterated over.
+ If this parameter is NULL or not an object, an empty iterator will returned.
+ @return A new iterator for the object.
+
+ @note The iterator does not need to be destroyed.
+ */
+yyjson_api_inline yyjson_mut_obj_iter yyjson_mut_obj_iter_with(
+ yyjson_mut_val *obj);
+
+/**
+ Returns whether the iteration has more elements.
+ If `iter` is NULL, this function will return false.
+ */
+yyjson_api_inline bool yyjson_mut_obj_iter_has_next(
+ yyjson_mut_obj_iter *iter);
+
+/**
+ Returns the next key in the iteration, or NULL on end.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_next(
+ yyjson_mut_obj_iter *iter);
+
+/**
+ Returns the value for key inside the iteration.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get_val(
+ yyjson_mut_val *key);
+
+/**
+ Removes current key-value pair in the iteration, returns the removed value.
+ If `iter` is NULL, this function will return NULL.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_remove(
+ yyjson_mut_obj_iter *iter);
+
+/**
+ Iterates to a specified key and returns the value.
+
+ This function does the same thing as `yyjson_mut_obj_get()`, but is much faster
+ if the ordering of the keys is known at compile-time and you are using the same
+ order to look up the values. If the key exists in this object, then the
+ iterator will stop at the next key, otherwise the iterator will not change and
+ NULL is returned.
+
+ @param iter The object iterator, should not be NULL.
+ @param key The key, should be a UTF-8 string with null-terminator.
+ @return The value to which the specified key is mapped.
+ NULL if this object contains no mapping for the key or input is invalid.
+
+ @warning This function takes a linear search time if the key is not nearby.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get(
+ yyjson_mut_obj_iter *iter, const char *key);
+
+/**
+ Iterates to a specified key and returns the value.
+
+ This function does the same thing as `yyjson_mut_obj_getn()` but is much faster
+ if the ordering of the keys is known at compile-time and you are using the same
+ order to look up the values. If the key exists in this object, then the
+ iterator will stop at the next key, otherwise the iterator will not change and
+ NULL is returned.
+
+ @param iter The object iterator, should not be NULL.
+ @param key The key, should be a UTF-8 string, null-terminator is not required.
+ @param key_len The the length of `key`, in bytes.
+ @return The value to which the specified key is mapped.
+ NULL if this object contains no mapping for the key or input is invalid.
+
+ @warning This function takes a linear search time if the key is not nearby.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
+ yyjson_mut_obj_iter *iter, const char *key, size_t key_len);
+
+/**
+ Macro for iterating over an object.
+ It works like iterator, but with a more intuitive API.
+
+ @warning You should not modify the object while iterating over it.
+
+ @b Example
+ @code
+ size_t idx, max;
+ yyjson_mut_val *key, *val;
+ yyjson_mut_obj_foreach(obj, idx, max, key, val) {
+ your_func(key, val);
+ }
+ @endcode
+ */
+#define yyjson_mut_obj_foreach(obj, idx, max, key, val) \
+ for ((idx) = 0, \
+ (max) = yyjson_mut_obj_size(obj), \
+ (key) = (max) ? ((yyjson_mut_val *)(obj)->uni.ptr)->next->next : NULL, \
+ (val) = (key) ? (key)->next : NULL; \
+ (idx) < (max); \
+ (idx)++, \
+ (key) = (val)->next, \
+ (val) = (key)->next)
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Creation API
+ *============================================================================*/
+
+/** Creates and returns a mutable object, returns NULL on error. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc);
+
+/**
+ Creates and returns a mutable object with keys and values, returns NULL on
+ error. The keys and values are not copied. The strings should be a
+ null-terminated UTF-8 string.
+
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document.
+
+ @b Example
+ @code
+ const char *keys[2] = { "id", "name" };
+ const char *vals[2] = { "01", "Harry" };
+ yyjson_mut_val *obj = yyjson_mut_obj_with_str(doc, keys, vals, 2);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_str(yyjson_mut_doc *doc,
+ const char **keys,
+ const char **vals,
+ size_t count);
+
+/**
+ Creates and returns a mutable object with key-value pairs and pair count,
+ returns NULL on error. The keys and values are not copied. The strings should
+ be a null-terminated UTF-8 string.
+
+ @warning The input string is not copied, you should keep this string
+ unmodified for the lifetime of this JSON document.
+
+ @b Example
+ @code
+ const char *kv_pairs[4] = { "id", "01", "name", "Harry" };
+ yyjson_mut_val *obj = yyjson_mut_obj_with_kv(doc, kv_pairs, 2);
+ @endcode
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
+ const char **kv_pairs,
+ size_t pair_count);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Modification API
+ *============================================================================*/
+
+/**
+ Adds a key-value pair at the end of the object.
+ This function allows duplicated key in one object.
+ @param obj The object to which the new key-value pair is to be added.
+ @param key The key, should be a string which is created by `yyjson_mut_str()`,
+ `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`.
+ @param val The value to add to the object.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_obj_add(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val);
+/**
+ Sets a key-value pair at the end of the object.
+ This function may remove all key-value pairs for the given key before add.
+ @param obj The object to which the new key-value pair is to be added.
+ @param key The key, should be a string which is created by `yyjson_mut_str()`,
+ `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`.
+ @param val The value to add to the object. If this value is null, the behavior
+ is same as `yyjson_mut_obj_remove()`.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_obj_put(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val);
+
+/**
+ Inserts a key-value pair to the object at the given position.
+ This function allows duplicated key in one object.
+ @param obj The object to which the new key-value pair is to be added.
+ @param key The key, should be a string which is created by `yyjson_mut_str()`,
+ `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`.
+ @param val The value to add to the object.
+ @param idx The index to which to insert the new pair.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_obj_insert(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val,
+ size_t idx);
+
+/**
+ Removes all key-value pair from the object with given key.
+ @param obj The object from which the key-value pair is to be removed.
+ @param key The key, should be a string value.
+ @return The first matched value, or NULL if no matched value.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove(yyjson_mut_val *obj,
+ yyjson_mut_val *key);
+
+/**
+ Removes all key-value pair from the object with given key.
+ @param obj The object from which the key-value pair is to be removed.
+ @param key The key, should be a UTF-8 string with null-terminator.
+ @return The first matched value, or NULL if no matched value.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_key(
+ yyjson_mut_val *obj, const char *key);
+
+/**
+ Removes all key-value pair from the object with given key.
+ @param obj The object from which the key-value pair is to be removed.
+ @param key The key, should be a UTF-8 string, null-terminator is not required.
+ @param key_len The length of the key.
+ @return The first matched value, or NULL if no matched value.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_keyn(
+ yyjson_mut_val *obj, const char *key, size_t key_len);
+
+/**
+ Removes all key-value pairs in this object.
+ @param obj The object from which all of the values are to be removed.
+ @return Whether successful.
+ */
+yyjson_api_inline bool yyjson_mut_obj_clear(yyjson_mut_val *obj);
+
+/**
+ Replaces value from the object with given key.
+ If the key is not exist, or the value is NULL, it will fail.
+ @param obj The object to which the value is to be replaced.
+ @param key The key, should be a string value.
+ @param val The value to replace into the object.
+ @return Whether successful.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline bool yyjson_mut_obj_replace(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val);
+
+/**
+ Rotates key-value pairs in the object for the given number of times.
+ For example: `{"a":1,"b":2,"c":3,"d":4}` rotate 1 is
+ `{"b":2,"c":3,"d":4,"a":1}`.
+ @param obj The object to be rotated.
+ @param idx Index (or times) to rotate.
+ @return Whether successful.
+ @warning This function takes a linear search time.
+ */
+yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
+ size_t idx);
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Modification Convenience API
+ *============================================================================*/
+
+/** Adds a `null` value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_null(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key);
+
+/** Adds a `true` value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_true(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key);
+
+/** Adds a `false` value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_false(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key);
+
+/** Adds a bool value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_bool(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, bool val);
+
+/** Adds an unsigned integer value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_uint(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, uint64_t val);
+
+/** Adds a signed integer value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_sint(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, int64_t val);
+
+/** Adds an int value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_int(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, int64_t val);
+
+/** Adds a float value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_float(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, float val);
+
+/** Adds a double value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_double(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, double val);
+
+/** Adds a real value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_real(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, double val);
+
+/** Adds a string value at the end of the object.
+ The `key` and `val` should be null-terminated UTF-8 strings.
+ This function allows duplicated key in one object.
+
+ @warning The key/value strings are not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_str(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key, const char *val);
+
+/** Adds a string value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ The `val` should be a UTF-8 string, null-terminator is not required.
+ The `len` should be the length of the `val`, in bytes.
+ This function allows duplicated key in one object.
+
+ @warning The key/value strings are not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_strn(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ const char *val, size_t len);
+
+/** Adds a string value at the end of the object.
+ The `key` and `val` should be null-terminated UTF-8 strings.
+ The value string is copied.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_strcpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ const char *val);
+
+/** Adds a string value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ The `val` should be a UTF-8 string, null-terminator is not required.
+ The `len` should be the length of the `val`, in bytes.
+ This function allows duplicated key in one object.
+
+ @warning The key strings are not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_strncpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ const char *val, size_t len);
+
+/**
+ Creates and adds a new array to the target object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document.
+ @return The new array, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_add_arr(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key);
+
+/**
+ Creates and adds a new object to the target object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep these strings
+ unmodified for the lifetime of this JSON document.
+ @return The new object, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_add_obj(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key);
+
+/** Adds a JSON value at the end of the object.
+ The `key` should be a null-terminated UTF-8 string.
+ This function allows duplicated key in one object.
+
+ @warning The key string is not copied, you should keep the string
+ unmodified for the lifetime of this JSON document. */
+yyjson_api_inline bool yyjson_mut_obj_add_val(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ yyjson_mut_val *val);
+
+/** Removes all key-value pairs for the given key.
+ Returns the first value to which the specified key is mapped or NULL if this
+ object contains no mapping for the key.
+ The `key` should be a null-terminated UTF-8 string.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_str(
+ yyjson_mut_val *obj, const char *key);
+
+/** Removes all key-value pairs for the given key.
+ Returns the first value to which the specified key is mapped or NULL if this
+ object contains no mapping for the key.
+ The `key` should be a UTF-8 string, null-terminator is not required.
+ The `len` should be the length of the key, in bytes.
+
+ @warning This function takes a linear search time. */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_strn(
+ yyjson_mut_val *obj, const char *key, size_t len);
+
+/** Replaces all matching keys with the new key.
+ Returns true if at least one key was renamed.
+ The `key` and `new_key` should be a null-terminated UTF-8 string.
+ The `new_key` is copied and held by doc.
+
+ @warning This function takes a linear search time.
+ If `new_key` already exists, it will cause duplicate keys.
+ */
+yyjson_api_inline bool yyjson_mut_obj_rename_key(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ const char *new_key);
+
+/** Replaces all matching keys with the new key.
+ Returns true if at least one key was renamed.
+ The `key` and `new_key` should be a UTF-8 string,
+ null-terminator is not required. The `new_key` is copied and held by doc.
+
+ @warning This function takes a linear search time.
+ If `new_key` already exists, it will cause duplicate keys.
+ */
+yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ size_t len,
+ const char *new_key,
+ size_t new_len);
+
+
+
+#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
+
+/*==============================================================================
+ * MARK: - JSON Pointer API (RFC 6901)
+ * https://tools.ietf.org/html/rfc6901
+ *============================================================================*/
+
+/** JSON Pointer error code. */
+typedef uint32_t yyjson_ptr_code;
+
+/** No JSON pointer error. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_NONE = 0;
+
+/** Invalid input parameter, such as NULL input. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_PARAMETER = 1;
+
+/** JSON pointer syntax error, such as invalid escape, token no prefix. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_SYNTAX = 2;
+
+/** JSON pointer resolve failed, such as index out of range, key not found. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_RESOLVE = 3;
+
+/** Document's root is NULL, but it is required for the function call. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_NULL_ROOT = 4;
+
+/** Cannot set root as the target is not a document. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_SET_ROOT = 5;
+
+/** The memory allocation failed and a new value could not be created. */
+static const yyjson_ptr_code YYJSON_PTR_ERR_MEMORY_ALLOCATION = 6;
+
+/** Error information for JSON pointer. */
+typedef struct yyjson_ptr_err {
+ /** Error code, see `yyjson_ptr_code` for all possible values. */
+ yyjson_ptr_code code;
+ /** Error message, constant, no need to free (NULL if no error). */
+ const char *msg;
+ /** Error byte position for input JSON pointer (0 if no error). */
+ size_t pos;
+} yyjson_ptr_err;
+
+/**
+ A context for JSON pointer operation.
+
+ This struct stores the context of JSON Pointer operation result. The struct
+ can be used with three helper functions: `ctx_append()`, `ctx_replace()`, and
+ `ctx_remove()`, which perform the corresponding operations on the container
+ without re-parsing the JSON Pointer.
+
+ For example:
+ @code
+ // doc before: {"a":[0,1,null]}
+ // ptr: "/a/2"
+ val = yyjson_mut_doc_ptr_getx(doc, ptr, strlen(ptr), &ctx, &err);
+ if (yyjson_is_null(val)) {
+ yyjson_ptr_ctx_remove(&ctx);
+ }
+ // doc after: {"a":[0,1]}
+ @endcode
+ */
+typedef struct yyjson_ptr_ctx {
+ /**
+ The container (parent) of the target value. It can be either an array or
+ an object. If the target location has no value, but all its parent
+ containers exist, and the target location can be used to insert a new
+ value, then `ctn` is the parent container of the target location.
+ Otherwise, `ctn` is NULL.
+ */
+ yyjson_mut_val *ctn;
+ /**
+ The previous sibling of the target value. It can be either a value in an
+ array or a key in an object. As the container is a `circular linked list`
+ of elements, `pre` is the previous node of the target value. If the
+ operation is `add` or `set`, then `pre` is the previous node of the new
+ value, not the original target value. If the target value does not exist,
+ `pre` is NULL.
+ */
+ yyjson_mut_val *pre;
+ /**
+ The removed value if the operation is `set`, `replace` or `remove`. It can
+ be used to restore the original state of the document if needed.
+ */
+ yyjson_mut_val *old;
+} yyjson_ptr_ctx;
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_get(yyjson_doc *doc,
+ const char *ptr);
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_getn(yyjson_doc *doc,
+ const char *ptr, size_t len);
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_getx(yyjson_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_ptr_err *err);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_ptr_get(yyjson_val *val,
+ const char *ptr);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_ptr_getn(yyjson_val *val,
+ const char *ptr, size_t len);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_val *yyjson_ptr_getx(yyjson_val *val,
+ const char *ptr, size_t len,
+ yyjson_ptr_err *err);
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_get(yyjson_mut_doc *doc,
+ const char *ptr);
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getn(yyjson_mut_doc *doc,
+ const char *ptr,
+ size_t len);
+
+/**
+ Get value by a JSON Pointer.
+ @param doc The JSON document to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The value referenced by the JSON pointer.
+ NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getx(yyjson_mut_doc *doc,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_get(yyjson_mut_val *val,
+ const char *ptr);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getn(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len);
+
+/**
+ Get value by a JSON Pointer.
+ @param val The JSON value to be queried.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The value referenced by the JSON pointer.
+ NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getx(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param new_val The value to be added.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_add(yyjson_mut_doc *doc,
+ const char *ptr,
+ yyjson_mut_val *new_val);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be added.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_addn(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be added.
+ @param create_parent Whether to create parent nodes if not exist.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_addx(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param doc Only used to create new values when needed.
+ @param new_val The value to be added.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_add(yyjson_mut_val *val,
+ const char *ptr,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param doc Only used to create new values when needed.
+ @param new_val The value to be added.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_addn(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc);
+
+/**
+ Add (insert) value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param doc Only used to create new values when needed.
+ @param new_val The value to be added.
+ @param create_parent Whether to create parent nodes if not exist.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return true if JSON pointer is valid and new value is added, false otherwise.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_addx(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Set value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param new_val The value to be set, pass NULL to remove.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_set(yyjson_mut_doc *doc,
+ const char *ptr,
+ yyjson_mut_val *new_val);
+
+/**
+ Set value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be set, pass NULL to remove.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_setn(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val);
+
+/**
+ Set value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be set, pass NULL to remove.
+ @param create_parent Whether to create parent nodes if not exist.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_doc_ptr_setx(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Set value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param new_val The value to be set, pass NULL to remove.
+ @param doc Only used to create new values when needed.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_set(yyjson_mut_val *val,
+ const char *ptr,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc);
+
+/**
+ Set value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be set, pass NULL to remove.
+ @param doc Only used to create new values when needed.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note The parent nodes will be created if they do not exist.
+ If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_setn(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc);
+
+/**
+ Set value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The value to be set, pass NULL to remove.
+ @param doc Only used to create new values when needed.
+ @param create_parent Whether to create parent nodes if not exist.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return true if JSON pointer is valid and new value is set, false otherwise.
+ @note If the target value already exists, it will be replaced by the new value.
+ */
+yyjson_api_inline bool yyjson_mut_ptr_setx(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Replace value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param new_val The new value to replace the old one.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replace(
+ yyjson_mut_doc *doc, const char *ptr, yyjson_mut_val *new_val);
+
+/**
+ Replace value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The new value to replace the old one.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacen(
+ yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val);
+
+/**
+ Replace value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The new value to replace the old one.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacex(
+ yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err);
+
+/**
+ Replace value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @param new_val The new value to replace the old one.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replace(
+ yyjson_mut_val *val, const char *ptr, yyjson_mut_val *new_val);
+
+/**
+ Replace value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The new value to replace the old one.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacen(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val);
+
+/**
+ Replace value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param new_val The new value to replace the old one.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The old value that was replaced, or NULL if not found.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacex(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err);
+
+/**
+ Remove value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_remove(
+ yyjson_mut_doc *doc, const char *ptr);
+
+/**
+ Remove value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removen(
+ yyjson_mut_doc *doc, const char *ptr, size_t len);
+
+/**
+ Remove value by a JSON pointer.
+ @param doc The target JSON document.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removex(
+ yyjson_mut_doc *doc, const char *ptr, size_t len,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err);
+
+/**
+ Remove value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8 with null-terminator).
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_remove(yyjson_mut_val *val,
+ const char *ptr);
+
+/**
+ Remove value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removen(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len);
+
+/**
+ Remove value by a JSON pointer.
+ @param val The target JSON value.
+ @param ptr The JSON pointer string (UTF-8, null-terminator is not required).
+ @param len The length of `ptr` in bytes.
+ @param ctx A pointer to store the result context, or NULL if not needed.
+ @param err A pointer to store the error information, or NULL if not needed.
+ @return The removed value, or NULL on error.
+ */
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removex(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/**
+ Append value by JSON pointer context.
+ @param ctx The context from the `yyjson_mut_ptr_xxx()` calls.
+ @param key New key if `ctx->ctn` is object, or NULL if `ctx->ctn` is array.
+ @param val New value to be added.
+ @return true on success or false on fail.
+ */
+yyjson_api_inline bool yyjson_ptr_ctx_append(yyjson_ptr_ctx *ctx,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val);
+
+/**
+ Replace value by JSON pointer context.
+ @param ctx The context from the `yyjson_mut_ptr_xxx()` calls.
+ @param val New value to be replaced.
+ @return true on success or false on fail.
+ @note If success, the old value will be returned via `ctx->old`.
+ */
+yyjson_api_inline bool yyjson_ptr_ctx_replace(yyjson_ptr_ctx *ctx,
+ yyjson_mut_val *val);
+
+/**
+ Remove value by JSON pointer context.
+ @param ctx The context from the `yyjson_mut_ptr_xxx()` calls.
+ @return true on success or false on fail.
+ @note If success, the old value will be returned via `ctx->old`.
+ */
+yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Patch API (RFC 6902)
+ * https://tools.ietf.org/html/rfc6902
+ *============================================================================*/
+
+/** Result code for JSON patch. */
+typedef uint32_t yyjson_patch_code;
+
+/** Success, no error. */
+static const yyjson_patch_code YYJSON_PATCH_SUCCESS = 0;
+
+/** Invalid parameter, such as NULL input or non-array patch. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_PARAMETER = 1;
+
+/** Memory allocation failure occurs. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_MEMORY_ALLOCATION = 2;
+
+/** JSON patch operation is not object type. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_OPERATION = 3;
+
+/** JSON patch operation is missing a required key. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_MISSING_KEY = 4;
+
+/** JSON patch operation member is invalid. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_MEMBER = 5;
+
+/** JSON patch operation `test` not equal. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_EQUAL = 6;
+
+/** JSON patch operation failed on JSON pointer. */
+static const yyjson_patch_code YYJSON_PATCH_ERROR_POINTER = 7;
+
+/** Error information for JSON patch. */
+typedef struct yyjson_patch_err {
+ /** Error code, see `yyjson_patch_code` for all possible values. */
+ yyjson_patch_code code;
+ /** Index of the error operation (0 if no error). */
+ size_t idx;
+ /** Error message, constant, no need to free (NULL if no error). */
+ const char *msg;
+ /** JSON pointer error if `code == YYJSON_PATCH_ERROR_POINTER`. */
+ yyjson_ptr_err ptr;
+} yyjson_patch_err;
+
+/**
+ Creates and returns a patched JSON value (RFC 6902).
+ The memory of the returned value is allocated by the `doc`.
+ The `err` is used to receive error information, pass NULL if not needed.
+ Returns NULL if the patch could not be applied.
+ */
+yyjson_api yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
+ yyjson_val *orig,
+ yyjson_val *patch,
+ yyjson_patch_err *err);
+
+/**
+ Creates and returns a patched JSON value (RFC 6902).
+ The memory of the returned value is allocated by the `doc`.
+ The `err` is used to receive error information, pass NULL if not needed.
+ Returns NULL if the patch could not be applied.
+ */
+yyjson_api yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
+ yyjson_mut_val *orig,
+ yyjson_mut_val *patch,
+ yyjson_patch_err *err);
+
+
+
+/*==============================================================================
+ * MARK: - JSON Merge-Patch API (RFC 7386)
+ * https://tools.ietf.org/html/rfc7386
+ *============================================================================*/
+
+/**
+ Creates and returns a merge-patched JSON value (RFC 7386).
+ The memory of the returned value is allocated by the `doc`.
+ Returns NULL if the patch could not be applied.
+
+ @warning This function is recursive and may cause a stack overflow if the
+ object level is too deep.
+ */
+yyjson_api yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
+ yyjson_val *orig,
+ yyjson_val *patch);
+
+/**
+ Creates and returns a merge-patched JSON value (RFC 7386).
+ The memory of the returned value is allocated by the `doc`.
+ Returns NULL if the patch could not be applied.
+
+ @warning This function is recursive and may cause a stack overflow if the
+ object level is too deep.
+ */
+yyjson_api yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
+ yyjson_mut_val *orig,
+ yyjson_mut_val *patch);
+
+#endif /* YYJSON_DISABLE_UTILS */
+
+
+
+/*==============================================================================
+ * MARK: - JSON Structure (Implementation)
+ *============================================================================*/
+
+/** Payload of a JSON value (8 bytes). */
+typedef union yyjson_val_uni {
+ uint64_t u64;
+ int64_t i64;
+ double f64;
+ const char *str;
+ void *ptr;
+ size_t ofs;
+} yyjson_val_uni;
+
+/**
+ Immutable JSON value, 16 bytes.
+ */
+struct yyjson_val {
+ uint64_t tag; /**< type, subtype and length */
+ yyjson_val_uni uni; /**< payload */
+};
+
+struct yyjson_doc {
+ /** Root value of the document (nonnull). */
+ yyjson_val *root;
+ /** Allocator used by document (nonnull). */
+ yyjson_alc alc;
+ /** The total number of bytes read when parsing JSON (nonzero). */
+ size_t dat_read;
+ /** The total number of value read when parsing JSON (nonzero). */
+ size_t val_read;
+ /** The string pool used by JSON values (nullable). */
+ char *str_pool;
+};
+
+
+
+/*==============================================================================
+ * MARK: - Unsafe JSON Value API (Implementation)
+ *============================================================================*/
+
+/*
+ Whether the string does not need to be escaped for serialization.
+ This function is used to optimize the writing speed of small constant strings.
+ This function works only if the compiler can evaluate it at compile time.
+
+ Clang supports it since v8.0,
+ earlier versions do not support constant_p(strlen) and return false.
+ GCC supports it since at least v4.4,
+ earlier versions may compile it as run-time instructions.
+ ICC supports it since at least v16,
+ earlier versions are uncertain.
+
+ @param str The C string.
+ @param len The returnd value from strlen(str).
+ */
+yyjson_api_inline bool unsafe_yyjson_is_str_noesc(const char *str, size_t len) {
+#if YYJSON_HAS_CONSTANT_P && \
+ (!YYJSON_IS_REAL_GCC || yyjson_gcc_available(4, 4, 0))
+ if (yyjson_constant_p(len) && len <= 32) {
+ /*
+ Same as the following loop:
+
+ for (size_t i = 0; i < len; i++) {
+ char c = str[i];
+ if (c < ' ' || c > '~' || c == '"' || c == '\\') return false;
+ }
+
+ GCC evaluates it at compile time only if the string length is within 17
+ and -O3 (which turns on the -fpeel-loops flag) is used.
+ So the loop is unrolled for GCC.
+ */
+# define yyjson_repeat32_incr(x) \
+ x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
+ x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) \
+ x(16) x(17) x(18) x(19) x(20) x(21) x(22) x(23) \
+ x(24) x(25) x(26) x(27) x(28) x(29) x(30) x(31)
+# define yyjson_check_char_noesc(i) \
+ if (i < len) { \
+ char c = str[i]; \
+ if (c < ' ' || c > '~' || c == '"' || c == '\\') return false; }
+ yyjson_repeat32_incr(yyjson_check_char_noesc)
+# undef yyjson_repeat32_incr
+# undef yyjson_check_char_noesc
+ return true;
+ }
+#else
+ (void)str;
+ (void)len;
+#endif
+ return false;
+}
+
+yyjson_api_inline double unsafe_yyjson_u64_to_f64(uint64_t num) {
+#if YYJSON_U64_TO_F64_NO_IMPL
+ uint64_t msb = ((uint64_t)1) << 63;
+ if ((num & msb) == 0) {
+ return (double)(int64_t)num;
+ } else {
+ return ((double)(int64_t)((num >> 1) | (num & 1))) * (double)2.0;
+ }
+#else
+ return (double)num;
+#endif
+}
+
+yyjson_api_inline yyjson_type unsafe_yyjson_get_type(void *val) {
+ uint8_t tag = (uint8_t)((yyjson_val *)val)->tag;
+ return (yyjson_type)(tag & YYJSON_TYPE_MASK);
+}
+
+yyjson_api_inline yyjson_subtype unsafe_yyjson_get_subtype(void *val) {
+ uint8_t tag = (uint8_t)((yyjson_val *)val)->tag;
+ return (yyjson_subtype)(tag & YYJSON_SUBTYPE_MASK);
+}
+
+yyjson_api_inline uint8_t unsafe_yyjson_get_tag(void *val) {
+ uint8_t tag = (uint8_t)((yyjson_val *)val)->tag;
+ return (uint8_t)(tag & YYJSON_TAG_MASK);
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_raw(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_RAW;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_null(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_NULL;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_bool(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_BOOL;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_num(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_NUM;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_str(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_STR;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_arr(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_ARR;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_obj(void *val) {
+ return unsafe_yyjson_get_type(val) == YYJSON_TYPE_OBJ;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_ctn(void *val) {
+ uint8_t mask = YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ;
+ return (unsafe_yyjson_get_tag(val) & mask) == mask;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_uint(void *val) {
+ const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT;
+ return unsafe_yyjson_get_tag(val) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_sint(void *val) {
+ const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT;
+ return unsafe_yyjson_get_tag(val) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_int(void *val) {
+ const uint8_t mask = YYJSON_TAG_MASK & (~YYJSON_SUBTYPE_SINT);
+ const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT;
+ return (unsafe_yyjson_get_tag(val) & mask) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_real(void *val) {
+ const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
+ return unsafe_yyjson_get_tag(val) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_true(void *val) {
+ const uint8_t patt = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
+ return unsafe_yyjson_get_tag(val) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_is_false(void *val) {
+ const uint8_t patt = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
+ return unsafe_yyjson_get_tag(val) == patt;
+}
+
+yyjson_api_inline bool unsafe_yyjson_arr_is_flat(yyjson_val *val) {
+ size_t ofs = val->uni.ofs;
+ size_t len = (size_t)(val->tag >> YYJSON_TAG_BIT);
+ return len * sizeof(yyjson_val) + sizeof(yyjson_val) == ofs;
+}
+
+yyjson_api_inline const char *unsafe_yyjson_get_raw(void *val) {
+ return ((yyjson_val *)val)->uni.str;
+}
+
+yyjson_api_inline bool unsafe_yyjson_get_bool(void *val) {
+ uint8_t tag = unsafe_yyjson_get_tag(val);
+ return (bool)((tag & YYJSON_SUBTYPE_MASK) >> YYJSON_TYPE_BIT);
+}
+
+yyjson_api_inline uint64_t unsafe_yyjson_get_uint(void *val) {
+ return ((yyjson_val *)val)->uni.u64;
+}
+
+yyjson_api_inline int64_t unsafe_yyjson_get_sint(void *val) {
+ return ((yyjson_val *)val)->uni.i64;
+}
+
+yyjson_api_inline int unsafe_yyjson_get_int(void *val) {
+ return (int)((yyjson_val *)val)->uni.i64;
+}
+
+yyjson_api_inline double unsafe_yyjson_get_real(void *val) {
+ return ((yyjson_val *)val)->uni.f64;
+}
+
+yyjson_api_inline double unsafe_yyjson_get_num(void *val) {
+ uint8_t tag = unsafe_yyjson_get_tag(val);
+ if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL)) {
+ return ((yyjson_val *)val)->uni.f64;
+ } else if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT)) {
+ return (double)((yyjson_val *)val)->uni.i64;
+ } else if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT)) {
+ return unsafe_yyjson_u64_to_f64(((yyjson_val *)val)->uni.u64);
+ }
+ return 0.0;
+}
+
+yyjson_api_inline const char *unsafe_yyjson_get_str(void *val) {
+ return ((yyjson_val *)val)->uni.str;
+}
+
+yyjson_api_inline size_t unsafe_yyjson_get_len(void *val) {
+ return (size_t)(((yyjson_val *)val)->tag >> YYJSON_TAG_BIT);
+}
+
+yyjson_api_inline yyjson_val *unsafe_yyjson_get_first(yyjson_val *ctn) {
+ return ctn + 1;
+}
+
+yyjson_api_inline yyjson_val *unsafe_yyjson_get_next(yyjson_val *val) {
+ bool is_ctn = unsafe_yyjson_is_ctn(val);
+ size_t ctn_ofs = val->uni.ofs;
+ size_t ofs = (is_ctn ? ctn_ofs : sizeof(yyjson_val));
+ return (yyjson_val *)(void *)((uint8_t *)val + ofs);
+}
+
+yyjson_api_inline bool unsafe_yyjson_equals_strn(void *val, const char *str,
+ size_t len) {
+ return unsafe_yyjson_get_len(val) == len &&
+ memcmp(((yyjson_val *)val)->uni.str, str, len) == 0;
+}
+
+yyjson_api_inline bool unsafe_yyjson_equals_str(void *val, const char *str) {
+ return unsafe_yyjson_equals_strn(val, str, strlen(str));
+}
+
+yyjson_api_inline void unsafe_yyjson_set_type(void *val, yyjson_type type,
+ yyjson_subtype subtype) {
+ uint8_t tag = (type | subtype);
+ uint64_t new_tag = ((yyjson_val *)val)->tag;
+ new_tag = (new_tag & (~(uint64_t)YYJSON_TAG_MASK)) | (uint64_t)tag;
+ ((yyjson_val *)val)->tag = new_tag;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_len(void *val, size_t len) {
+ uint64_t tag = ((yyjson_val *)val)->tag & YYJSON_TAG_MASK;
+ tag |= (uint64_t)len << YYJSON_TAG_BIT;
+ ((yyjson_val *)val)->tag = tag;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_tag(void *val, yyjson_type type,
+ yyjson_subtype subtype,
+ size_t len) {
+ uint64_t tag = (uint64_t)len << YYJSON_TAG_BIT;
+ tag |= (type | subtype);
+ ((yyjson_val *)val)->tag = tag;
+}
+
+yyjson_api_inline void unsafe_yyjson_inc_len(void *val) {
+ uint64_t tag = ((yyjson_val *)val)->tag;
+ tag += (uint64_t)(1 << YYJSON_TAG_BIT);
+ ((yyjson_val *)val)->tag = tag;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_raw(void *val, const char *raw,
+ size_t len) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_RAW, YYJSON_SUBTYPE_NONE, len);
+ ((yyjson_val *)val)->uni.str = raw;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_null(void *val) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NULL, YYJSON_SUBTYPE_NONE, 0);
+}
+
+yyjson_api_inline void unsafe_yyjson_set_bool(void *val, bool num) {
+ yyjson_subtype subtype = num ? YYJSON_SUBTYPE_TRUE : YYJSON_SUBTYPE_FALSE;
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_BOOL, subtype, 0);
+}
+
+yyjson_api_inline void unsafe_yyjson_set_uint(void *val, uint64_t num) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_UINT, 0);
+ ((yyjson_val *)val)->uni.u64 = num;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_sint(void *val, int64_t num) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_SINT, 0);
+ ((yyjson_val *)val)->uni.i64 = num;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_fp_to_fixed(void *val, int prec) {
+ ((yyjson_val *)val)->tag &= ~((uint64_t)YYJSON_WRITE_FP_TO_FIXED(15) << 32);
+ ((yyjson_val *)val)->tag |= (uint64_t)YYJSON_WRITE_FP_TO_FIXED(prec) << 32;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_fp_to_float(void *val, bool flt) {
+ uint64_t flag = (uint64_t)YYJSON_WRITE_FP_TO_FLOAT << 32;
+ if (flt) ((yyjson_val *)val)->tag |= flag;
+ else ((yyjson_val *)val)->tag &= ~flag;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_float(void *val, float num) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_REAL, 0);
+ ((yyjson_val *)val)->tag |= (uint64_t)YYJSON_WRITE_FP_TO_FLOAT << 32;
+ ((yyjson_val *)val)->uni.f64 = (double)num;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_double(void *val, double num) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_REAL, 0);
+ ((yyjson_val *)val)->uni.f64 = num;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_real(void *val, double num) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_REAL, 0);
+ ((yyjson_val *)val)->uni.f64 = num;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_str_noesc(void *val, bool noesc) {
+ ((yyjson_val *)val)->tag &= ~(uint64_t)YYJSON_SUBTYPE_MASK;
+ if (noesc) ((yyjson_val *)val)->tag |= (uint64_t)YYJSON_SUBTYPE_NOESC;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_strn(void *val, const char *str,
+ size_t len) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_STR, YYJSON_SUBTYPE_NONE, len);
+ ((yyjson_val *)val)->uni.str = str;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_str(void *val, const char *str) {
+ size_t len = strlen(str);
+ bool noesc = unsafe_yyjson_is_str_noesc(str, len);
+ yyjson_subtype subtype = noesc ? YYJSON_SUBTYPE_NOESC : YYJSON_SUBTYPE_NONE;
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_STR, subtype, len);
+ ((yyjson_val *)val)->uni.str = str;
+}
+
+yyjson_api_inline void unsafe_yyjson_set_arr(void *val, size_t size) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_ARR, YYJSON_SUBTYPE_NONE, size);
+}
+
+yyjson_api_inline void unsafe_yyjson_set_obj(void *val, size_t size) {
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_OBJ, YYJSON_SUBTYPE_NONE, size);
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Document API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc) {
+ return doc ? doc->root : NULL;
+}
+
+yyjson_api_inline size_t yyjson_doc_get_read_size(yyjson_doc *doc) {
+ return doc ? doc->dat_read : 0;
+}
+
+yyjson_api_inline size_t yyjson_doc_get_val_count(yyjson_doc *doc) {
+ return doc ? doc->val_read : 0;
+}
+
+yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc) {
+ if (doc) {
+ yyjson_alc alc = doc->alc;
+ memset(&doc->alc, 0, sizeof(alc));
+ if (doc->str_pool) alc.free(alc.ctx, doc->str_pool);
+ alc.free(alc.ctx, doc);
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value Type API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_is_raw(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_raw(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_null(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_null(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_true(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_true(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_false(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_false(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_bool(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_bool(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_uint(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_uint(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_sint(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_sint(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_int(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_int(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_real(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_real(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_num(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_num(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_str(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_str(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_arr(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_arr(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_obj(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_obj(val) : false;
+}
+
+yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val) {
+ return val ? unsafe_yyjson_is_ctn(val) : false;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value Content API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val) {
+ return val ? unsafe_yyjson_get_type(val) : YYJSON_TYPE_NONE;
+}
+
+yyjson_api_inline yyjson_subtype yyjson_get_subtype(yyjson_val *val) {
+ return val ? unsafe_yyjson_get_subtype(val) : YYJSON_SUBTYPE_NONE;
+}
+
+yyjson_api_inline uint8_t yyjson_get_tag(yyjson_val *val) {
+ return val ? unsafe_yyjson_get_tag(val) : 0;
+}
+
+yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val) {
+ switch (yyjson_get_tag(val)) {
+ case YYJSON_TYPE_RAW | YYJSON_SUBTYPE_NONE: return "raw";
+ case YYJSON_TYPE_NULL | YYJSON_SUBTYPE_NONE: return "null";
+ case YYJSON_TYPE_STR | YYJSON_SUBTYPE_NONE: return "string";
+ case YYJSON_TYPE_STR | YYJSON_SUBTYPE_NOESC: return "string";
+ case YYJSON_TYPE_ARR | YYJSON_SUBTYPE_NONE: return "array";
+ case YYJSON_TYPE_OBJ | YYJSON_SUBTYPE_NONE: return "object";
+ case YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE: return "true";
+ case YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE: return "false";
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: return "uint";
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: return "sint";
+ case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: return "real";
+ default: return "unknown";
+ }
+}
+
+yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val) {
+ return yyjson_is_raw(val) ? unsafe_yyjson_get_raw(val) : NULL;
+}
+
+yyjson_api_inline bool yyjson_get_bool(yyjson_val *val) {
+ return yyjson_is_bool(val) ? unsafe_yyjson_get_bool(val) : false;
+}
+
+yyjson_api_inline uint64_t yyjson_get_uint(yyjson_val *val) {
+ return yyjson_is_int(val) ? unsafe_yyjson_get_uint(val) : 0;
+}
+
+yyjson_api_inline int64_t yyjson_get_sint(yyjson_val *val) {
+ return yyjson_is_int(val) ? unsafe_yyjson_get_sint(val) : 0;
+}
+
+yyjson_api_inline int yyjson_get_int(yyjson_val *val) {
+ return yyjson_is_int(val) ? unsafe_yyjson_get_int(val) : 0;
+}
+
+yyjson_api_inline double yyjson_get_real(yyjson_val *val) {
+ return yyjson_is_real(val) ? unsafe_yyjson_get_real(val) : 0.0;
+}
+
+yyjson_api_inline double yyjson_get_num(yyjson_val *val) {
+ return val ? unsafe_yyjson_get_num(val) : 0.0;
+}
+
+yyjson_api_inline const char *yyjson_get_str(yyjson_val *val) {
+ return yyjson_is_str(val) ? unsafe_yyjson_get_str(val) : NULL;
+}
+
+yyjson_api_inline size_t yyjson_get_len(yyjson_val *val) {
+ return val ? unsafe_yyjson_get_len(val) : 0;
+}
+
+yyjson_api_inline bool yyjson_equals_str(yyjson_val *val, const char *str) {
+ if (yyjson_likely(val && str)) {
+ return unsafe_yyjson_is_str(val) &&
+ unsafe_yyjson_equals_str(val, str);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_equals_strn(yyjson_val *val, const char *str,
+ size_t len) {
+ if (yyjson_likely(val && str)) {
+ return unsafe_yyjson_is_str(val) &&
+ unsafe_yyjson_equals_strn(val, str, len);
+ }
+ return false;
+}
+
+yyjson_api bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs);
+
+yyjson_api_inline bool yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) {
+ if (yyjson_unlikely(!lhs || !rhs)) return false;
+ return unsafe_yyjson_equals(lhs, rhs);
+}
+
+yyjson_api_inline bool yyjson_set_raw(yyjson_val *val,
+ const char *raw, size_t len) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_raw(val, raw, len);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_null(yyjson_val *val) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_null(val);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_bool(yyjson_val *val, bool num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_bool(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_uint(yyjson_val *val, uint64_t num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_uint(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_sint(yyjson_val *val, int64_t num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_sint(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_int(yyjson_val *val, int num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_sint(val, (int64_t)num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_float(yyjson_val *val, float num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_float(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_double(yyjson_val *val, double num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_double(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_real(yyjson_val *val, double num) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ unsafe_yyjson_set_real(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_fp_to_fixed(yyjson_val *val, int prec) {
+ if (yyjson_unlikely(!yyjson_is_real(val))) return false;
+ unsafe_yyjson_set_fp_to_fixed(val, prec);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_fp_to_float(yyjson_val *val, bool flt) {
+ if (yyjson_unlikely(!yyjson_is_real(val))) return false;
+ unsafe_yyjson_set_fp_to_float(val, flt);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_str(yyjson_val *val, const char *str) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ if (yyjson_unlikely(!str)) return false;
+ unsafe_yyjson_set_str(val, str);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_strn(yyjson_val *val,
+ const char *str, size_t len) {
+ if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false;
+ if (yyjson_unlikely(!str)) return false;
+ unsafe_yyjson_set_strn(val, str, len);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc) {
+ if (yyjson_unlikely(!yyjson_is_str(val))) return false;
+ unsafe_yyjson_set_str_noesc(val, noesc);
+ return true;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Array API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr) {
+ return yyjson_is_arr(arr) ? unsafe_yyjson_get_len(arr) : 0;
+}
+
+yyjson_api_inline yyjson_val *yyjson_arr_get(yyjson_val *arr, size_t idx) {
+ if (yyjson_likely(yyjson_is_arr(arr))) {
+ if (yyjson_likely(unsafe_yyjson_get_len(arr) > idx)) {
+ yyjson_val *val = unsafe_yyjson_get_first(arr);
+ if (unsafe_yyjson_arr_is_flat(arr)) {
+ return val + idx;
+ } else {
+ while (idx-- > 0) val = unsafe_yyjson_get_next(val);
+ return val;
+ }
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_val *yyjson_arr_get_first(yyjson_val *arr) {
+ if (yyjson_likely(yyjson_is_arr(arr))) {
+ if (yyjson_likely(unsafe_yyjson_get_len(arr) > 0)) {
+ return unsafe_yyjson_get_first(arr);
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr) {
+ if (yyjson_likely(yyjson_is_arr(arr))) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_likely(len > 0)) {
+ yyjson_val *val = unsafe_yyjson_get_first(arr);
+ if (unsafe_yyjson_arr_is_flat(arr)) {
+ return val + (len - 1);
+ } else {
+ while (len-- > 1) val = unsafe_yyjson_get_next(val);
+ return val;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Array Iterator API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr,
+ yyjson_arr_iter *iter) {
+ if (yyjson_likely(yyjson_is_arr(arr) && iter)) {
+ iter->idx = 0;
+ iter->max = unsafe_yyjson_get_len(arr);
+ iter->cur = unsafe_yyjson_get_first(arr);
+ return true;
+ }
+ if (iter) memset(iter, 0, sizeof(yyjson_arr_iter));
+ return false;
+}
+
+yyjson_api_inline yyjson_arr_iter yyjson_arr_iter_with(yyjson_val *arr) {
+ yyjson_arr_iter iter;
+ yyjson_arr_iter_init(arr, &iter);
+ return iter;
+}
+
+yyjson_api_inline bool yyjson_arr_iter_has_next(yyjson_arr_iter *iter) {
+ return iter ? iter->idx < iter->max : false;
+}
+
+yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter) {
+ yyjson_val *val;
+ if (iter && iter->idx < iter->max) {
+ val = iter->cur;
+ iter->cur = unsafe_yyjson_get_next(val);
+ iter->idx++;
+ return val;
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Object API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj) {
+ return yyjson_is_obj(obj) ? unsafe_yyjson_get_len(obj) : 0;
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_get(yyjson_val *obj,
+ const char *key) {
+ return yyjson_obj_getn(obj, key, key ? strlen(key) : 0);
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj,
+ const char *_key,
+ size_t key_len) {
+ if (yyjson_likely(yyjson_is_obj(obj) && _key)) {
+ size_t len = unsafe_yyjson_get_len(obj);
+ yyjson_val *key = unsafe_yyjson_get_first(obj);
+ while (len-- > 0) {
+ if (unsafe_yyjson_equals_strn(key, _key, key_len)) return key + 1;
+ key = unsafe_yyjson_get_next(key + 1);
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - JSON Object Iterator API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj,
+ yyjson_obj_iter *iter) {
+ if (yyjson_likely(yyjson_is_obj(obj) && iter)) {
+ iter->idx = 0;
+ iter->max = unsafe_yyjson_get_len(obj);
+ iter->cur = unsafe_yyjson_get_first(obj);
+ iter->obj = obj;
+ return true;
+ }
+ if (iter) memset(iter, 0, sizeof(yyjson_obj_iter));
+ return false;
+}
+
+yyjson_api_inline yyjson_obj_iter yyjson_obj_iter_with(yyjson_val *obj) {
+ yyjson_obj_iter iter;
+ yyjson_obj_iter_init(obj, &iter);
+ return iter;
+}
+
+yyjson_api_inline bool yyjson_obj_iter_has_next(yyjson_obj_iter *iter) {
+ return iter ? iter->idx < iter->max : false;
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_iter_next(yyjson_obj_iter *iter) {
+ if (iter && iter->idx < iter->max) {
+ yyjson_val *key = iter->cur;
+ iter->idx++;
+ iter->cur = unsafe_yyjson_get_next(key + 1);
+ return key;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_iter_get_val(yyjson_val *key) {
+ return key ? key + 1 : NULL;
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_iter_get(yyjson_obj_iter *iter,
+ const char *key) {
+ return yyjson_obj_iter_getn(iter, key, key ? strlen(key) : 0);
+}
+
+yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
+ const char *key,
+ size_t key_len) {
+ if (iter && key) {
+ size_t idx = iter->idx;
+ size_t max = iter->max;
+ yyjson_val *cur = iter->cur;
+ if (yyjson_unlikely(idx == max)) {
+ idx = 0;
+ cur = unsafe_yyjson_get_first(iter->obj);
+ }
+ while (idx++ < max) {
+ yyjson_val *next = unsafe_yyjson_get_next(cur + 1);
+ if (unsafe_yyjson_equals_strn(cur, key, key_len)) {
+ iter->idx = idx;
+ iter->cur = next;
+ return cur + 1;
+ }
+ cur = next;
+ if (idx == iter->max && iter->idx < iter->max) {
+ idx = 0;
+ max = iter->idx;
+ cur = unsafe_yyjson_get_first(iter->obj);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Structure (Implementation)
+ *============================================================================*/
+
+/**
+ Mutable JSON value, 24 bytes.
+ The 'tag' and 'uni' field is same as immutable value.
+ The 'next' field links all elements inside the container to be a cycle.
+ */
+struct yyjson_mut_val {
+ uint64_t tag; /**< type, subtype and length */
+ yyjson_val_uni uni; /**< payload */
+ yyjson_mut_val *next; /**< the next value in circular linked list */
+};
+
+/**
+ A memory chunk in string memory pool.
+ */
+typedef struct yyjson_str_chunk {
+ struct yyjson_str_chunk *next; /* next chunk linked list */
+ size_t chunk_size; /* chunk size in bytes */
+ /* char str[]; flexible array member */
+} yyjson_str_chunk;
+
+/**
+ A memory pool to hold all strings in a mutable document.
+ */
+typedef struct yyjson_str_pool {
+ char *cur; /* cursor inside current chunk */
+ char *end; /* the end of current chunk */
+ size_t chunk_size; /* chunk size in bytes while creating new chunk */
+ size_t chunk_size_max; /* maximum chunk size in bytes */
+ yyjson_str_chunk *chunks; /* a linked list of chunks, nullable */
+} yyjson_str_pool;
+
+/**
+ A memory chunk in value memory pool.
+ `sizeof(yyjson_val_chunk)` should not larger than `sizeof(yyjson_mut_val)`.
+ */
+typedef struct yyjson_val_chunk {
+ struct yyjson_val_chunk *next; /* next chunk linked list */
+ size_t chunk_size; /* chunk size in bytes */
+ /* char pad[sizeof(yyjson_mut_val) - sizeof(yyjson_val_chunk)]; padding */
+ /* yyjson_mut_val vals[]; flexible array member */
+} yyjson_val_chunk;
+
+/**
+ A memory pool to hold all values in a mutable document.
+ */
+typedef struct yyjson_val_pool {
+ yyjson_mut_val *cur; /* cursor inside current chunk */
+ yyjson_mut_val *end; /* the end of current chunk */
+ size_t chunk_size; /* chunk size in bytes while creating new chunk */
+ size_t chunk_size_max; /* maximum chunk size in bytes */
+ yyjson_val_chunk *chunks; /* a linked list of chunks, nullable */
+} yyjson_val_pool;
+
+struct yyjson_mut_doc {
+ yyjson_mut_val *root; /**< root value of the JSON document, nullable */
+ yyjson_alc alc; /**< a valid allocator, nonnull */
+ yyjson_str_pool str_pool; /**< string memory pool */
+ yyjson_val_pool val_pool; /**< value memory pool */
+};
+
+/* Ensures the capacity to at least equal to the specified byte length. */
+yyjson_api bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
+ const yyjson_alc *alc,
+ size_t len);
+
+/* Ensures the capacity to at least equal to the specified value count. */
+yyjson_api bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
+ const yyjson_alc *alc,
+ size_t count);
+
+/* Allocate memory for string. */
+yyjson_api_inline char *unsafe_yyjson_mut_str_alc(yyjson_mut_doc *doc,
+ size_t len) {
+ char *mem;
+ const yyjson_alc *alc = &doc->alc;
+ yyjson_str_pool *pool = &doc->str_pool;
+ if (yyjson_unlikely((size_t)(pool->end - pool->cur) <= len)) {
+ if (yyjson_unlikely(!unsafe_yyjson_str_pool_grow(pool, alc, len + 1))) {
+ return NULL;
+ }
+ }
+ mem = pool->cur;
+ pool->cur = mem + len + 1;
+ return mem;
+}
+
+yyjson_api_inline char *unsafe_yyjson_mut_strncpy(yyjson_mut_doc *doc,
+ const char *str, size_t len) {
+ char *mem = unsafe_yyjson_mut_str_alc(doc, len);
+ if (yyjson_unlikely(!mem)) return NULL;
+ memcpy((void *)mem, (const void *)str, len);
+ mem[len] = '\0';
+ return mem;
+}
+
+yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_val(yyjson_mut_doc *doc,
+ size_t count) {
+ yyjson_mut_val *val;
+ yyjson_alc *alc = &doc->alc;
+ yyjson_val_pool *pool = &doc->val_pool;
+ if (yyjson_unlikely((size_t)(pool->end - pool->cur) < count)) {
+ if (yyjson_unlikely(!unsafe_yyjson_val_pool_grow(pool, alc, count))) {
+ return NULL;
+ }
+ }
+ val = pool->cur;
+ pool->cur += count;
+ return val;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Document API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc) {
+ return doc ? doc->root : NULL;
+}
+
+yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc,
+ yyjson_mut_val *root) {
+ if (doc) doc->root = root;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Type API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_raw(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_null(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_null(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_true(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_true(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_false(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_false(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_bool(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_bool(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_uint(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_uint(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_sint(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_sint(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_int(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_int(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_real(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_real(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_num(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_num(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_str(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_str(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_arr(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_arr(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_obj(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_obj(val) : false;
+}
+
+yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val) {
+ return val ? unsafe_yyjson_is_ctn(val) : false;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Content API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val) {
+ return yyjson_get_type((yyjson_val *)val);
+}
+
+yyjson_api_inline yyjson_subtype yyjson_mut_get_subtype(yyjson_mut_val *val) {
+ return yyjson_get_subtype((yyjson_val *)val);
+}
+
+yyjson_api_inline uint8_t yyjson_mut_get_tag(yyjson_mut_val *val) {
+ return yyjson_get_tag((yyjson_val *)val);
+}
+
+yyjson_api_inline const char *yyjson_mut_get_type_desc(yyjson_mut_val *val) {
+ return yyjson_get_type_desc((yyjson_val *)val);
+}
+
+yyjson_api_inline const char *yyjson_mut_get_raw(yyjson_mut_val *val) {
+ return yyjson_get_raw((yyjson_val *)val);
+}
+
+yyjson_api_inline bool yyjson_mut_get_bool(yyjson_mut_val *val) {
+ return yyjson_get_bool((yyjson_val *)val);
+}
+
+yyjson_api_inline uint64_t yyjson_mut_get_uint(yyjson_mut_val *val) {
+ return yyjson_get_uint((yyjson_val *)val);
+}
+
+yyjson_api_inline int64_t yyjson_mut_get_sint(yyjson_mut_val *val) {
+ return yyjson_get_sint((yyjson_val *)val);
+}
+
+yyjson_api_inline int yyjson_mut_get_int(yyjson_mut_val *val) {
+ return yyjson_get_int((yyjson_val *)val);
+}
+
+yyjson_api_inline double yyjson_mut_get_real(yyjson_mut_val *val) {
+ return yyjson_get_real((yyjson_val *)val);
+}
+
+yyjson_api_inline double yyjson_mut_get_num(yyjson_mut_val *val) {
+ return yyjson_get_num((yyjson_val *)val);
+}
+
+yyjson_api_inline const char *yyjson_mut_get_str(yyjson_mut_val *val) {
+ return yyjson_get_str((yyjson_val *)val);
+}
+
+yyjson_api_inline size_t yyjson_mut_get_len(yyjson_mut_val *val) {
+ return yyjson_get_len((yyjson_val *)val);
+}
+
+yyjson_api_inline bool yyjson_mut_equals_str(yyjson_mut_val *val,
+ const char *str) {
+ return yyjson_equals_str((yyjson_val *)val, str);
+}
+
+yyjson_api_inline bool yyjson_mut_equals_strn(yyjson_mut_val *val,
+ const char *str, size_t len) {
+ return yyjson_equals_strn((yyjson_val *)val, str, len);
+}
+
+yyjson_api bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs,
+ yyjson_mut_val *rhs);
+
+yyjson_api_inline bool yyjson_mut_equals(yyjson_mut_val *lhs,
+ yyjson_mut_val *rhs) {
+ if (yyjson_unlikely(!lhs || !rhs)) return false;
+ return unsafe_yyjson_mut_equals(lhs, rhs);
+}
+
+yyjson_api_inline bool yyjson_mut_set_raw(yyjson_mut_val *val,
+ const char *raw, size_t len) {
+ if (yyjson_unlikely(!val || !raw)) return false;
+ unsafe_yyjson_set_raw(val, raw, len);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_null(yyjson_mut_val *val) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_null(val);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_bool(yyjson_mut_val *val, bool num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_bool(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_uint(yyjson_mut_val *val, uint64_t num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_uint(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_sint(yyjson_mut_val *val, int64_t num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_sint(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_int(yyjson_mut_val *val, int num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_sint(val, (int64_t)num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_float(yyjson_mut_val *val, float num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_float(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_double(yyjson_mut_val *val, double num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_double(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_real(yyjson_mut_val *val, double num) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_real(val, num);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_fp_to_fixed(yyjson_mut_val *val,
+ int prec) {
+ if (yyjson_unlikely(!yyjson_mut_is_real(val))) return false;
+ unsafe_yyjson_set_fp_to_fixed(val, prec);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_fp_to_float(yyjson_mut_val *val,
+ bool flt) {
+ if (yyjson_unlikely(!yyjson_mut_is_real(val))) return false;
+ unsafe_yyjson_set_fp_to_float(val, flt);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_str(yyjson_mut_val *val,
+ const char *str) {
+ if (yyjson_unlikely(!val || !str)) return false;
+ unsafe_yyjson_set_str(val, str);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_strn(yyjson_mut_val *val,
+ const char *str, size_t len) {
+ if (yyjson_unlikely(!val || !str)) return false;
+ unsafe_yyjson_set_strn(val, str, len);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_str_noesc(yyjson_mut_val *val,
+ bool noesc) {
+ if (yyjson_unlikely(!yyjson_mut_is_str(val))) return false;
+ unsafe_yyjson_set_str_noesc(val, noesc);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_arr(yyjson_mut_val *val) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_arr(val, 0);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val) {
+ if (yyjson_unlikely(!val)) return false;
+ unsafe_yyjson_set_obj(val, 0);
+ return true;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Value Creation API (Implementation)
+ *============================================================================*/
+
+#define yyjson_mut_val_one(func) \
+ if (yyjson_likely(doc)) { \
+ yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); \
+ if (yyjson_likely(val)) { \
+ func \
+ return val; \
+ } \
+ } \
+ return NULL
+
+#define yyjson_mut_val_one_str(func) \
+ if (yyjson_likely(doc && str)) { \
+ yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); \
+ if (yyjson_likely(val)) { \
+ func \
+ return val; \
+ } \
+ } \
+ return NULL
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_raw(yyjson_mut_doc *doc,
+ const char *str) {
+ yyjson_mut_val_one_str({ unsafe_yyjson_set_raw(val, str, strlen(str)); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawn(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len) {
+ yyjson_mut_val_one_str({ unsafe_yyjson_set_raw(val, str, len); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawcpy(yyjson_mut_doc *doc,
+ const char *str) {
+ yyjson_mut_val_one_str({
+ size_t len = strlen(str);
+ char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_raw(val, new_str, len);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_rawncpy(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len) {
+ yyjson_mut_val_one_str({
+ char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_raw(val, new_str, len);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_null(yyjson_mut_doc *doc) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_null(val); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_true(yyjson_mut_doc *doc) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_bool(val, true); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_false(yyjson_mut_doc *doc) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_bool(val, false); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_bool(yyjson_mut_doc *doc,
+ bool _val) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_bool(val, _val); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_uint(yyjson_mut_doc *doc,
+ uint64_t num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_uint(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_sint(yyjson_mut_doc *doc,
+ int64_t num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_sint(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_int(yyjson_mut_doc *doc,
+ int64_t num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_sint(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_float(yyjson_mut_doc *doc,
+ float num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_float(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_double(yyjson_mut_doc *doc,
+ double num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_double(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_real(yyjson_mut_doc *doc,
+ double num) {
+ yyjson_mut_val_one({ unsafe_yyjson_set_real(val, num); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_str(yyjson_mut_doc *doc,
+ const char *str) {
+ yyjson_mut_val_one_str({ unsafe_yyjson_set_str(val, str); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strn(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len) {
+ yyjson_mut_val_one_str({ unsafe_yyjson_set_strn(val, str, len); });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strcpy(yyjson_mut_doc *doc,
+ const char *str) {
+ yyjson_mut_val_one_str({
+ size_t len = strlen(str);
+ bool noesc = unsafe_yyjson_is_str_noesc(str, len);
+ yyjson_subtype sub = noesc ? YYJSON_SUBTYPE_NOESC : YYJSON_SUBTYPE_NONE;
+ char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_tag(val, YYJSON_TYPE_STR, sub, len);
+ val->uni.str = new_str;
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
+ const char *str,
+ size_t len) {
+ yyjson_mut_val_one_str({
+ char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_strn(val, new_str, len);
+ });
+}
+
+#undef yyjson_mut_val_one
+#undef yyjson_mut_val_one_str
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr) {
+ return yyjson_mut_is_arr(arr) ? unsafe_yyjson_get_len(arr) : 0;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get(yyjson_mut_val *arr,
+ size_t idx) {
+ if (yyjson_likely(idx < yyjson_mut_arr_size(arr))) {
+ yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr;
+ while (idx-- > 0) val = val->next;
+ return val->next;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_first(
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(yyjson_mut_arr_size(arr) > 0)) {
+ return ((yyjson_mut_val *)arr->uni.ptr)->next;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(yyjson_mut_arr_size(arr) > 0)) {
+ return ((yyjson_mut_val *)arr->uni.ptr);
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Iterator API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr,
+ yyjson_mut_arr_iter *iter) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) && iter)) {
+ iter->idx = 0;
+ iter->max = unsafe_yyjson_get_len(arr);
+ iter->cur = iter->max ? (yyjson_mut_val *)arr->uni.ptr : NULL;
+ iter->pre = NULL;
+ iter->arr = arr;
+ return true;
+ }
+ if (iter) memset(iter, 0, sizeof(yyjson_mut_arr_iter));
+ return false;
+}
+
+yyjson_api_inline yyjson_mut_arr_iter yyjson_mut_arr_iter_with(
+ yyjson_mut_val *arr) {
+ yyjson_mut_arr_iter iter;
+ yyjson_mut_arr_iter_init(arr, &iter);
+ return iter;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_iter_has_next(yyjson_mut_arr_iter *iter) {
+ return iter ? iter->idx < iter->max : false;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_next(
+ yyjson_mut_arr_iter *iter) {
+ if (iter && iter->idx < iter->max) {
+ yyjson_mut_val *val = iter->cur;
+ iter->pre = val;
+ iter->cur = val->next;
+ iter->idx++;
+ return iter->cur;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
+ yyjson_mut_arr_iter *iter) {
+ if (yyjson_likely(iter && 0 < iter->idx && iter->idx <= iter->max)) {
+ yyjson_mut_val *prev = iter->pre;
+ yyjson_mut_val *cur = iter->cur;
+ yyjson_mut_val *next = cur->next;
+ if (yyjson_unlikely(iter->idx == iter->max)) iter->arr->uni.ptr = prev;
+ iter->idx--;
+ iter->max--;
+ unsafe_yyjson_set_len(iter->arr, iter->max);
+ prev->next = next;
+ iter->cur = prev;
+ return cur;
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Creation API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc) {
+ if (yyjson_likely(doc)) {
+ yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1);
+ if (yyjson_likely(val)) {
+ val->tag = YYJSON_TYPE_ARR | YYJSON_SUBTYPE_NONE;
+ return val;
+ }
+ }
+ return NULL;
+}
+
+#define yyjson_mut_arr_with_func(func) \
+ if (yyjson_likely(doc && ((0 < count && count < \
+ (~(size_t)0) / sizeof(yyjson_mut_val) && vals) || count == 0))) { \
+ yyjson_mut_val *arr = unsafe_yyjson_mut_val(doc, 1 + count); \
+ if (yyjson_likely(arr)) { \
+ arr->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; \
+ if (count > 0) { \
+ size_t i; \
+ for (i = 0; i < count; i++) { \
+ yyjson_mut_val *val = arr + i + 1; \
+ func \
+ val->next = val + 1; \
+ } \
+ arr[count].next = arr + 1; \
+ arr->uni.ptr = arr + count; \
+ } \
+ return arr; \
+ } \
+ } \
+ return NULL
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_bool(
+ yyjson_mut_doc *doc, const bool *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_bool(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint(
+ yyjson_mut_doc *doc, const int64_t *vals, size_t count) {
+ return yyjson_mut_arr_with_sint64(doc, vals, count);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint(
+ yyjson_mut_doc *doc, const uint64_t *vals, size_t count) {
+ return yyjson_mut_arr_with_uint64(doc, vals, count);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_real(
+ yyjson_mut_doc *doc, const double *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_real(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint8(
+ yyjson_mut_doc *doc, const int8_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_sint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint16(
+ yyjson_mut_doc *doc, const int16_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_sint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint32(
+ yyjson_mut_doc *doc, const int32_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_sint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint64(
+ yyjson_mut_doc *doc, const int64_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_sint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint8(
+ yyjson_mut_doc *doc, const uint8_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_uint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint16(
+ yyjson_mut_doc *doc, const uint16_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_uint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint32(
+ yyjson_mut_doc *doc, const uint32_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_uint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint64(
+ yyjson_mut_doc *doc, const uint64_t *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_uint(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_float(
+ yyjson_mut_doc *doc, const float *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_float(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_double(
+ yyjson_mut_doc *doc, const double *vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ unsafe_yyjson_set_double(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_str(
+ yyjson_mut_doc *doc, const char **vals, size_t count) {
+ yyjson_mut_arr_with_func({
+ if (yyjson_unlikely(!vals[i])) return NULL;
+ unsafe_yyjson_set_str(val, vals[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strn(
+ yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count) {
+ if (yyjson_unlikely(count > 0 && !lens)) return NULL;
+ yyjson_mut_arr_with_func({
+ if (yyjson_unlikely(!vals[i])) return NULL;
+ unsafe_yyjson_set_strn(val, vals[i], lens[i]);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strcpy(
+ yyjson_mut_doc *doc, const char **vals, size_t count) {
+ size_t len;
+ const char *str, *new_str;
+ yyjson_mut_arr_with_func({
+ str = vals[i];
+ if (yyjson_unlikely(!str)) return NULL;
+ len = strlen(str);
+ new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_strn(val, new_str, len);
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
+ yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count) {
+ size_t len;
+ const char *str, *new_str;
+ if (yyjson_unlikely(count > 0 && !lens)) return NULL;
+ yyjson_mut_arr_with_func({
+ str = vals[i];
+ if (yyjson_unlikely(!str)) return NULL;
+ len = lens[i];
+ new_str = unsafe_yyjson_mut_strncpy(doc, str, len);
+ if (yyjson_unlikely(!new_str)) return NULL;
+ unsafe_yyjson_set_strn(val, new_str, len);
+ });
+}
+
+#undef yyjson_mut_arr_with_func
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Modification API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr,
+ yyjson_mut_val *val, size_t idx) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_likely(idx <= len)) {
+ unsafe_yyjson_set_len(arr, len + 1);
+ if (len == 0) {
+ val->next = val;
+ arr->uni.ptr = val;
+ } else {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ if (idx == len) {
+ prev->next = val;
+ val->next = next;
+ arr->uni.ptr = val;
+ } else {
+ while (idx-- > 0) {
+ prev = next;
+ next = next->next;
+ }
+ prev->next = val;
+ val->next = next;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_append(yyjson_mut_val *arr,
+ yyjson_mut_val *val) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ unsafe_yyjson_set_len(arr, len + 1);
+ if (len == 0) {
+ val->next = val;
+ } else {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ prev->next = val;
+ val->next = next;
+ }
+ arr->uni.ptr = val;
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_prepend(yyjson_mut_val *arr,
+ yyjson_mut_val *val) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ unsafe_yyjson_set_len(arr, len + 1);
+ if (len == 0) {
+ val->next = val;
+ arr->uni.ptr = val;
+ } else {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ prev->next = val;
+ val->next = next;
+ }
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_replace(yyjson_mut_val *arr,
+ size_t idx,
+ yyjson_mut_val *val) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_likely(idx < len)) {
+ if (yyjson_likely(len > 1)) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ while (idx-- > 0) {
+ prev = next;
+ next = next->next;
+ }
+ prev->next = val;
+ val->next = next->next;
+ if ((void *)next == arr->uni.ptr) arr->uni.ptr = val;
+ return next;
+ } else {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ val->next = val;
+ arr->uni.ptr = val;
+ return prev;
+ }
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove(yyjson_mut_val *arr,
+ size_t idx) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr))) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_likely(idx < len)) {
+ unsafe_yyjson_set_len(arr, len - 1);
+ if (yyjson_likely(len > 1)) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ while (idx-- > 0) {
+ prev = next;
+ next = next->next;
+ }
+ prev->next = next->next;
+ if ((void *)next == arr->uni.ptr) arr->uni.ptr = prev;
+ return next;
+ } else {
+ return ((yyjson_mut_val *)arr->uni.ptr);
+ }
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_first(
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr))) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (len > 1) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ prev->next = next->next;
+ unsafe_yyjson_set_len(arr, len - 1);
+ return next;
+ } else if (len == 1) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ unsafe_yyjson_set_len(arr, 0);
+ return prev;
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_last(
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr))) {
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_likely(len > 1)) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ yyjson_mut_val *next = prev->next;
+ unsafe_yyjson_set_len(arr, len - 1);
+ while (--len > 0) prev = prev->next;
+ prev->next = next;
+ next = (yyjson_mut_val *)arr->uni.ptr;
+ arr->uni.ptr = prev;
+ return next;
+ } else if (len == 1) {
+ yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr);
+ unsafe_yyjson_set_len(arr, 0);
+ return prev;
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_remove_range(yyjson_mut_val *arr,
+ size_t _idx, size_t _len) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *prev, *next;
+ bool tail_removed;
+ size_t len = unsafe_yyjson_get_len(arr);
+ if (yyjson_unlikely(_idx + _len > len)) return false;
+ if (yyjson_unlikely(_len == 0)) return true;
+ unsafe_yyjson_set_len(arr, len - _len);
+ if (yyjson_unlikely(len == _len)) return true;
+ tail_removed = (_idx + _len == len);
+ prev = ((yyjson_mut_val *)arr->uni.ptr);
+ while (_idx-- > 0) prev = prev->next;
+ next = prev->next;
+ while (_len-- > 0) next = next->next;
+ prev->next = next;
+ if (yyjson_unlikely(tail_removed)) arr->uni.ptr = prev;
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_clear(yyjson_mut_val *arr) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr))) {
+ unsafe_yyjson_set_len(arr, 0);
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
+ size_t idx) {
+ if (yyjson_likely(yyjson_mut_is_arr(arr) &&
+ unsafe_yyjson_get_len(arr) > idx)) {
+ yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr;
+ while (idx-- > 0) val = val->next;
+ arr->uni.ptr = (void *)val;
+ return true;
+ }
+ return false;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Array Modification Convenience API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr,
+ yyjson_mut_val *val) {
+ return yyjson_mut_arr_append(arr, val);
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_null(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_null(doc);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_true(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_true(doc);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_false(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_false(doc);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_bool(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ bool _val) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_bool(doc, _val);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_uint(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ uint64_t num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_uint(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_sint(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ int64_t num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_sint(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_int(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ int64_t num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_sint(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_float(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ float num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_float(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_double(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ double num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_double(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_real(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ double num) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_real(doc, num);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_str(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_str(doc, str);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_strn(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str, size_t len) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_strn(doc, str, len);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_strcpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_strcpy(doc, str);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_arr_add_strncpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr,
+ const char *str, size_t len) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_strncpy(doc, str, len);
+ return yyjson_mut_arr_append(arr, val);
+ }
+ return false;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_arr(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_arr(doc);
+ return yyjson_mut_arr_append(arr, val) ? val : NULL;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
+ yyjson_mut_val *arr) {
+ if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) {
+ yyjson_mut_val *val = yyjson_mut_obj(doc);
+ return yyjson_mut_arr_append(arr, val) ? val : NULL;
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj) {
+ return yyjson_mut_is_obj(obj) ? unsafe_yyjson_get_len(obj) : 0;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_get(yyjson_mut_val *obj,
+ const char *key) {
+ return yyjson_mut_obj_getn(obj, key, key ? strlen(key) : 0);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
+ const char *_key,
+ size_t key_len) {
+ size_t len = yyjson_mut_obj_size(obj);
+ if (yyjson_likely(len && _key)) {
+ yyjson_mut_val *key = ((yyjson_mut_val *)obj->uni.ptr)->next->next;
+ while (len-- > 0) {
+ if (unsafe_yyjson_equals_strn(key, _key, key_len)) return key->next;
+ key = key->next->next;
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Iterator API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj,
+ yyjson_mut_obj_iter *iter) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) && iter)) {
+ iter->idx = 0;
+ iter->max = unsafe_yyjson_get_len(obj);
+ iter->cur = iter->max ? (yyjson_mut_val *)obj->uni.ptr : NULL;
+ iter->pre = NULL;
+ iter->obj = obj;
+ return true;
+ }
+ if (iter) memset(iter, 0, sizeof(yyjson_mut_obj_iter));
+ return false;
+}
+
+yyjson_api_inline yyjson_mut_obj_iter yyjson_mut_obj_iter_with(
+ yyjson_mut_val *obj) {
+ yyjson_mut_obj_iter iter;
+ yyjson_mut_obj_iter_init(obj, &iter);
+ return iter;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_iter_has_next(yyjson_mut_obj_iter *iter) {
+ return iter ? iter->idx < iter->max : false;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_next(
+ yyjson_mut_obj_iter *iter) {
+ if (iter && iter->idx < iter->max) {
+ yyjson_mut_val *key = iter->cur;
+ iter->pre = key;
+ iter->cur = key->next->next;
+ iter->idx++;
+ return iter->cur;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get_val(
+ yyjson_mut_val *key) {
+ return key ? key->next : NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_remove(
+ yyjson_mut_obj_iter *iter) {
+ if (yyjson_likely(iter && 0 < iter->idx && iter->idx <= iter->max)) {
+ yyjson_mut_val *prev = iter->pre;
+ yyjson_mut_val *cur = iter->cur;
+ yyjson_mut_val *next = cur->next->next;
+ if (yyjson_unlikely(iter->idx == iter->max)) iter->obj->uni.ptr = prev;
+ iter->idx--;
+ iter->max--;
+ unsafe_yyjson_set_len(iter->obj, iter->max);
+ prev->next->next = next;
+ iter->cur = prev;
+ return cur->next;
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get(
+ yyjson_mut_obj_iter *iter, const char *key) {
+ return yyjson_mut_obj_iter_getn(iter, key, key ? strlen(key) : 0);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
+ yyjson_mut_obj_iter *iter, const char *key, size_t key_len) {
+ if (iter && key) {
+ size_t idx = 0;
+ size_t max = iter->max;
+ yyjson_mut_val *pre, *cur = iter->cur;
+ while (idx++ < max) {
+ pre = cur;
+ cur = cur->next->next;
+ if (unsafe_yyjson_equals_strn(cur, key, key_len)) {
+ iter->idx += idx;
+ if (iter->idx > max) iter->idx -= max + 1;
+ iter->pre = pre;
+ iter->cur = cur;
+ return cur->next;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Creation API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc) {
+ if (yyjson_likely(doc)) {
+ yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1);
+ if (yyjson_likely(val)) {
+ val->tag = YYJSON_TYPE_OBJ | YYJSON_SUBTYPE_NONE;
+ return val;
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_str(yyjson_mut_doc *doc,
+ const char **keys,
+ const char **vals,
+ size_t count) {
+ if (yyjson_likely(doc && ((count > 0 && keys && vals) || (count == 0)))) {
+ yyjson_mut_val *obj = unsafe_yyjson_mut_val(doc, 1 + count * 2);
+ if (yyjson_likely(obj)) {
+ obj->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_OBJ;
+ if (count > 0) {
+ size_t i;
+ for (i = 0; i < count; i++) {
+ yyjson_mut_val *key = obj + (i * 2 + 1);
+ yyjson_mut_val *val = obj + (i * 2 + 2);
+ uint64_t key_len = (uint64_t)strlen(keys[i]);
+ uint64_t val_len = (uint64_t)strlen(vals[i]);
+ key->tag = (key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ val->tag = (val_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ key->uni.str = keys[i];
+ val->uni.str = vals[i];
+ key->next = val;
+ val->next = val + 1;
+ }
+ obj[count * 2].next = obj + 1;
+ obj->uni.ptr = obj + (count * 2 - 1);
+ }
+ return obj;
+ }
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
+ const char **pairs,
+ size_t count) {
+ if (yyjson_likely(doc && ((count > 0 && pairs) || (count == 0)))) {
+ yyjson_mut_val *obj = unsafe_yyjson_mut_val(doc, 1 + count * 2);
+ if (yyjson_likely(obj)) {
+ obj->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_OBJ;
+ if (count > 0) {
+ size_t i;
+ for (i = 0; i < count; i++) {
+ yyjson_mut_val *key = obj + (i * 2 + 1);
+ yyjson_mut_val *val = obj + (i * 2 + 2);
+ const char *key_str = pairs[i * 2 + 0];
+ const char *val_str = pairs[i * 2 + 1];
+ uint64_t key_len = (uint64_t)strlen(key_str);
+ uint64_t val_len = (uint64_t)strlen(val_str);
+ key->tag = (key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ val->tag = (val_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ key->uni.str = key_str;
+ val->uni.str = val_str;
+ key->next = val;
+ val->next = val + 1;
+ }
+ obj[count * 2].next = obj + 1;
+ obj->uni.ptr = obj + (count * 2 - 1);
+ }
+ return obj;
+ }
+ }
+ return NULL;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Modification API (Implementation)
+ *============================================================================*/
+
+yyjson_api_inline void unsafe_yyjson_mut_obj_add(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val,
+ size_t len) {
+ if (yyjson_likely(len)) {
+ yyjson_mut_val *prev_val = ((yyjson_mut_val *)obj->uni.ptr)->next;
+ yyjson_mut_val *next_key = prev_val->next;
+ prev_val->next = key;
+ val->next = next_key;
+ } else {
+ val->next = key;
+ }
+ key->next = val;
+ obj->uni.ptr = (void *)key;
+ unsafe_yyjson_set_len(obj, len + 1);
+}
+
+yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_obj_remove(
+ yyjson_mut_val *obj, const char *key, size_t key_len) {
+ size_t obj_len = unsafe_yyjson_get_len(obj);
+ if (obj_len) {
+ yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr;
+ yyjson_mut_val *cur_key = pre_key->next->next;
+ yyjson_mut_val *removed_item = NULL;
+ size_t i;
+ for (i = 0; i < obj_len; i++) {
+ if (unsafe_yyjson_equals_strn(cur_key, key, key_len)) {
+ if (!removed_item) removed_item = cur_key->next;
+ cur_key = cur_key->next->next;
+ pre_key->next->next = cur_key;
+ if (i + 1 == obj_len) obj->uni.ptr = pre_key;
+ i--;
+ obj_len--;
+ } else {
+ pre_key = cur_key;
+ cur_key = cur_key->next->next;
+ }
+ }
+ unsafe_yyjson_set_len(obj, obj_len);
+ return removed_item;
+ } else {
+ return NULL;
+ }
+}
+
+yyjson_api_inline bool unsafe_yyjson_mut_obj_replace(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val) {
+ size_t key_len = unsafe_yyjson_get_len(key);
+ size_t obj_len = unsafe_yyjson_get_len(obj);
+ if (obj_len) {
+ yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr;
+ yyjson_mut_val *cur_key = pre_key->next->next;
+ size_t i;
+ for (i = 0; i < obj_len; i++) {
+ if (unsafe_yyjson_equals_strn(cur_key, key->uni.str, key_len)) {
+ cur_key->next->tag = val->tag;
+ cur_key->next->uni.u64 = val->uni.u64;
+ return true;
+ } else {
+ cur_key = cur_key->next->next;
+ }
+ }
+ }
+ return false;
+}
+
+yyjson_api_inline void unsafe_yyjson_mut_obj_rotate(yyjson_mut_val *obj,
+ size_t idx) {
+ yyjson_mut_val *key = (yyjson_mut_val *)obj->uni.ptr;
+ while (idx-- > 0) key = key->next->next;
+ obj->uni.ptr = (void *)key;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) &&
+ yyjson_mut_is_str(key) && val)) {
+ unsafe_yyjson_mut_obj_add(obj, key, val, unsafe_yyjson_get_len(obj));
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_put(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val) {
+ bool replaced = false;
+ size_t key_len;
+ yyjson_mut_obj_iter iter;
+ yyjson_mut_val *cur_key;
+ if (yyjson_unlikely(!yyjson_mut_is_obj(obj) ||
+ !yyjson_mut_is_str(key))) return false;
+ key_len = unsafe_yyjson_get_len(key);
+ yyjson_mut_obj_iter_init(obj, &iter);
+ while ((cur_key = yyjson_mut_obj_iter_next(&iter)) != 0) {
+ if (unsafe_yyjson_equals_strn(cur_key, key->uni.str, key_len)) {
+ if (!replaced && val) {
+ replaced = true;
+ val->next = cur_key->next->next;
+ cur_key->next = val;
+ } else {
+ yyjson_mut_obj_iter_remove(&iter);
+ }
+ }
+ }
+ if (!replaced && val) unsafe_yyjson_mut_obj_add(obj, key, val, iter.max);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_insert(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val,
+ size_t idx) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) &&
+ yyjson_mut_is_str(key) && val)) {
+ size_t len = unsafe_yyjson_get_len(obj);
+ if (yyjson_likely(len >= idx)) {
+ if (len > idx) {
+ void *ptr = obj->uni.ptr;
+ unsafe_yyjson_mut_obj_rotate(obj, idx);
+ unsafe_yyjson_mut_obj_add(obj, key, val, len);
+ obj->uni.ptr = ptr;
+ } else {
+ unsafe_yyjson_mut_obj_add(obj, key, val, len);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove(yyjson_mut_val *obj,
+ yyjson_mut_val *key) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) && yyjson_mut_is_str(key))) {
+ return unsafe_yyjson_mut_obj_remove(obj, key->uni.str,
+ unsafe_yyjson_get_len(key));
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_key(
+ yyjson_mut_val *obj, const char *key) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) && key)) {
+ size_t key_len = strlen(key);
+ return unsafe_yyjson_mut_obj_remove(obj, key, key_len);
+ }
+ return NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_keyn(
+ yyjson_mut_val *obj, const char *key, size_t key_len) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) && key)) {
+ return unsafe_yyjson_mut_obj_remove(obj, key, key_len);
+ }
+ return NULL;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_clear(yyjson_mut_val *obj) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj))) {
+ unsafe_yyjson_set_len(obj, 0);
+ return true;
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_replace(yyjson_mut_val *obj,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) &&
+ yyjson_mut_is_str(key) && val)) {
+ return unsafe_yyjson_mut_obj_replace(obj, key, val);
+ }
+ return false;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
+ size_t idx) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) &&
+ unsafe_yyjson_get_len(obj) > idx)) {
+ unsafe_yyjson_mut_obj_rotate(obj, idx);
+ return true;
+ }
+ return false;
+}
+
+
+
+/*==============================================================================
+ * MARK: - Mutable JSON Object Modification Convenience API (Implementation)
+ *============================================================================*/
+
+#define yyjson_mut_obj_add_func(func) \
+ if (yyjson_likely(doc && yyjson_mut_is_obj(obj) && _key)) { \
+ yyjson_mut_val *key = unsafe_yyjson_mut_val(doc, 2); \
+ if (yyjson_likely(key)) { \
+ size_t len = unsafe_yyjson_get_len(obj); \
+ yyjson_mut_val *val = key + 1; \
+ size_t key_len = strlen(_key); \
+ bool noesc = unsafe_yyjson_is_str_noesc(_key, key_len); \
+ key->tag = YYJSON_TYPE_STR; \
+ key->tag |= noesc ? YYJSON_SUBTYPE_NOESC : YYJSON_SUBTYPE_NONE; \
+ key->tag |= (uint64_t)strlen(_key) << YYJSON_TAG_BIT; \
+ key->uni.str = _key; \
+ func \
+ unsafe_yyjson_mut_obj_add(obj, key, val, len); \
+ return true; \
+ } \
+ } \
+ return false
+
+yyjson_api_inline bool yyjson_mut_obj_add_null(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_null(val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_true(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_bool(val, true); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_false(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_bool(val, false); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_bool(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ bool _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_bool(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_uint(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ uint64_t _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_uint(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_sint(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ int64_t _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_sint(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_int(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ int64_t _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_sint(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_float(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ float _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_float(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_double(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ double _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_double(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_real(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ double _val) {
+ yyjson_mut_obj_add_func({ unsafe_yyjson_set_real(val, _val); });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_str(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ const char *_val) {
+ if (yyjson_unlikely(!_val)) return false;
+ yyjson_mut_obj_add_func({
+ size_t val_len = strlen(_val);
+ bool val_noesc = unsafe_yyjson_is_str_noesc(_val, val_len);
+ val->tag = ((uint64_t)strlen(_val) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ val->tag |= val_noesc ? YYJSON_SUBTYPE_NOESC : YYJSON_SUBTYPE_NONE;
+ val->uni.str = _val;
+ });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_strn(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ const char *_val,
+ size_t _len) {
+ if (yyjson_unlikely(!_val)) return false;
+ yyjson_mut_obj_add_func({
+ val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ val->uni.str = _val;
+ });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_strcpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ const char *_val) {
+ if (yyjson_unlikely(!_val)) return false;
+ yyjson_mut_obj_add_func({
+ size_t _len = strlen(_val);
+ val->uni.str = unsafe_yyjson_mut_strncpy(doc, _val, _len);
+ if (yyjson_unlikely(!val->uni.str)) return false;
+ val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ });
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_strncpy(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ const char *_val,
+ size_t _len) {
+ if (yyjson_unlikely(!_val)) return false;
+ yyjson_mut_obj_add_func({
+ val->uni.str = unsafe_yyjson_mut_strncpy(doc, _val, _len);
+ if (yyjson_unlikely(!val->uni.str)) return false;
+ val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_add_arr(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key) {
+ yyjson_mut_val *key = yyjson_mut_str(doc, _key);
+ yyjson_mut_val *val = yyjson_mut_arr(doc);
+ return yyjson_mut_obj_add(obj, key, val) ? val : NULL;
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_add_obj(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key) {
+ yyjson_mut_val *key = yyjson_mut_str(doc, _key);
+ yyjson_mut_val *val = yyjson_mut_obj(doc);
+ return yyjson_mut_obj_add(obj, key, val) ? val : NULL;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_add_val(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *_key,
+ yyjson_mut_val *_val) {
+ if (yyjson_unlikely(!_val)) return false;
+ yyjson_mut_obj_add_func({
+ val = _val;
+ });
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_str(yyjson_mut_val *obj,
+ const char *key) {
+ return yyjson_mut_obj_remove_strn(obj, key, key ? strlen(key) : 0);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_strn(
+ yyjson_mut_val *obj, const char *_key, size_t _len) {
+ if (yyjson_likely(yyjson_mut_is_obj(obj) && _key)) {
+ yyjson_mut_val *key;
+ yyjson_mut_obj_iter iter;
+ yyjson_mut_val *val_removed = NULL;
+ yyjson_mut_obj_iter_init(obj, &iter);
+ while ((key = yyjson_mut_obj_iter_next(&iter)) != NULL) {
+ if (unsafe_yyjson_equals_strn(key, _key, _len)) {
+ if (!val_removed) val_removed = key->next;
+ yyjson_mut_obj_iter_remove(&iter);
+ }
+ }
+ return val_removed;
+ }
+ return NULL;
+}
+
+yyjson_api_inline bool yyjson_mut_obj_rename_key(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ const char *new_key) {
+ if (!key || !new_key) return false;
+ return yyjson_mut_obj_rename_keyn(doc, obj, key, strlen(key),
+ new_key, strlen(new_key));
+}
+
+yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
+ yyjson_mut_val *obj,
+ const char *key,
+ size_t len,
+ const char *new_key,
+ size_t new_len) {
+ char *cpy_key = NULL;
+ yyjson_mut_val *old_key;
+ yyjson_mut_obj_iter iter;
+ if (!doc || !obj || !key || !new_key) return false;
+ yyjson_mut_obj_iter_init(obj, &iter);
+ while ((old_key = yyjson_mut_obj_iter_next(&iter))) {
+ if (unsafe_yyjson_equals_strn((void *)old_key, key, len)) {
+ if (!cpy_key) {
+ cpy_key = unsafe_yyjson_mut_strncpy(doc, new_key, new_len);
+ if (!cpy_key) return false;
+ }
+ yyjson_mut_set_strn(old_key, cpy_key, new_len);
+ }
+ }
+ return cpy_key != NULL;
+}
+
+
+
+#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
+
+/*==============================================================================
+ * MARK: - JSON Pointer API (Implementation)
+ *============================================================================*/
+
+#define yyjson_ptr_set_err(_code, _msg) do { \
+ if (err) { \
+ err->code = YYJSON_PTR_ERR_##_code; \
+ err->msg = _msg; \
+ err->pos = 0; \
+ } \
+} while(false)
+
+/* require: val != NULL, *ptr == '/', len > 0 */
+yyjson_api yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val,
+ const char *ptr, size_t len,
+ yyjson_ptr_err *err);
+
+/* require: val != NULL, *ptr == '/', len > 0 */
+yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/* require: val/new_val/doc != NULL, *ptr == '/', len > 0 */
+yyjson_api bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc,
+ bool create_parent, bool insert_new,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+/* require: val/err != NULL, *ptr == '/', len > 0 */
+yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err);
+
+/* require: val/err != NULL, *ptr == '/', len > 0 */
+yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err);
+
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_get(yyjson_doc *doc,
+ const char *ptr) {
+ if (yyjson_unlikely(!ptr)) return NULL;
+ return yyjson_doc_ptr_getn(doc, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_getn(yyjson_doc *doc,
+ const char *ptr, size_t len) {
+ return yyjson_doc_ptr_getx(doc, ptr, len, NULL);
+}
+
+yyjson_api_inline yyjson_val *yyjson_doc_ptr_getx(yyjson_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (yyjson_unlikely(!doc || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ return doc->root;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_ptr_getx(doc->root, ptr, len, err);
+}
+
+yyjson_api_inline yyjson_val *yyjson_ptr_get(yyjson_val *val,
+ const char *ptr) {
+ if (yyjson_unlikely(!ptr)) return NULL;
+ return yyjson_ptr_getn(val, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_val *yyjson_ptr_getn(yyjson_val *val,
+ const char *ptr, size_t len) {
+ return yyjson_ptr_getx(val, ptr, len, NULL);
+}
+
+yyjson_api_inline yyjson_val *yyjson_ptr_getx(yyjson_val *val,
+ const char *ptr, size_t len,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (yyjson_unlikely(!val || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ return val;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_ptr_getx(val, ptr, len, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_get(yyjson_mut_doc *doc,
+ const char *ptr) {
+ if (!ptr) return NULL;
+ return yyjson_mut_doc_ptr_getn(doc, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getn(yyjson_mut_doc *doc,
+ const char *ptr,
+ size_t len) {
+ return yyjson_mut_doc_ptr_getx(doc, ptr, len, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getx(yyjson_mut_doc *doc,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!doc || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ return doc->root;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_getx(doc->root, ptr, len, ctx, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_get(yyjson_mut_val *val,
+ const char *ptr) {
+ if (!ptr) return NULL;
+ return yyjson_mut_ptr_getn(val, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getn(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len) {
+ return yyjson_mut_ptr_getx(val, ptr, len, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getx(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!val || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ return val;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_add(yyjson_mut_doc *doc,
+ const char *ptr,
+ yyjson_mut_val *new_val) {
+ if (yyjson_unlikely(!ptr)) return false;
+ return yyjson_mut_doc_ptr_addn(doc, ptr, strlen(ptr), new_val);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_addn(yyjson_mut_doc *doc,
+ const char *ptr,
+ size_t len,
+ yyjson_mut_val *new_val) {
+ return yyjson_mut_doc_ptr_addx(doc, ptr, len, new_val, true, NULL, NULL);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_addx(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!doc || !ptr || !new_val)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ if (doc->root) {
+ yyjson_ptr_set_err(SET_ROOT, "cannot set document's root");
+ return false;
+ } else {
+ doc->root = new_val;
+ return true;
+ }
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return false;
+ }
+ if (yyjson_unlikely(!doc->root && !create_parent)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_mut_val *root = yyjson_mut_obj(doc);
+ if (yyjson_unlikely(!root)) {
+ yyjson_ptr_set_err(MEMORY_ALLOCATION, "failed to create value");
+ return false;
+ }
+ if (unsafe_yyjson_mut_ptr_putx(root, ptr, len, new_val, doc,
+ create_parent, true, ctx, err)) {
+ doc->root = root;
+ return true;
+ }
+ return false;
+ }
+ return unsafe_yyjson_mut_ptr_putx(doc->root, ptr, len, new_val, doc,
+ create_parent, true, ctx, err);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_add(yyjson_mut_val *val,
+ const char *ptr,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc) {
+ if (yyjson_unlikely(!ptr)) return false;
+ return yyjson_mut_ptr_addn(val, ptr, strlen(ptr), new_val, doc);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_addn(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc) {
+ return yyjson_mut_ptr_addx(val, ptr, len, new_val, doc, true, NULL, NULL);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_addx(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!val || !ptr || !new_val || !doc)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_ptr_set_err(SET_ROOT, "cannot set root");
+ return false;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return false;
+ }
+ return unsafe_yyjson_mut_ptr_putx(val, ptr, len, new_val,
+ doc, create_parent, true, ctx, err);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_set(yyjson_mut_doc *doc,
+ const char *ptr,
+ yyjson_mut_val *new_val) {
+ if (yyjson_unlikely(!ptr)) return false;
+ return yyjson_mut_doc_ptr_setn(doc, ptr, strlen(ptr), new_val);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_setn(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val) {
+ return yyjson_mut_doc_ptr_setx(doc, ptr, len, new_val, true, NULL, NULL);
+}
+
+yyjson_api_inline bool yyjson_mut_doc_ptr_setx(yyjson_mut_doc *doc,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!doc || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ if (ctx) ctx->old = doc->root;
+ doc->root = new_val;
+ return true;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return false;
+ }
+ if (!new_val) {
+ if (!doc->root) {
+ yyjson_ptr_set_err(RESOLVE, "JSON pointer cannot be resolved");
+ return false;
+ }
+ return !!unsafe_yyjson_mut_ptr_removex(doc->root, ptr, len, ctx, err);
+ }
+ if (yyjson_unlikely(!doc->root && !create_parent)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_mut_val *root = yyjson_mut_obj(doc);
+ if (yyjson_unlikely(!root)) {
+ yyjson_ptr_set_err(MEMORY_ALLOCATION, "failed to create value");
+ return false;
+ }
+ if (unsafe_yyjson_mut_ptr_putx(root, ptr, len, new_val, doc,
+ create_parent, false, ctx, err)) {
+ doc->root = root;
+ return true;
+ }
+ return false;
+ }
+ return unsafe_yyjson_mut_ptr_putx(doc->root, ptr, len, new_val, doc,
+ create_parent, false, ctx, err);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_set(yyjson_mut_val *val,
+ const char *ptr,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc) {
+ if (yyjson_unlikely(!ptr)) return false;
+ return yyjson_mut_ptr_setn(val, ptr, strlen(ptr), new_val, doc);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_setn(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc) {
+ return yyjson_mut_ptr_setx(val, ptr, len, new_val, doc, true, NULL, NULL);
+}
+
+yyjson_api_inline bool yyjson_mut_ptr_setx(yyjson_mut_val *val,
+ const char *ptr, size_t len,
+ yyjson_mut_val *new_val,
+ yyjson_mut_doc *doc,
+ bool create_parent,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!val || !ptr || !doc)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return false;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_ptr_set_err(SET_ROOT, "cannot set root");
+ return false;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return false;
+ }
+ if (!new_val) {
+ return !!unsafe_yyjson_mut_ptr_removex(val, ptr, len, ctx, err);
+ }
+ return unsafe_yyjson_mut_ptr_putx(val, ptr, len, new_val, doc,
+ create_parent, false, ctx, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replace(
+ yyjson_mut_doc *doc, const char *ptr, yyjson_mut_val *new_val) {
+ if (!ptr) return NULL;
+ return yyjson_mut_doc_ptr_replacen(doc, ptr, strlen(ptr), new_val);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacen(
+ yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val) {
+ return yyjson_mut_doc_ptr_replacex(doc, ptr, len, new_val, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacex(
+ yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!doc || !ptr || !new_val)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_mut_val *root = doc->root;
+ if (yyjson_unlikely(!root)) {
+ yyjson_ptr_set_err(RESOLVE, "JSON pointer cannot be resolved");
+ return NULL;
+ }
+ if (ctx) ctx->old = root;
+ doc->root = new_val;
+ return root;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_replacex(doc->root, ptr, len, new_val,
+ ctx, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replace(
+ yyjson_mut_val *val, const char *ptr, yyjson_mut_val *new_val) {
+ if (!ptr) return NULL;
+ return yyjson_mut_ptr_replacen(val, ptr, strlen(ptr), new_val);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacen(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val) {
+ return yyjson_mut_ptr_replacex(val, ptr, len, new_val, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacex(
+ yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!val || !ptr || !new_val)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_ptr_set_err(SET_ROOT, "cannot set root");
+ return NULL;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_replacex(val, ptr, len, new_val, ctx, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_remove(
+ yyjson_mut_doc *doc, const char *ptr) {
+ if (!ptr) return NULL;
+ return yyjson_mut_doc_ptr_removen(doc, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removen(
+ yyjson_mut_doc *doc, const char *ptr, size_t len) {
+ return yyjson_mut_doc_ptr_removex(doc, ptr, len, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removex(
+ yyjson_mut_doc *doc, const char *ptr, size_t len,
+ yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
+
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!doc || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(!doc->root)) {
+ yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_mut_val *root = doc->root;
+ if (ctx) ctx->old = root;
+ doc->root = NULL;
+ return root;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_removex(doc->root, ptr, len, ctx, err);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_remove(yyjson_mut_val *val,
+ const char *ptr) {
+ if (!ptr) return NULL;
+ return yyjson_mut_ptr_removen(val, ptr, strlen(ptr));
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removen(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len) {
+ return yyjson_mut_ptr_removex(val, ptr, len, NULL, NULL);
+}
+
+yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removex(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len,
+ yyjson_ptr_ctx *ctx,
+ yyjson_ptr_err *err) {
+ yyjson_ptr_set_err(NONE, NULL);
+ if (ctx) memset(ctx, 0, sizeof(*ctx));
+
+ if (yyjson_unlikely(!val || !ptr)) {
+ yyjson_ptr_set_err(PARAMETER, "input parameter is NULL");
+ return NULL;
+ }
+ if (yyjson_unlikely(len == 0)) {
+ yyjson_ptr_set_err(SET_ROOT, "cannot set root");
+ return NULL;
+ }
+ if (yyjson_unlikely(*ptr != '/')) {
+ yyjson_ptr_set_err(SYNTAX, "no prefix '/'");
+ return NULL;
+ }
+ return unsafe_yyjson_mut_ptr_removex(val, ptr, len, ctx, err);
+}
+
+yyjson_api_inline bool yyjson_ptr_ctx_append(yyjson_ptr_ctx *ctx,
+ yyjson_mut_val *key,
+ yyjson_mut_val *val) {
+ yyjson_mut_val *ctn, *pre_key, *pre_val, *cur_key, *cur_val;
+ if (!ctx || !ctx->ctn || !val) return false;
+ ctn = ctx->ctn;
+
+ if (yyjson_mut_is_obj(ctn)) {
+ if (!key) return false;
+ key->next = val;
+ pre_key = ctx->pre;
+ if (unsafe_yyjson_get_len(ctn) == 0) {
+ val->next = key;
+ ctn->uni.ptr = key;
+ ctx->pre = key;
+ } else if (!pre_key) {
+ pre_key = (yyjson_mut_val *)ctn->uni.ptr;
+ pre_val = pre_key->next;
+ val->next = pre_val->next;
+ pre_val->next = key;
+ ctn->uni.ptr = key;
+ ctx->pre = pre_key;
+ } else {
+ cur_key = pre_key->next->next;
+ cur_val = cur_key->next;
+ val->next = cur_val->next;
+ cur_val->next = key;
+ if (ctn->uni.ptr == cur_key) ctn->uni.ptr = key;
+ ctx->pre = cur_key;
+ }
+ } else {
+ pre_val = ctx->pre;
+ if (unsafe_yyjson_get_len(ctn) == 0) {
+ val->next = val;
+ ctn->uni.ptr = val;
+ ctx->pre = val;
+ } else if (!pre_val) {
+ pre_val = (yyjson_mut_val *)ctn->uni.ptr;
+ val->next = pre_val->next;
+ pre_val->next = val;
+ ctn->uni.ptr = val;
+ ctx->pre = pre_val;
+ } else {
+ cur_val = pre_val->next;
+ val->next = cur_val->next;
+ cur_val->next = val;
+ if (ctn->uni.ptr == cur_val) ctn->uni.ptr = val;
+ ctx->pre = cur_val;
+ }
+ }
+ unsafe_yyjson_inc_len(ctn);
+ return true;
+}
+
+yyjson_api_inline bool yyjson_ptr_ctx_replace(yyjson_ptr_ctx *ctx,
+ yyjson_mut_val *val) {
+ yyjson_mut_val *ctn, *pre_key, *cur_key, *pre_val, *cur_val;
+ if (!ctx || !ctx->ctn || !ctx->pre || !val) return false;
+ ctn = ctx->ctn;
+ if (yyjson_mut_is_obj(ctn)) {
+ pre_key = ctx->pre;
+ pre_val = pre_key->next;
+ cur_key = pre_val->next;
+ cur_val = cur_key->next;
+ /* replace current value */
+ cur_key->next = val;
+ val->next = cur_val->next;
+ ctx->old = cur_val;
+ } else {
+ pre_val = ctx->pre;
+ cur_val = pre_val->next;
+ /* replace current value */
+ if (pre_val != cur_val) {
+ val->next = cur_val->next;
+ pre_val->next = val;
+ if (ctn->uni.ptr == cur_val) ctn->uni.ptr = val;
+ } else {
+ val->next = val;
+ ctn->uni.ptr = val;
+ ctx->pre = val;
+ }
+ ctx->old = cur_val;
+ }
+ return true;
+}
+
+yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx) {
+ yyjson_mut_val *ctn, *pre_key, *pre_val, *cur_key, *cur_val;
+ size_t len;
+ if (!ctx || !ctx->ctn || !ctx->pre) return false;
+ ctn = ctx->ctn;
+ if (yyjson_mut_is_obj(ctn)) {
+ pre_key = ctx->pre;
+ pre_val = pre_key->next;
+ cur_key = pre_val->next;
+ cur_val = cur_key->next;
+ /* remove current key-value */
+ pre_val->next = cur_val->next;
+ if (ctn->uni.ptr == cur_key) ctn->uni.ptr = pre_key;
+ ctx->pre = NULL;
+ ctx->old = cur_val;
+ } else {
+ pre_val = ctx->pre;
+ cur_val = pre_val->next;
+ /* remove current key-value */
+ pre_val->next = cur_val->next;
+ if (ctn->uni.ptr == cur_val) ctn->uni.ptr = pre_val;
+ ctx->pre = NULL;
+ ctx->old = cur_val;
+ }
+ len = unsafe_yyjson_get_len(ctn) - 1;
+ if (len == 0) ctn->uni.ptr = NULL;
+ unsafe_yyjson_set_len(ctn, len);
+ return true;
+}
+
+#undef yyjson_ptr_set_err
+
+
+
+/*==============================================================================
+ * MARK: - JSON Value at Pointer API (Implementation)
+ *============================================================================*/
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is type bool.
+ Returns true if value at `ptr` exists and is the correct type, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_bool(
+ yyjson_val *root, const char *ptr, bool *value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && yyjson_is_bool(val)) {
+ *value = unsafe_yyjson_get_bool(val);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is an integer
+ that fits in `uint64_t`. Returns true if successful, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_uint(
+ yyjson_val *root, const char *ptr, uint64_t *value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && val) {
+ uint64_t ret = val->uni.u64;
+ if (unsafe_yyjson_is_uint(val) ||
+ (unsafe_yyjson_is_sint(val) && !(ret >> 63))) {
+ *value = ret;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is an integer
+ that fits in `int64_t`. Returns true if successful, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_sint(
+ yyjson_val *root, const char *ptr, int64_t *value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && val) {
+ int64_t ret = val->uni.i64;
+ if (unsafe_yyjson_is_sint(val) ||
+ (unsafe_yyjson_is_uint(val) && ret >= 0)) {
+ *value = ret;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is type real.
+ Returns true if value at `ptr` exists and is the correct type, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_real(
+ yyjson_val *root, const char *ptr, double *value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && yyjson_is_real(val)) {
+ *value = unsafe_yyjson_get_real(val);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is type sint,
+ uint or real.
+ Returns true if value at `ptr` exists and is the correct type, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_num(
+ yyjson_val *root, const char *ptr, double *value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && yyjson_is_num(val)) {
+ *value = unsafe_yyjson_get_num(val);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ Set provided `value` if the JSON Pointer (RFC 6901) exists and is type string.
+ Returns true if value at `ptr` exists and is the correct type, otherwise false.
+ */
+yyjson_api_inline bool yyjson_ptr_get_str(
+ yyjson_val *root, const char *ptr, const char **value) {
+ yyjson_val *val = yyjson_ptr_get(root, ptr);
+ if (value && yyjson_is_str(val)) {
+ *value = unsafe_yyjson_get_str(val);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+/*==============================================================================
+ * MARK: - Deprecated
+ *============================================================================*/
+
+/** @deprecated renamed to `yyjson_doc_ptr_get` */
+yyjson_deprecated("renamed to yyjson_doc_ptr_get")
+yyjson_api_inline yyjson_val *yyjson_doc_get_pointer(yyjson_doc *doc,
+ const char *ptr) {
+ return yyjson_doc_ptr_get(doc, ptr);
+}
+
+/** @deprecated renamed to `yyjson_doc_ptr_getn` */
+yyjson_deprecated("renamed to yyjson_doc_ptr_getn")
+yyjson_api_inline yyjson_val *yyjson_doc_get_pointern(yyjson_doc *doc,
+ const char *ptr,
+ size_t len) {
+ return yyjson_doc_ptr_getn(doc, ptr, len);
+}
+
+/** @deprecated renamed to `yyjson_mut_doc_ptr_get` */
+yyjson_deprecated("renamed to yyjson_mut_doc_ptr_get")
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_pointer(
+ yyjson_mut_doc *doc, const char *ptr) {
+ return yyjson_mut_doc_ptr_get(doc, ptr);
+}
+
+/** @deprecated renamed to `yyjson_mut_doc_ptr_getn` */
+yyjson_deprecated("renamed to yyjson_mut_doc_ptr_getn")
+yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_pointern(
+ yyjson_mut_doc *doc, const char *ptr, size_t len) {
+ return yyjson_mut_doc_ptr_getn(doc, ptr, len);
+}
+
+/** @deprecated renamed to `yyjson_ptr_get` */
+yyjson_deprecated("renamed to yyjson_ptr_get")
+yyjson_api_inline yyjson_val *yyjson_get_pointer(yyjson_val *val,
+ const char *ptr) {
+ return yyjson_ptr_get(val, ptr);
+}
+
+/** @deprecated renamed to `yyjson_ptr_getn` */
+yyjson_deprecated("renamed to yyjson_ptr_getn")
+yyjson_api_inline yyjson_val *yyjson_get_pointern(yyjson_val *val,
+ const char *ptr,
+ size_t len) {
+ return yyjson_ptr_getn(val, ptr, len);
+}
+
+/** @deprecated renamed to `yyjson_mut_ptr_get` */
+yyjson_deprecated("renamed to yyjson_mut_ptr_get")
+yyjson_api_inline yyjson_mut_val *yyjson_mut_get_pointer(yyjson_mut_val *val,
+ const char *ptr) {
+ return yyjson_mut_ptr_get(val, ptr);
+}
+
+/** @deprecated renamed to `yyjson_mut_ptr_getn` */
+yyjson_deprecated("renamed to yyjson_mut_ptr_getn")
+yyjson_api_inline yyjson_mut_val *yyjson_mut_get_pointern(yyjson_mut_val *val,
+ const char *ptr,
+ size_t len) {
+ return yyjson_mut_ptr_getn(val, ptr, len);
+}
+
+/** @deprecated renamed to `yyjson_mut_ptr_getn` */
+yyjson_deprecated("renamed to unsafe_yyjson_ptr_getn")
+yyjson_api_inline yyjson_val *unsafe_yyjson_get_pointer(yyjson_val *val,
+ const char *ptr,
+ size_t len) {
+ yyjson_ptr_err err;
+ return unsafe_yyjson_ptr_getx(val, ptr, len, &err);
+}
+
+/** @deprecated renamed to `unsafe_yyjson_mut_ptr_getx` */
+yyjson_deprecated("renamed to unsafe_yyjson_mut_ptr_getx")
+yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_get_pointer(
+ yyjson_mut_val *val, const char *ptr, size_t len) {
+ yyjson_ptr_err err;
+ return unsafe_yyjson_mut_ptr_getx(val, ptr, len, NULL, &err);
+}
+
+#endif /* YYJSON_DISABLE_UTILS */
+
+
+
+/*==============================================================================
+ * MARK: - Compiler Hint End
+ *============================================================================*/
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__)
+# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# pragma GCC diagnostic pop
+# endif
+#elif defined(_MSC_VER)
+# pragma warning(pop)
+#endif /* warning suppress end */
+
+#ifdef __cplusplus
+}
+#endif /* extern "C" end */
+
+#endif /* YYJSON_H */
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/summary.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/summary.json
new file mode 100644
index 0000000..908043b
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/summary.json
@@ -0,0 +1,4006 @@
+[
+ {
+ "case": "metadata_heavy",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1208192,
+ "min": 1208192,
+ "max": 1208192
+ },
+ "source_peak_bytes": {
+ "median": 1059888,
+ "min": 1059888,
+ "max": 1059888
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 2785280,
+ "min": 2768896,
+ "max": 2801664
+ },
+ "elapsed_ns": {
+ "median": 66395496,
+ "min": 66302663,
+ "max": 66397387
+ },
+ "cpu_ns": {
+ "median": 14840713,
+ "min": 14680433,
+ "max": 14949295
+ },
+ "parse_call_ns": {
+ "median": 10710339,
+ "min": 10679603,
+ "max": 10748920
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 67622.063537,
+ "min": 67603.216745,
+ "max": 67632.156584
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26533.881,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5055556.934,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8039215.434,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1209200,
+ "min": 1209200,
+ "max": 1209200
+ },
+ "source_peak_bytes": {
+ "median": 1059888,
+ "min": 1059888,
+ "max": 1059888
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 2916352,
+ "min": 2899968,
+ "max": 2932736
+ },
+ "elapsed_ns": {
+ "median": 66425702,
+ "min": 66346982,
+ "max": 66647996
+ },
+ "cpu_ns": {
+ "median": 15174956,
+ "min": 15115580,
+ "max": 15645769
+ },
+ "parse_call_ns": {
+ "median": 10767457,
+ "min": 10730381,
+ "max": 10897093
+ },
+ "selection_copy_bytes": {
+ "median": 28672,
+ "min": 28672,
+ "max": 28672
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 42524.965388,
+ "min": 42518.234312,
+ "max": 42539.689103
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 512,
+ "min": 512,
+ "max": 512
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26833.023,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5056115.033,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8039588.77,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 187312,
+ "min": 187312,
+ "max": 187312
+ },
+ "source_peak_bytes": {
+ "median": 24672,
+ "min": 24672,
+ "max": 24672
+ },
+ "output_peak_bytes": {
+ "median": 14896,
+ "min": 14896,
+ "max": 14896
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 1835008,
+ "min": 1818624,
+ "max": 1835008
+ },
+ "elapsed_ns": {
+ "median": 66358054,
+ "min": 66338315,
+ "max": 66437867
+ },
+ "cpu_ns": {
+ "median": 14754424,
+ "min": 14688841,
+ "max": 14887131
+ },
+ "parse_call_ns": {
+ "median": 10588699,
+ "min": 10558757,
+ "max": 10719986
+ },
+ "selection_copy_bytes": {
+ "median": 319488,
+ "min": 319488,
+ "max": 319488
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 190.767691,
+ "min": 190.237303,
+ "max": 192.97609
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26285.051,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5055200.059,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8039957.693,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 170672,
+ "min": 170672,
+ "max": 170672
+ },
+ "source_peak_bytes": {
+ "median": 24672,
+ "min": 24672,
+ "max": 24672
+ },
+ "output_peak_bytes": {
+ "median": 14896,
+ "min": 14896,
+ "max": 14896
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 1835008,
+ "min": 1835008,
+ "max": 1851392
+ },
+ "elapsed_ns": {
+ "median": 66421906,
+ "min": 66367572,
+ "max": 69246534
+ },
+ "cpu_ns": {
+ "median": 14937944,
+ "min": 14844612,
+ "max": 16610834
+ },
+ "parse_call_ns": {
+ "median": 10714630,
+ "min": 10626817,
+ "max": 11758115
+ },
+ "selection_copy_bytes": {
+ "median": 319488,
+ "min": 319488,
+ "max": 319488
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 193.34471,
+ "min": 191.787957,
+ "max": 215.365911
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26630.812,
+ "latency_p99_upper_ns": 40960
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5055539.021,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8039399.533,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 180144,
+ "min": 180144,
+ "max": 180144
+ },
+ "source_peak_bytes": {
+ "median": 24672,
+ "min": 24672,
+ "max": 24672
+ },
+ "output_peak_bytes": {
+ "median": 7728,
+ "min": 7728,
+ "max": 7728
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 1835008,
+ "min": 1835008,
+ "max": 1835008
+ },
+ "elapsed_ns": {
+ "median": 66509552,
+ "min": 66340017,
+ "max": 67338922
+ },
+ "cpu_ns": {
+ "median": 14641398,
+ "min": 14565611,
+ "max": 15543047
+ },
+ "parse_call_ns": {
+ "median": 10583202,
+ "min": 10558947,
+ "max": 10965512
+ },
+ "selection_copy_bytes": {
+ "median": 290816,
+ "min": 290816,
+ "max": 290816
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 189.850967,
+ "min": 189.196651,
+ "max": 198.833427
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 512,
+ "min": 512,
+ "max": 512
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26126.43,
+ "latency_p99_upper_ns": 32768
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5054896.006,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8039936.652,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 180144,
+ "min": 180144,
+ "max": 180144
+ },
+ "source_peak_bytes": {
+ "median": 24672,
+ "min": 24672,
+ "max": 24672
+ },
+ "output_peak_bytes": {
+ "median": 7728,
+ "min": 7728,
+ "max": 7728
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 1835008,
+ "min": 1835008,
+ "max": 1851392
+ },
+ "elapsed_ns": {
+ "median": 66354498,
+ "min": 66341459,
+ "max": 66675868
+ },
+ "cpu_ns": {
+ "median": 14610428,
+ "min": 14573003,
+ "max": 15617313
+ },
+ "parse_call_ns": {
+ "median": 10568715,
+ "min": 10552983,
+ "max": 10794500
+ },
+ "selection_copy_bytes": {
+ "median": 290816,
+ "min": 290816,
+ "max": 290816
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 189.501318,
+ "min": 189.19959,
+ "max": 196.368374
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 512,
+ "min": 512,
+ "max": 512
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26103.785,
+ "latency_p99_upper_ns": 30720
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5054791.455,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8037890.609,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "metadata_heavy",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 180144,
+ "min": 180144,
+ "max": 180144
+ },
+ "source_peak_bytes": {
+ "median": 24672,
+ "min": 24672,
+ "max": 24672
+ },
+ "output_peak_bytes": {
+ "median": 7728,
+ "min": 7728,
+ "max": 7728
+ },
+ "parser_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "rss_peak_bytes": {
+ "median": 1835008,
+ "min": 1835008,
+ "max": 1851392
+ },
+ "elapsed_ns": {
+ "median": 66346091,
+ "min": 66342183,
+ "max": 66620533
+ },
+ "cpu_ns": {
+ "median": 14678765,
+ "min": 14624958,
+ "max": 15009658
+ },
+ "parse_call_ns": {
+ "median": 10599246,
+ "min": 10558072,
+ "max": 10663838
+ },
+ "selection_copy_bytes": {
+ "median": 290816,
+ "min": 290816,
+ "max": 290816
+ },
+ "reader_copy_bytes": {
+ "median": 6312628,
+ "min": 6312628,
+ "max": 6312628
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 14086144,
+ "min": 14086144,
+ "max": 14086144
+ },
+ "source_byte_seconds": {
+ "median": 190.199351,
+ "min": 189.596919,
+ "max": 191.566293
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 512,
+ "min": 512,
+ "max": 512
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 26178.92,
+ "latency_p99_upper_ns": 36864
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5054797.43,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8038718.686,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2097024,
+ "min": 2097024,
+ "max": 2097072
+ },
+ "source_peak_bytes": {
+ "median": 2047296,
+ "min": 2047296,
+ "max": 2047296
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 3719168,
+ "min": 3702784,
+ "max": 3719168
+ },
+ "elapsed_ns": {
+ "median": 516876187,
+ "min": 516415971,
+ "max": 519737827
+ },
+ "cpu_ns": {
+ "median": 58189132,
+ "min": 56956626,
+ "max": 63401151
+ },
+ "parse_call_ns": {
+ "median": 413462854,
+ "min": 410873515,
+ "max": 414175159
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 866155.703795,
+ "min": 865936.173669,
+ "max": 869390.688093
+ },
+ "budget_waits": {
+ "median": 1258,
+ "min": 1250,
+ "max": 1267
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 496219.126,
+ "latency_p99_upper_ns": 7864320
+ },
+ {
+ "peak_count": 30,
+ "latency_mean_ns": 5528237.536,
+ "latency_p99_upper_ns": 12582912
+ },
+ {
+ "peak_count": 30,
+ "latency_mean_ns": 8542682.03,
+ "latency_p99_upper_ns": 15728640
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2096656,
+ "min": 2095936,
+ "max": 2097104
+ },
+ "source_peak_bytes": {
+ "median": 2047296,
+ "min": 2047296,
+ "max": 2047296
+ },
+ "output_peak_bytes": {
+ "median": 3360,
+ "min": 3360,
+ "max": 3360
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 3719168,
+ "min": 3702784,
+ "max": 3833856
+ },
+ "elapsed_ns": {
+ "median": 330507221,
+ "min": 330325402,
+ "max": 332809762
+ },
+ "cpu_ns": {
+ "median": 57227425,
+ "min": 56526552,
+ "max": 64506702
+ },
+ "parse_call_ns": {
+ "median": 257390641,
+ "min": 255295188,
+ "max": 258042238
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 542286.835871,
+ "min": 542057.64214,
+ "max": 544031.993873
+ },
+ "budget_waits": {
+ "median": 1246,
+ "min": 1227,
+ "max": 1262
+ },
+ "compacted": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 314160.033,
+ "latency_p99_upper_ns": 4718592
+ },
+ {
+ "peak_count": 30,
+ "latency_mean_ns": 5361784.028,
+ "latency_p99_upper_ns": 10485760
+ },
+ {
+ "peak_count": 49,
+ "latency_mean_ns": 8345801.06,
+ "latency_p99_upper_ns": 12582912
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1104848,
+ "min": 1104736,
+ "max": 1104848
+ },
+ "source_peak_bytes": {
+ "median": 393312,
+ "min": 393312,
+ "max": 393312
+ },
+ "output_peak_bytes": {
+ "median": 79920,
+ "min": 79920,
+ "max": 79920
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 1884160,
+ "min": 1884160,
+ "max": 1900544
+ },
+ "elapsed_ns": {
+ "median": 134798098,
+ "min": 134667407,
+ "max": 135397301
+ },
+ "cpu_ns": {
+ "median": 52545277,
+ "min": 52218674,
+ "max": 55535720
+ },
+ "parse_call_ns": {
+ "median": 26282225,
+ "min": 26241260,
+ "max": 28191073
+ },
+ "selection_copy_bytes": {
+ "median": 26872064,
+ "min": 26872064,
+ "max": 26872064
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 6883.203763,
+ "min": 6810.984162,
+ "max": 7296.683374
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 47583.467,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5082343.96,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8083520.998,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 842368,
+ "min": 842368,
+ "max": 842368
+ },
+ "source_peak_bytes": {
+ "median": 393312,
+ "min": 393312,
+ "max": 393312
+ },
+ "output_peak_bytes": {
+ "median": 79920,
+ "min": 79920,
+ "max": 79920
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 1933312,
+ "min": 1916928,
+ "max": 1949696
+ },
+ "elapsed_ns": {
+ "median": 135708499,
+ "min": 135580728,
+ "max": 135818181
+ },
+ "cpu_ns": {
+ "median": 59498427,
+ "min": 59055276,
+ "max": 61310764
+ },
+ "parse_call_ns": {
+ "median": 27370335,
+ "min": 27293452,
+ "max": 27699522
+ },
+ "selection_copy_bytes": {
+ "median": 26872064,
+ "min": 26872064,
+ "max": 26872064
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 8320.069469,
+ "min": 8268.860241,
+ "max": 8492.13471
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 54118.737,
+ "latency_p99_upper_ns": 180224
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5093193.132,
+ "latency_p99_upper_ns": 5767168
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8094306.969,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1097792,
+ "min": 1097792,
+ "max": 1097792
+ },
+ "source_peak_bytes": {
+ "median": 393312,
+ "min": 393312,
+ "max": 393312
+ },
+ "output_peak_bytes": {
+ "median": 72752,
+ "min": 72752,
+ "max": 72752
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 1884160,
+ "min": 1884160,
+ "max": 1900544
+ },
+ "elapsed_ns": {
+ "median": 134698503,
+ "min": 134660107,
+ "max": 134733970
+ },
+ "cpu_ns": {
+ "median": 52085095,
+ "min": 51849496,
+ "max": 52189389
+ },
+ "parse_call_ns": {
+ "median": 26235438,
+ "min": 26215409,
+ "max": 26273407
+ },
+ "selection_copy_bytes": {
+ "median": 26814720,
+ "min": 26814720,
+ "max": 26814720
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 6831.305534,
+ "min": 6785.330268,
+ "max": 6865.482399
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 47354.551,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5081713.058,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8082113.784,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1097792,
+ "min": 1097792,
+ "max": 1097792
+ },
+ "source_peak_bytes": {
+ "median": 393312,
+ "min": 393312,
+ "max": 393312
+ },
+ "output_peak_bytes": {
+ "median": 72752,
+ "min": 72752,
+ "max": 72752
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 1884160,
+ "min": 1867776,
+ "max": 1900544
+ },
+ "elapsed_ns": {
+ "median": 134646087,
+ "min": 134596389,
+ "max": 134805557
+ },
+ "cpu_ns": {
+ "median": 51969989,
+ "min": 51772899,
+ "max": 52099602
+ },
+ "parse_call_ns": {
+ "median": 26207832,
+ "min": 26192074,
+ "max": 26303805
+ },
+ "selection_copy_bytes": {
+ "median": 26814720,
+ "min": 26814720,
+ "max": 26814720
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 6812.54134,
+ "min": 6795.293198,
+ "max": 6823.249522
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 47208.702,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5082291.09,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8082717.212,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "mixed_tight",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 1097792,
+ "min": 1097792,
+ "max": 1097792
+ },
+ "source_peak_bytes": {
+ "median": 393312,
+ "min": 393312,
+ "max": 393312
+ },
+ "output_peak_bytes": {
+ "median": 11312,
+ "min": 11312,
+ "max": 11312
+ },
+ "parser_peak_bytes": {
+ "median": 524336,
+ "min": 524336,
+ "max": 524336
+ },
+ "rss_peak_bytes": {
+ "median": 2048000,
+ "min": 2031616,
+ "max": 2064384
+ },
+ "elapsed_ns": {
+ "median": 134627181,
+ "min": 134514858,
+ "max": 135143135
+ },
+ "cpu_ns": {
+ "median": 51051158,
+ "min": 50901202,
+ "max": 54181725
+ },
+ "parse_call_ns": {
+ "median": 26232175,
+ "min": 26138215,
+ "max": 28073539
+ },
+ "selection_copy_bytes": {
+ "median": 1059072,
+ "min": 1059072,
+ "max": 1059072
+ },
+ "reader_copy_bytes": {
+ "median": 114814580,
+ "min": 114814580,
+ "max": 114814580
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 7499.787736,
+ "min": 7468.893211,
+ "max": 7971.142415
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 46365.068,
+ "latency_p99_upper_ns": 147456
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5080938.783,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8081990.295,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4427696,
+ "min": 4427696,
+ "max": 4427696
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5537792,
+ "min": 5521408,
+ "max": 5554176
+ },
+ "elapsed_ns": {
+ "median": 132124751,
+ "min": 131976979,
+ "max": 132469040
+ },
+ "cpu_ns": {
+ "median": 38591495,
+ "min": 37612015,
+ "max": 41862764
+ },
+ "parse_call_ns": {
+ "median": 22573964,
+ "min": 22444229,
+ "max": 22964342
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 540860.949553,
+ "min": 540831.163899,
+ "max": 541099.43903
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8058679.423,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4427696,
+ "min": 4427696,
+ "max": 4427696
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5537792,
+ "min": 5537792,
+ "max": 5554176
+ },
+ "elapsed_ns": {
+ "median": 132110379,
+ "min": 131996119,
+ "max": 132186905
+ },
+ "cpu_ns": {
+ "median": 38257181,
+ "min": 38004572,
+ "max": 38709650
+ },
+ "parse_call_ns": {
+ "median": 22486562,
+ "min": 22434299,
+ "max": 22557256
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 540815.06589,
+ "min": 540791.270719,
+ "max": 540907.798619
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8057936.641,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 303072,
+ "min": 303072,
+ "max": 303072
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1818624,
+ "min": 1818624,
+ "max": 1818624
+ },
+ "elapsed_ns": {
+ "median": 131689453,
+ "min": 131600270,
+ "max": 131752053
+ },
+ "cpu_ns": {
+ "median": 34877739,
+ "min": 34455850,
+ "max": 35243759
+ },
+ "parse_call_ns": {
+ "median": 21993246,
+ "min": 21964978,
+ "max": 22030534
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1845.194241,
+ "min": 1832.537919,
+ "max": 1857.757504
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8053071.22,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 237296,
+ "min": 237296,
+ "max": 237296
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1818624,
+ "min": 1802240,
+ "max": 1835008
+ },
+ "elapsed_ns": {
+ "median": 132246841,
+ "min": 132199048,
+ "max": 137450461
+ },
+ "cpu_ns": {
+ "median": 42202499,
+ "min": 41767998,
+ "max": 46306762
+ },
+ "parse_call_ns": {
+ "median": 24805054,
+ "min": 24673720,
+ "max": 25720817
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2084.967873,
+ "min": 2066.312998,
+ "max": 2217.245474
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8059680.607,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 303072,
+ "min": 303072,
+ "max": 303072
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1818624,
+ "min": 1802240,
+ "max": 1835008
+ },
+ "elapsed_ns": {
+ "median": 132103712,
+ "min": 131708165,
+ "max": 134003964
+ },
+ "cpu_ns": {
+ "median": 35248408,
+ "min": 34456703,
+ "max": 37157688
+ },
+ "parse_call_ns": {
+ "median": 22044118,
+ "min": 21940218,
+ "max": 22141327
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1858.44117,
+ "min": 1833.007769,
+ "max": 1917.711679
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8054276.953,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 303072,
+ "min": 303072,
+ "max": 303072
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1818624,
+ "min": 1802240,
+ "max": 1835008
+ },
+ "elapsed_ns": {
+ "median": 132093280,
+ "min": 131703634,
+ "max": 132588310
+ },
+ "cpu_ns": {
+ "median": 36810738,
+ "min": 34747849,
+ "max": 37673671
+ },
+ "parse_call_ns": {
+ "median": 22338927,
+ "min": 21989760,
+ "max": 22518430
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1914.610493,
+ "min": 1842.615404,
+ "max": 1949.11739
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8054865.09,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "one_slow",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 303072,
+ "min": 303072,
+ "max": 303072
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1818624,
+ "min": 1802240,
+ "max": 1818624
+ },
+ "elapsed_ns": {
+ "median": 131798127,
+ "min": 131620844,
+ "max": 131976855
+ },
+ "cpu_ns": {
+ "median": 34803856,
+ "min": 34446035,
+ "max": 36997295
+ },
+ "parse_call_ns": {
+ "median": 22050963,
+ "min": 21905479,
+ "max": 22094634
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1846.36305,
+ "min": 1832.609103,
+ "max": 1904.528214
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8054286.008,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4435888,
+ "min": 4435888,
+ "max": 4435888
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 4767744,
+ "min": 4767744,
+ "max": 4767744
+ },
+ "elapsed_ns": {
+ "median": 133814643,
+ "min": 133553215,
+ "max": 134337593
+ },
+ "cpu_ns": {
+ "median": 68888479,
+ "min": 68534602,
+ "max": 71105404
+ },
+ "parse_call_ns": {
+ "median": 22344284,
+ "min": 22264001,
+ "max": 22575073
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 541341.207084,
+ "min": 541236.958782,
+ "max": 541448.462493
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 52115.836,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5078986.712,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8067041.718,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4730672,
+ "min": 4730672,
+ "max": 4730672
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 2001776,
+ "min": 1936144,
+ "max": 2034592
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 6340608,
+ "min": 6340608,
+ "max": 6340608
+ },
+ "elapsed_ns": {
+ "median": 134204038,
+ "min": 134074359,
+ "max": 135831514
+ },
+ "cpu_ns": {
+ "median": 74886880,
+ "min": 74679639,
+ "max": 84355786
+ },
+ "parse_call_ns": {
+ "median": 22736073,
+ "min": 22714288,
+ "max": 23107923
+ },
+ "selection_copy_bytes": {
+ "median": 33554432,
+ "min": 33554432,
+ "max": 33554432
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 341191.973388,
+ "min": 341111.908821,
+ "max": 341580.411374
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 54208.683,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5084673.227,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8069796.873,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4504544,
+ "min": 4504544,
+ "max": 4504544
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 4233264,
+ "min": 4233264,
+ "max": 4233264
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5292032,
+ "min": 5275648,
+ "max": 5292032
+ },
+ "elapsed_ns": {
+ "median": 134436483,
+ "min": 134254523,
+ "max": 139508137
+ },
+ "cpu_ns": {
+ "median": 76196602,
+ "min": 74842901,
+ "max": 88332555
+ },
+ "parse_call_ns": {
+ "median": 22285338,
+ "min": 22151327,
+ "max": 22864596
+ },
+ "selection_copy_bytes": {
+ "median": 100663296,
+ "min": 100663296,
+ "max": 100663296
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2295.795833,
+ "min": 2277.11069,
+ "max": 2528.253394
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 58635.959,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5084371.237,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8075247.27,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4373248,
+ "min": 4373248,
+ "max": 4373248
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 4233264,
+ "min": 4233264,
+ "max": 4233264
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5816320,
+ "min": 5799936,
+ "max": 6078464
+ },
+ "elapsed_ns": {
+ "median": 134471775,
+ "min": 134289332,
+ "max": 216945564
+ },
+ "cpu_ns": {
+ "median": 76002725,
+ "min": 75355273,
+ "max": 116157398
+ },
+ "parse_call_ns": {
+ "median": 22740343,
+ "min": 22600489,
+ "max": 25703347
+ },
+ "selection_copy_bytes": {
+ "median": 100663296,
+ "min": 100663296,
+ "max": 100663296
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2334.193158,
+ "min": 2317.391148,
+ "max": 3917.681175
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 59008.762,
+ "latency_p99_upper_ns": 90112
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5084982.783,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8075279.097,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2371504,
+ "min": 2371504,
+ "max": 2371504
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2100224,
+ "min": 2100224,
+ "max": 2100224
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3293184,
+ "min": 3178496,
+ "max": 3571712
+ },
+ "elapsed_ns": {
+ "median": 133593447,
+ "min": 133495777,
+ "max": 135030934
+ },
+ "cpu_ns": {
+ "median": 66640259,
+ "min": 66172548,
+ "max": 71236281
+ },
+ "parse_call_ns": {
+ "median": 22303696,
+ "min": 22176603,
+ "max": 22446961
+ },
+ "selection_copy_bytes": {
+ "median": 33554432,
+ "min": 33554432,
+ "max": 33554432
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2044.238204,
+ "min": 2031.917671,
+ "max": 2100.123381
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 2048,
+ "min": 2048,
+ "max": 2048
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 51484.234,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5078396.125,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8066089.677,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2371504,
+ "min": 2371504,
+ "max": 2371504
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2100224,
+ "min": 2100224,
+ "max": 2100224
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3194880,
+ "min": 3194880,
+ "max": 3244032
+ },
+ "elapsed_ns": {
+ "median": 133655494,
+ "min": 133441147,
+ "max": 134034428
+ },
+ "cpu_ns": {
+ "median": 66434679,
+ "min": 66234578,
+ "max": 69077852
+ },
+ "parse_call_ns": {
+ "median": 22159339,
+ "min": 22119254,
+ "max": 22386881
+ },
+ "selection_copy_bytes": {
+ "median": 33554432,
+ "min": 33554432,
+ "max": 33554432
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2045.927873,
+ "min": 2030.079604,
+ "max": 2071.219143
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 2048,
+ "min": 2048,
+ "max": 2048
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 51484.504,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5078118.015,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8066441.419,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "same_large_field",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4435888,
+ "min": 4435888,
+ "max": 4435888
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 4767744,
+ "min": 4767744,
+ "max": 4833280
+ },
+ "elapsed_ns": {
+ "median": 133681327,
+ "min": 133447386,
+ "max": 134457305
+ },
+ "cpu_ns": {
+ "median": 69361342,
+ "min": 68765370,
+ "max": 70251788
+ },
+ "parse_call_ns": {
+ "median": 22353361,
+ "min": 22338685,
+ "max": 22437830
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 541359.828153,
+ "min": 541289.267391,
+ "max": 541408.186663
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 52372.427,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5079700.568,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8067374.837,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4435888,
+ "min": 4435888,
+ "max": 4435888
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 4767744,
+ "min": 4767744,
+ "max": 5390336
+ },
+ "elapsed_ns": {
+ "median": 133311566,
+ "min": 133254368,
+ "max": 133477288
+ },
+ "cpu_ns": {
+ "median": 53725285,
+ "min": 52234245,
+ "max": 54530428
+ },
+ "parse_call_ns": {
+ "median": 22266351,
+ "min": 22239925,
+ "max": 22789187
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 541551.170985,
+ "min": 541367.893955,
+ "max": 541575.408384
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 46306.509,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5067325.337,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8070214.071,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4730672,
+ "min": 4730672,
+ "max": 4730672
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 2100224,
+ "min": 2067408,
+ "max": 2100224
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 6340608,
+ "min": 6340608,
+ "max": 6406144
+ },
+ "elapsed_ns": {
+ "median": 133282278,
+ "min": 133118662,
+ "max": 133472857
+ },
+ "cpu_ns": {
+ "median": 59607669,
+ "min": 59503628,
+ "max": 62602975
+ },
+ "parse_call_ns": {
+ "median": 22648269,
+ "min": 22558632,
+ "max": 23134595
+ },
+ "selection_copy_bytes": {
+ "median": 33554432,
+ "min": 33554432,
+ "max": 33554432
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 340524.867797,
+ "min": 340502.324772,
+ "max": 340709.17918
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 47236.674,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5071269.907,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8068767.35,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2378784,
+ "min": 2378784,
+ "max": 2378784
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2107504,
+ "min": 2107504,
+ "max": 2107504
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3948544,
+ "min": 3751936,
+ "max": 3964928
+ },
+ "elapsed_ns": {
+ "median": 133179940,
+ "min": 133174357,
+ "max": 133407209
+ },
+ "cpu_ns": {
+ "median": 52486508,
+ "min": 52033688,
+ "max": 55263103
+ },
+ "parse_call_ns": {
+ "median": 22154380,
+ "min": 22117835,
+ "max": 22433685
+ },
+ "selection_copy_bytes": {
+ "median": 33669120,
+ "min": 33669120,
+ "max": 33669120
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2028.917653,
+ "min": 2021.284206,
+ "max": 2079.608844
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 46179.91,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068142.38,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8068218.996,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2312896,
+ "min": 2312896,
+ "max": 2312896
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2107504,
+ "min": 2107504,
+ "max": 2107504
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3194880,
+ "min": 3178496,
+ "max": 3194880
+ },
+ "elapsed_ns": {
+ "median": 133540522,
+ "min": 133362779,
+ "max": 134281084
+ },
+ "cpu_ns": {
+ "median": 58472614,
+ "min": 57999768,
+ "max": 62190824
+ },
+ "parse_call_ns": {
+ "median": 24345793,
+ "min": 24134627,
+ "max": 25370210
+ },
+ "selection_copy_bytes": {
+ "median": 33669120,
+ "min": 33669120,
+ "max": 33669120
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2208.417867,
+ "min": 2191.645151,
+ "max": 2300.277794
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 51364.197,
+ "latency_p99_upper_ns": 81920
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5074603.185,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8073207.582,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2378672,
+ "min": 2378672,
+ "max": 2378672
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2107392,
+ "min": 2107392,
+ "max": 2107392
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3899392,
+ "min": 3293184,
+ "max": 3948544
+ },
+ "elapsed_ns": {
+ "median": 133216315,
+ "min": 133064931,
+ "max": 154001095
+ },
+ "cpu_ns": {
+ "median": 52117164,
+ "min": 51631438,
+ "max": 65368726
+ },
+ "parse_call_ns": {
+ "median": 22128273,
+ "min": 22057182,
+ "max": 23437273
+ },
+ "selection_copy_bytes": {
+ "median": 33611776,
+ "min": 33611776,
+ "max": 33611776
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2026.862393,
+ "min": 2014.496107,
+ "max": 2683.230182
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 46182.627,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068255.587,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8067189.304,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 2378672,
+ "min": 2378672,
+ "max": 2378672
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 2107392,
+ "min": 2107392,
+ "max": 2107392
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 3751936,
+ "min": 3342336,
+ "max": 3932160
+ },
+ "elapsed_ns": {
+ "median": 133312135,
+ "min": 133094723,
+ "max": 134333542
+ },
+ "cpu_ns": {
+ "median": 52726291,
+ "min": 52362717,
+ "max": 53734268
+ },
+ "parse_call_ns": {
+ "median": 22219255,
+ "min": 22103023,
+ "max": 22533891
+ },
+ "selection_copy_bytes": {
+ "median": 33611776,
+ "min": 33611776,
+ "max": 33611776
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2039.714059,
+ "min": 2022.420003,
+ "max": 2071.170012
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 46192.459,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068879.809,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8069081.323,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "slow_large_field",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4443056,
+ "min": 4443056,
+ "max": 4443056
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5292032,
+ "min": 4751360,
+ "max": 5439488
+ },
+ "elapsed_ns": {
+ "median": 133341496,
+ "min": 133297584,
+ "max": 134650847
+ },
+ "cpu_ns": {
+ "median": 54857945,
+ "min": 53670610,
+ "max": 58145169
+ },
+ "parse_call_ns": {
+ "median": 22618201,
+ "min": 22263776,
+ "max": 22801055
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 541518.37496,
+ "min": 541459.255198,
+ "max": 542663.104532
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 47550.497,
+ "latency_p99_upper_ns": 73728
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5070242.543,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8069675.14,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "borrow",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4435888,
+ "min": 4435888,
+ "max": 4435888
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5373952,
+ "min": 5373952,
+ "max": 5373952
+ },
+ "elapsed_ns": {
+ "median": 132595906,
+ "min": 132489898,
+ "max": 133433884
+ },
+ "cpu_ns": {
+ "median": 49691116,
+ "min": 48808681,
+ "max": 51462618
+ },
+ "parse_call_ns": {
+ "median": 22667622,
+ "min": 22622066,
+ "max": 23747967
+ },
+ "selection_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 540593.356702,
+ "min": 540484.370521,
+ "max": 540814.68462
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 45356.652,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5069713.765,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8055489.045,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "compact",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 4436784,
+ "min": 4436784,
+ "max": 4436784
+ },
+ "source_peak_bytes": {
+ "median": 4230192,
+ "min": 4230192,
+ "max": 4230192
+ },
+ "output_peak_bytes": {
+ "median": 6944,
+ "min": 6944,
+ "max": 7056
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 5537792,
+ "min": 5488640,
+ "max": 5603328
+ },
+ "elapsed_ns": {
+ "median": 132699783,
+ "min": 132597323,
+ "max": 132746292
+ },
+ "cpu_ns": {
+ "median": 50225388,
+ "min": 49739534,
+ "max": 50870250
+ },
+ "parse_call_ns": {
+ "median": 22671992,
+ "min": 22546544,
+ "max": 22749218
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 340108.105991,
+ "min": 340105.112239,
+ "max": 340246.674827
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 45463.711,
+ "latency_p99_upper_ns": 65536
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5069991.558,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8055038.37,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 318432,
+ "min": 318432,
+ "max": 318432
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 47152,
+ "min": 47152,
+ "max": 47152
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1851392,
+ "min": 1851392,
+ "max": 1867776
+ },
+ "elapsed_ns": {
+ "median": 132282510,
+ "min": 132122049,
+ "max": 132351078
+ },
+ "cpu_ns": {
+ "median": 46122525,
+ "min": 45960158,
+ "max": 46415608
+ },
+ "parse_call_ns": {
+ "median": 22062914,
+ "min": 22012014,
+ "max": 22082400
+ },
+ "selection_copy_bytes": {
+ "median": 33669120,
+ "min": 33669120,
+ "max": 33669120
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1991.776071,
+ "min": 1985.913742,
+ "max": 1996.444688
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 42165.024,
+ "latency_p99_upper_ns": 53248
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068352.743,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8050279.443,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "copy_no_pool",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 252544,
+ "min": 252544,
+ "max": 252544
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 47152,
+ "min": 47152,
+ "max": 47152
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1900544,
+ "min": 1884160,
+ "max": 1933312
+ },
+ "elapsed_ns": {
+ "median": 132297747,
+ "min": 132221655,
+ "max": 132985160
+ },
+ "cpu_ns": {
+ "median": 46669804,
+ "min": 46345346,
+ "max": 49981054
+ },
+ "parse_call_ns": {
+ "median": 22170762,
+ "min": 22094470,
+ "max": 23442854
+ },
+ "selection_copy_bytes": {
+ "median": 33669120,
+ "min": 33669120,
+ "max": 33669120
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2009.648765,
+ "min": 1998.568774,
+ "max": 2129.142526
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 42678.905,
+ "latency_p99_upper_ns": 61440
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068637.263,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8054142.04,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "shared_copy",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 311264,
+ "min": 311264,
+ "max": 311264
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 39984,
+ "min": 39984,
+ "max": 39984
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1851392,
+ "min": 1835008,
+ "max": 1851392
+ },
+ "elapsed_ns": {
+ "median": 132284819,
+ "min": 132140503,
+ "max": 133179387
+ },
+ "cpu_ns": {
+ "median": 45991210,
+ "min": 45823432,
+ "max": 47009567
+ },
+ "parse_call_ns": {
+ "median": 22104890,
+ "min": 22053622,
+ "max": 22145612
+ },
+ "selection_copy_bytes": {
+ "median": 33611776,
+ "min": 33611776,
+ "max": 33611776
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1991.371251,
+ "min": 1983.569581,
+ "max": 2001.098596
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 42139.616,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068344.258,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8052022.729,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold2",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 311264,
+ "min": 311264,
+ "max": 311264
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 39984,
+ "min": 39984,
+ "max": 39984
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1851392,
+ "min": 1835008,
+ "max": 1867776
+ },
+ "elapsed_ns": {
+ "median": 132243573,
+ "min": 132119197,
+ "max": 132423215
+ },
+ "cpu_ns": {
+ "median": 45811373,
+ "min": 45674856,
+ "max": 46202689
+ },
+ "parse_call_ns": {
+ "median": 22085581,
+ "min": 22029775,
+ "max": 22137673
+ },
+ "selection_copy_bytes": {
+ "median": 33611776,
+ "min": 33611776,
+ "max": 33611776
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 1984.871517,
+ "min": 1978.146096,
+ "max": 1992.776523
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 42043.254,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5068193.573,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8050581.195,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ },
+ {
+ "case": "three_distinct_speeds",
+ "variant": "threshold8",
+ "samples": 5,
+ "peak_reserved_bytes": {
+ "median": 311264,
+ "min": 311264,
+ "max": 311264
+ },
+ "source_peak_bytes": {
+ "median": 98400,
+ "min": 98400,
+ "max": 98400
+ },
+ "output_peak_bytes": {
+ "median": 7168,
+ "min": 7168,
+ "max": 7168
+ },
+ "parser_peak_bytes": {
+ "median": 131120,
+ "min": 131120,
+ "max": 131120
+ },
+ "rss_peak_bytes": {
+ "median": 1851392,
+ "min": 1851392,
+ "max": 1851392
+ },
+ "elapsed_ns": {
+ "median": 132177385,
+ "min": 132072752,
+ "max": 132687220
+ },
+ "cpu_ns": {
+ "median": 44977578,
+ "min": 44815017,
+ "max": 45610919
+ },
+ "parse_call_ns": {
+ "median": 22128368,
+ "min": 22007505,
+ "max": 22143479
+ },
+ "selection_copy_bytes": {
+ "median": 57344,
+ "min": 57344,
+ "max": 57344
+ },
+ "reader_copy_bytes": {
+ "median": 75711296,
+ "min": 75711296,
+ "max": 75711296
+ },
+ "parser_realloc_copy_bytes": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "source_byte_seconds": {
+ "median": 2381.095196,
+ "min": 2372.402719,
+ "max": 2398.303122
+ },
+ "budget_waits": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "compacted": {
+ "median": 0,
+ "min": 0,
+ "max": 0
+ },
+ "dedup_hits": {
+ "median": 1024,
+ "min": 1024,
+ "max": 1024
+ },
+ "queues": [
+ {
+ "peak_count": 1,
+ "latency_mean_ns": 41268.295,
+ "latency_p99_upper_ns": 57344
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 5067698.961,
+ "latency_p99_upper_ns": 5242880
+ },
+ {
+ "peak_count": 64,
+ "latency_mean_ns": 8050851.553,
+ "latency_p99_upper_ns": 8388608
+ }
+ ]
+ }
+]
diff --git a/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/verification.json b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/verification.json
new file mode 100644
index 0000000..ca94ae7
--- /dev/null
+++ b/research/experiments/003-json-fanout/results/2026-09-22-linux-aarch64/verification.json
@@ -0,0 +1,114 @@
+{
+ "native": [
+ "borrow: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: empty input, final JSON without newline, first duplicate member",
+ "borrow: eight invalid JSON/schema cases with retained owners",
+ "borrow: cancellation preserves each branch prefix and releases all shared owners",
+ "borrow: parser allocation charged and refused within total budget",
+ "copy: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: empty input, final JSON without newline, first duplicate member",
+ "copy: eight invalid JSON/schema cases with retained owners",
+ "copy: cancellation preserves each branch prefix and releases all shared owners",
+ "copy: parser allocation charged and refused within total budget",
+ "shared_copy: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: empty input, final JSON without newline, first duplicate member",
+ "shared_copy: eight invalid JSON/schema cases with retained owners",
+ "shared_copy: cancellation preserves each branch prefix and releases all shared owners",
+ "shared_copy: parser allocation charged and refused within total budget",
+ "threshold2: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: empty input, final JSON without newline, first duplicate member",
+ "threshold2: eight invalid JSON/schema cases with retained owners",
+ "threshold2: cancellation preserves each branch prefix and releases all shared owners",
+ "threshold2: parser allocation charged and refused within total budget",
+ "threshold8: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: empty input, final JSON without newline, first duplicate member",
+ "threshold8: eight invalid JSON/schema cases with retained owners",
+ "threshold8: cancellation preserves each branch prefix and releases all shared owners",
+ "threshold8: parser allocation charged and refused within total budget",
+ "compact: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: empty input, final JSON without newline, first duplicate member",
+ "compact: eight invalid JSON/schema cases with retained owners",
+ "compact: cancellation preserves each branch prefix and releases all shared owners",
+ "compact: parser allocation charged and refused within total budget",
+ "copy_no_pool: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: empty input, final JSON without newline, first duplicate member",
+ "copy_no_pool: eight invalid JSON/schema cases with retained owners",
+ "copy_no_pool: cancellation preserves each branch prefix and releases all shared owners",
+ "copy_no_pool: parser allocation charged and refused within total budget",
+ "identical selections copied once and live until the final consumer",
+ "last-owner compaction keeps the delayed decoded value valid",
+ "overlong NDJSON record refused without leaked source",
+ "actual /dev/full failure releases multiple owners",
+ "SIGTERM during delayed fan-out releases all owners"
+ ],
+ "asan_ubsan": [
+ "borrow: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "borrow: empty input, final JSON without newline, first duplicate member",
+ "borrow: eight invalid JSON/schema cases with retained owners",
+ "borrow: cancellation preserves each branch prefix and releases all shared owners",
+ "borrow: parser allocation charged and refused within total budget",
+ "copy: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy: empty input, final JSON without newline, first duplicate member",
+ "copy: eight invalid JSON/schema cases with retained owners",
+ "copy: cancellation preserves each branch prefix and releases all shared owners",
+ "copy: parser allocation charged and refused within total budget",
+ "shared_copy: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "shared_copy: empty input, final JSON without newline, first duplicate member",
+ "shared_copy: eight invalid JSON/schema cases with retained owners",
+ "shared_copy: cancellation preserves each branch prefix and releases all shared owners",
+ "shared_copy: parser allocation charged and refused within total budget",
+ "threshold2: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold2: empty input, final JSON without newline, first duplicate member",
+ "threshold2: eight invalid JSON/schema cases with retained owners",
+ "threshold2: cancellation preserves each branch prefix and releases all shared owners",
+ "threshold2: parser allocation charged and refused within total budget",
+ "threshold8: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "threshold8: empty input, final JSON without newline, first duplicate member",
+ "threshold8: eight invalid JSON/schema cases with retained owners",
+ "threshold8: cancellation preserves each branch prefix and releases all shared owners",
+ "threshold8: parser allocation charged and refused within total budget",
+ "compact: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "compact: empty input, final JSON without newline, first duplicate member",
+ "compact: eight invalid JSON/schema cases with retained owners",
+ "compact: cancellation preserves each branch prefix and releases all shared owners",
+ "compact: parser allocation charged and refused within total budget",
+ "copy_no_pool: 1 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: 2 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: 3 consumer(s), UTF-8/escapes/NUL/empty, slot reuse",
+ "copy_no_pool: empty input, final JSON without newline, first duplicate member",
+ "copy_no_pool: eight invalid JSON/schema cases with retained owners",
+ "copy_no_pool: cancellation preserves each branch prefix and releases all shared owners",
+ "copy_no_pool: parser allocation charged and refused within total budget",
+ "identical selections copied once and live until the final consumer",
+ "last-owner compaction keeps the delayed decoded value valid",
+ "overlong NDJSON record refused without leaked source",
+ "actual /dev/full failure releases multiple owners",
+ "SIGTERM during delayed fan-out releases all owners"
+ ]
+}