deploy: a47170346a
This commit is contained in:
1 parent
b36f8a9821
commit
11a863958e
1180 files changed
+14211
-6025
No files matched your search
+133
-18
@@ -6,7 +6,7 @@ first. If a hard real-time budget or the last percent of throughput matters more
|
||||
[faster, more specialized library](https://github.com/miloyip/nativejson-benchmark#parsing-time) may be a better fit.
|
||||
|
||||
That said, how you use this library still makes a measurable difference. This page collects practical, code-verified
|
||||
techniques for reducing time, memory, and compile-time cost -- without repeating the detailed pages it links to.
|
||||
techniques for reducing time, memory, and compile-time cost — without repeating the detailed pages it links to.
|
||||
|
||||
## Parsing input
|
||||
|
||||
@@ -14,8 +14,8 @@ techniques for reducing time, memory, and compile-time cost -- without repeating
|
||||
`#!cpp FILE*` (see [Parsing](parsing/index.md#input)). Internally, every input is wrapped in an
|
||||
[input adapter](../home/architecture.md#input-adapters), and not all adapters are equally fast.
|
||||
|
||||
For inputs backed by contiguous, single-byte memory -- a `#!cpp std::string`, a `#!cpp std::vector<char>`, a string
|
||||
literal, or a pointer range -- the library uses `iterator_input_adapter`, wrapped in a raw pointer so the fast paths
|
||||
For inputs backed by contiguous, single-byte memory — a `#!cpp std::string`, a `#!cpp std::vector<char>`, a string
|
||||
literal, or a pointer range — the library uses `iterator_input_adapter`, wrapped in a raw pointer so the fast paths
|
||||
below apply on every supported standard. This adapter exposes two optimizations the lexer detects at compile time:
|
||||
|
||||
- it can reconstruct already-consumed input on demand for error messages, instead of copying every character as it is
|
||||
@@ -69,7 +69,7 @@ a DOM, three alternatives avoid building it:
|
||||
`basic_json` values.
|
||||
- Pass a [parser callback](parsing/parser_callbacks.md) to `parse`. This still builds a DOM, but the callback can
|
||||
discard finished elements as soon as they are handled, so memory usage stays bounded by one element (plus the
|
||||
unparsed remainder of the input) instead of the whole document -- see the [recipe for streaming a large homogeneous
|
||||
unparsed remainder of the input) instead of the whole document — see the [recipe for streaming a large homogeneous
|
||||
array](parsing/parser_callbacks.md#recipe-streaming-a-large-homogeneous-array).
|
||||
- Parse into a [`json_document`](json_view.md) (`#!cpp <nlohmann/json_view.hpp>`) instead of a `basic_json`. It keeps
|
||||
the input text and builds a flat index of 16 bytes per value; strings and floating-point numbers are not copied, but
|
||||
@@ -85,35 +85,144 @@ at a time, and a malformed line does not invalidate lines already processed.
|
||||
## Binary formats
|
||||
|
||||
JSON text is not a compact format. If the data is only exchanged between programs (not read by humans), the
|
||||
[binary formats](binary_formats/index.md) -- BJData, BON8, BSON, CBOR, MessagePack, and UBJSON -- encode the same
|
||||
[binary formats](binary_formats/index.md) — BJData, BON8, BSON, CBOR, MessagePack, and UBJSON — encode the same
|
||||
values more compactly, which reduces both the bytes transferred and, for most of them, the work needed to parse them
|
||||
back. The [size comparison](binary_formats/index.md#sizes) on that page, measured against minified JSON for four
|
||||
reference documents, shows the effect varies a lot by document shape: CBOR and MessagePack come out at 50.5% of the
|
||||
minified JSON size for the numeric-array-heavy `canada.json`, but only around 87-88% for the string-heavy
|
||||
`jeopardy.json`, where there is less numeric data to encode more compactly. BON8 is the most compact option in that
|
||||
comparison for text-heavy documents (63.5%-87.5%), at the cost of an
|
||||
[incomplete serializer](binary_formats/index.md#completeness) (no unsigned integers above int64). Which format -- and
|
||||
whether it is worth the loss of human readability at all -- depends on the actual data; see the
|
||||
[incomplete serializer](binary_formats/index.md#completeness) (no unsigned integers above int64). Which format — and
|
||||
whether it is worth the loss of human readability at all — depends on the actual data; see the
|
||||
[comparison tables](binary_formats/index.md#comparison) before choosing one.
|
||||
|
||||
<div class="nj-charts-grid-wrap" markdown>
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
<svg class="nj-fig nj-charts nj-charts--sizes" viewBox="0 0 340 220" role="img" aria-labelledby="nj-charts-bs-canada nj-charts-bs-canada-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-charts-bs-canada">Size of canada.json in each binary format relative to minified J​SON</title>
|
||||
<desc id="nj-charts-bs-canada-d">B​JData 53.2 %; B​ON8 50.5 %; B​SON 85.8 %; C​BOR 50.5 %; MessagePack 50.5 %; U​BJSON 53.2 %. Smallest: B​ON8 and C​BOR and MessagePack.</desc>
|
||||
<text class="nj-charts-panel" x="8" y="18">canada.json</text>
|
||||
<line class="nj-charts-grid" x1="104" y1="40" x2="104" y2="196"/>
|
||||
<text class="nj-charts-tick" x="104" y="211">0 %</text>
|
||||
<line class="nj-charts-grid" x1="186.727" y1="40" x2="186.727" y2="196"/>
|
||||
<text class="nj-charts-tick" x="186.727" y="211">50 %</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="58.5">B​JData</text>
|
||||
<path class="nj-charts-c1 nj-charts-dim" d="M104 46 H188.022 Q192.022 46 192.022 50 V58 Q192.022 62 188.022 62 H104 Z"><title>canada.json, B​JData: 53.2 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt nj-charts-best" x="96" y="84.5">B​ON8</text>
|
||||
<path class="nj-charts-c2" d="M104 72 H183.555 Q187.555 72 187.555 76 V84 Q187.555 88 183.555 88 H104 Z"><title>canada.json, B​ON8: 50.5 % of minified J​SON (smallest)</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="110.5">B​SON</text>
|
||||
<path class="nj-charts-c3 nj-charts-dim" d="M104 98 H241.96 Q245.96 98 245.96 102 V110 Q245.96 114 241.96 114 H104 Z"><title>canada.json, B​SON: 85.8 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt nj-charts-best" x="96" y="136.5">C​BOR</text>
|
||||
<path class="nj-charts-c4" d="M104 124 H183.555 Q187.555 124 187.555 128 V136 Q187.555 140 183.555 140 H104 Z"><title>canada.json, C​BOR: 50.5 % of minified J​SON (smallest)</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt nj-charts-best" x="96" y="162.5">MessagePack</text>
|
||||
<path class="nj-charts-c5" d="M104 150 H183.555 Q187.555 150 187.555 154 V162 Q187.555 166 183.555 166 H104 Z"><title>canada.json, MessagePack: 50.5 % of minified J​SON (smallest)</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="188.5">U​BJSON</text>
|
||||
<path class="nj-charts-c6 nj-charts-dim" d="M104 176 H188.022 Q192.022 176 192.022 180 V188 Q192.022 192 188.022 192 H104 Z"><title>canada.json, U​BJSON: 53.2 % of minified J​SON</title></path>
|
||||
<line class="nj-charts-ref" x1="269.455" y1="36" x2="269.455" y2="196"/>
|
||||
<text class="nj-charts-tick nj-charts-tick--r" x="271.455" y="32">minified J​SON = 100 %</text>
|
||||
<text class="nj-charts-tick" x="269.455" y="211">100 %</text>
|
||||
<text class="nj-charts-val" x="197.022" y="58.5">53.2 %</text>
|
||||
<text class="nj-charts-val nj-charts-best" x="192.555" y="84.5">50.5 %</text>
|
||||
<text class="nj-charts-val" x="250.96" y="110.5">85.8 %</text>
|
||||
<text class="nj-charts-val nj-charts-best" x="192.555" y="136.5">50.5 %</text>
|
||||
<text class="nj-charts-val nj-charts-best" x="192.555" y="162.5">50.5 %</text>
|
||||
<text class="nj-charts-val" x="197.022" y="188.5">53.2 %</text>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
<svg class="nj-fig nj-charts nj-charts--sizes" viewBox="0 0 340 220" role="img" aria-labelledby="nj-charts-bs-jeopardy nj-charts-bs-jeopardy-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-charts-bs-jeopardy">Size of jeopardy.json in each binary format relative to minified J​SON</title>
|
||||
<desc id="nj-charts-bs-jeopardy-d">B​JData 96.6 %; B​ON8 87.5 %; B​SON 106.7 %; C​BOR 88 %; MessagePack 87.9 %; U​BJSON 96.6 %. Smallest: B​ON8.</desc>
|
||||
<text class="nj-charts-panel" x="8" y="18">jeopardy.json</text>
|
||||
<line class="nj-charts-grid" x1="104" y1="40" x2="104" y2="196"/>
|
||||
<text class="nj-charts-tick" x="104" y="211">0 %</text>
|
||||
<line class="nj-charts-grid" x1="186.727" y1="40" x2="186.727" y2="196"/>
|
||||
<text class="nj-charts-tick" x="186.727" y="211">50 %</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="58.5">B​JData</text>
|
||||
<path class="nj-charts-c1 nj-charts-dim" d="M104 46 H259.829 Q263.829 46 263.829 50 V58 Q263.829 62 259.829 62 H104 Z"><title>jeopardy.json, B​JData: 96.6 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt nj-charts-best" x="96" y="84.5">B​ON8</text>
|
||||
<path class="nj-charts-c2" d="M104 72 H244.773 Q248.773 72 248.773 76 V84 Q248.773 88 244.773 88 H104 Z"><title>jeopardy.json, B​ON8: 87.5 % of minified J​SON (smallest)</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="110.5">B​SON</text>
|
||||
<path class="nj-charts-c3 nj-charts-dim" d="M104 98 H276.54 Q280.54 98 280.54 102 V110 Q280.54 114 276.54 114 H104 Z"><title>jeopardy.json, B​SON: 106.7 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="136.5">C​BOR</text>
|
||||
<path class="nj-charts-c4 nj-charts-dim" d="M104 124 H245.6 Q249.6 124 249.6 128 V136 Q249.6 140 245.6 140 H104 Z"><title>jeopardy.json, C​BOR: 88 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="162.5">MessagePack</text>
|
||||
<path class="nj-charts-c5 nj-charts-dim" d="M104 150 H245.435 Q249.435 150 249.435 154 V162 Q249.435 166 245.435 166 H104 Z"><title>jeopardy.json, MessagePack: 87.9 % of minified J​SON</title></path>
|
||||
<text class="nj-charts-rowlabel nj-charts-fmt" x="96" y="188.5">U​BJSON</text>
|
||||
<path class="nj-charts-c6 nj-charts-dim" d="M104 176 H259.829 Q263.829 176 263.829 180 V188 Q263.829 192 259.829 192 H104 Z"><title>jeopardy.json, U​BJSON: 96.6 % of minified J​SON</title></path>
|
||||
<line class="nj-charts-ref" x1="269.455" y1="36" x2="269.455" y2="196"/>
|
||||
<text class="nj-charts-tick nj-charts-tick--r" x="271.455" y="32">minified J​SON = 100 %</text>
|
||||
<text class="nj-charts-tick" x="269.455" y="211">100 %</text>
|
||||
<text class="nj-charts-val" x="268.829" y="58.5">96.6 %</text>
|
||||
<text class="nj-charts-val nj-charts-best" x="253.773" y="84.5">87.5 %</text>
|
||||
<text class="nj-charts-val" x="285.54" y="110.5">106.7 %</text>
|
||||
<text class="nj-charts-val" x="254.6" y="136.5">88.0 %</text>
|
||||
<text class="nj-charts-val" x="254.435" y="162.5">87.9 %</text>
|
||||
<text class="nj-charts-val" x="268.829" y="188.5">96.6 %</text>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p class="nj-charts-caption" markdown>Two of the four panels from the [size comparison](binary_formats/index.md#sizes);
|
||||
the smallest format per file is drawn in a stronger colour than the others.</p>
|
||||
|
||||
## Object type: `json` vs. `ordered_json`
|
||||
|
||||
The default [`json`](../api/json.md) type stores object keys in a `#!cpp std::map`, giving logarithmic-time lookup,
|
||||
insertion, and erasure, at the cost of sorting keys alphabetically rather than preserving insertion order (see
|
||||
[Object Order](object_order.md)). [`ordered_json`](../api/ordered_json.md) uses
|
||||
[`nlohmann::ordered_map`](../api/ordered_map.md) instead, a `#!cpp std::vector`-backed container with no lookup index:
|
||||
every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total --
|
||||
every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total —
|
||||
this applies equally to inserting keys one by one and to parsing an object, since the parser inserts each key as it is
|
||||
read. The [measurements on the `ordered_map` page](../api/ordered_map.md#complexity) show this is
|
||||
negligible at typical object sizes (2000 keys: 0.7 ms for `json` vs. 3.6 ms for `ordered_json`, a 5x factor) but grows
|
||||
steeply for large, machine-generated objects (16 000 keys: 3.3 ms vs. 181.6 ms, a 54x factor).
|
||||
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
<svg class="nj-fig nj-charts nj-charts--scaling" viewBox="0 0 440 238" role="img" aria-labelledby="nj-charts-sc nj-charts-sc-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-charts-sc">Time to parse a flat object of n keys, json against ordered_json, logarithmic axes</title>
|
||||
<desc id="nj-charts-sc-d">2000 keys: json 0.7 ms, ordered_json 3.6 ms (5x). 4000 keys: 0.8 ms and 14.0 ms (19x). 8000 keys: 1.6 ms and 67.8 ms (43x). 16000 keys: 3.3 ms and 181.6 ms (54x).</desc>
|
||||
<line class="nj-charts-grid" x1="66" y1="176.187" x2="330" y2="176.187"/>
|
||||
<text class="nj-charts-tick nj-charts-tick--r" x="60" y="180.187">1 ms</text>
|
||||
<line class="nj-charts-grid" x1="66" y1="111.521" x2="330" y2="111.521"/>
|
||||
<text class="nj-charts-tick nj-charts-tick--r" x="60" y="115.521">10 ms</text>
|
||||
<line class="nj-charts-grid" x1="66" y1="46.8538" x2="330" y2="46.8538"/>
|
||||
<text class="nj-charts-tick nj-charts-tick--r" x="60" y="50.8538">100 ms</text>
|
||||
<line class="nj-charts-axis" x1="66" y1="210" x2="330" y2="210"/>
|
||||
<text class="nj-charts-tick" x="66" y="226">2 000</text>
|
||||
<text class="nj-charts-tick" x="154" y="226">4 000</text>
|
||||
<text class="nj-charts-tick" x="242" y="226">8 000</text>
|
||||
<text class="nj-charts-tick" x="330" y="226">16 000</text>
|
||||
<polyline class="nj-charts-json" points="66,186.204 154,182.454 242,162.987 330,142.657"/>
|
||||
<circle class="nj-charts-json-dot" cx="66" cy="186.204" r="4.5"><title>json, 2000 keys: 0.7 ms</title></circle>
|
||||
<circle class="nj-charts-json-dot" cx="154" cy="182.454" r="4.5"><title>json, 4000 keys: 0.8 ms</title></circle>
|
||||
<circle class="nj-charts-json-dot" cx="242" cy="162.987" r="4.5"><title>json, 8000 keys: 1.6 ms</title></circle>
|
||||
<circle class="nj-charts-json-dot" cx="330" cy="142.657" r="4.5"><title>json, 16000 keys: 3.3 ms</title></circle>
|
||||
<text class="nj-charts-val nj-charts-name-json" x="340" y="140.657">json</text>
|
||||
<text class="nj-charts-val" x="340" y="155.657">3.3 ms</text>
|
||||
<text class="nj-charts-val" x="72" y="202.204">0.7 ms</text>
|
||||
<polyline class="nj-charts-ojson" points="66,140.213 154,102.071 242,57.7677 330,30.0977"/>
|
||||
<circle class="nj-charts-ojson-dot" cx="66" cy="140.213" r="4.5"><title>ordered_json, 2000 keys: 3.6 ms</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="154" cy="102.071" r="4.5"><title>ordered_json, 4000 keys: 14 ms</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="242" cy="57.7677" r="4.5"><title>ordered_json, 8000 keys: 67.8 ms</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="330" cy="30.0977" r="4.5"><title>ordered_json, 16000 keys: 181.6 ms</title></circle>
|
||||
<text class="nj-charts-val nj-charts-name-ojson" x="340" y="28.0977">ordered_json</text>
|
||||
<text class="nj-charts-val" x="340" y="43.0977">181.6 ms</text>
|
||||
<text class="nj-charts-val" x="72" y="160.213">3.6 ms</text>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<p class="nj-charts-caption" markdown>Parsing a flat object of `n` keys, measured with `-O2 -DNDEBUG`; all
|
||||
four sizes from the [table on the `ordered_map` page](../api/ordered_map.md#complexity), both
|
||||
axes logarithmic.</p>
|
||||
|
||||
If insertion order matters *and* an object routinely has many thousands of keys, `ordered_json`'s quadratic build cost
|
||||
may not be acceptable. The library's [`ObjectType` template parameter](types/template_parameters.md#objecttype) can be
|
||||
set to a different container instead: `#!cpp nlohmann::fifo_map` keeps insertion order with a real lookup index
|
||||
(avoiding the quadratic cost), while `#!cpp std::unordered_map`, `#!cpp boost::unordered_flat_map`,
|
||||
`#!cpp absl::flat_hash_map`, and similar hash maps trade insertion order for average-case constant-time lookup (through
|
||||
an adapter, since their template argument order does not match what `basic_json` expects) -- see
|
||||
an adapter, since their template argument order does not match what `basic_json` expects) — see
|
||||
[Object Order](object_order.md#alternative-behavior-preserve-insertion-order) for the full list.
|
||||
|
||||
## Avoiding copies
|
||||
@@ -128,13 +237,13 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
- **Access without copying.** [`get<T>()`](../api/basic_json/get.md) returns a copy of the stored value converted to
|
||||
`T`. When a reference or pointer to the value already stored inside the `basic_json` is enough,
|
||||
[`get_ref()`](../api/basic_json/get_ref.md) and [`get_ptr()`](../api/basic_json/get_ptr.md) access it directly:
|
||||
both pages state, word for word, "No copies are made." -- at the cost of that reference or pointer becoming invalid
|
||||
both pages state, word for word, "No copies are made." — at the cost of that reference or pointer becoming invalid
|
||||
once the underlying value changes.
|
||||
- **Iterate by reference.** `#!cpp basic_json::iterator::operator*()` returns a `reference` (an alias for
|
||||
`#!cpp basic_json&`), but a range-based for loop with a by-value loop variable (`#!cpp for (auto el : j)`) still
|
||||
copies each element, because plain `#!cpp auto` drops the reference. Write `#!cpp for (const auto& el : j)` (or
|
||||
`#!cpp auto&` for a mutable loop), and use [`items()`](../api/basic_json/items.md) the same way when the key is
|
||||
needed too -- its own examples use `#!cpp for (auto& el : j.items())`.
|
||||
needed too — its own examples use `#!cpp for (auto& el : j.items())`.
|
||||
- **Construct in place.** [`emplace_back()`](../api/basic_json/emplace_back.md) (arrays, amortized constant time) and
|
||||
[`emplace()`](../api/basic_json/emplace.md) (objects, logarithmic in the size of the container for `json`) forward
|
||||
their arguments directly to a `basic_json` constructor, rather than requiring a temporary value to be
|
||||
@@ -143,13 +252,13 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
in instead of copying it.
|
||||
- **Skip the bounds check when it is redundant.** [`at()`](../api/basic_json/at.md) and
|
||||
[`operator[]`](../api/basic_json/operator%5B%5D.md) have the same complexity (constant for a valid array index,
|
||||
logarithmic for an object key in `json`) -- the difference is that `at()` additionally checks the key or index and
|
||||
logarithmic for an object key in `json`) — the difference is that `at()` additionally checks the key or index and
|
||||
throws if it is invalid, while `operator[]` does not (see [unchecked access](element_access/unchecked_access.md) and
|
||||
[checked access](element_access/checked_access.md)). Prefer `operator[]` when the surrounding code has already
|
||||
established that the access is valid.
|
||||
- **Reserve array capacity.** `basic_json` has no public `reserve()`, but when building a large array
|
||||
incrementally with a known final size, [`get_ref()`](../api/basic_json/get_ref.md) exposes the underlying
|
||||
`#!cpp array_t` so it can be reserved directly -- see
|
||||
`#!cpp array_t` so it can be reserved directly — see
|
||||
["reserving array capacity"](element_access/unchecked_access.md#performance-reserving-array-capacity) for the
|
||||
one-line recipe.
|
||||
|
||||
@@ -182,7 +291,7 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
(word for word from the page); any non-negative `indent` pretty-prints instead, which is more readable but produces
|
||||
more bytes and more work. `dump()` builds and returns a complete `#!cpp string_t` containing the whole serialization.
|
||||
[`operator<<`](../api/operator_ltlt.md) writes directly to a `#!cpp std::ostream` instead, through the same
|
||||
serializer, but without ever materializing that intermediate string -- so if the destination is a stream (a file, or
|
||||
serializer, but without ever materializing that intermediate string — so if the destination is a stream (a file, or
|
||||
`#!cpp std::cout`), `#!cpp os << j;` avoids the allocation and copy that `#!cpp os << j.dump();` would incur for large
|
||||
values.
|
||||
|
||||
@@ -193,7 +302,7 @@ while it is in use:
|
||||
|
||||
- [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) adds a JSON Pointer to exception messages, pointing at the
|
||||
value that triggered the exception. Quoting the page directly: "enabling this macro increases the size of every
|
||||
JSON value by one pointer and adds some runtime overhead" -- every value gains a parent pointer that has to be kept
|
||||
JSON value by one pointer and adds some runtime overhead" — every value gains a parent pointer that has to be kept
|
||||
up to date as the document is built and modified.
|
||||
- [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) adds
|
||||
[`start_pos()`](../api/basic_json/start_pos.md) and [`end_pos()`](../api/basic_json/end_pos.md), the byte offsets a
|
||||
@@ -210,7 +319,7 @@ untrusted input, or in a debug build), and keep them off in a release build that
|
||||
[`basic_json`](../api/basic_json/index.md), [`json`](../api/json.md), [`ordered_json`](../api/ordered_json.md),
|
||||
[`json_pointer`](../api/json_pointer/index.md), and [`adl_serializer`](../api/adl_serializer/index.md), pulling in only
|
||||
a handful of lightweight standard headers instead of the full `json.hpp`. A header that only needs to *name*
|
||||
`nlohmann::json` -- in a function signature or a class member declaration, for instance -- can include `json_fwd.hpp`
|
||||
`nlohmann::json` — in a function signature or a class member declaration, for instance — can include `json_fwd.hpp`
|
||||
and leave `#!cpp #include <nlohmann/json.hpp>` to the source files that actually parse, build, or serialize values,
|
||||
the same way a project would forward-declare any other heavy class to keep it out of widely-included headers:
|
||||
|
||||
@@ -231,8 +340,8 @@ nlohmann::json my_type::config() const { /* ... */ }
|
||||
```
|
||||
|
||||
One caveat: ABI-affecting macros such as `JSON_DIAGNOSTICS` and `JSON_DIAGNOSTIC_POSITIONS` are encoded into the
|
||||
library's [inline namespace name](namespace.md#limitations). Every translation unit -- whether it includes
|
||||
`json_fwd.hpp` or the full header -- must define them the same way, or linking fails with undefined references
|
||||
library's [inline namespace name](namespace.md#limitations). Every translation unit — whether it includes
|
||||
`json_fwd.hpp` or the full header — must define them the same way, or linking fails with undefined references
|
||||
instead of a compile error.
|
||||
|
||||
If I/O support is not needed at all, [`JSON_NO_IO`](../api/macros/json_no_io.md) excludes `<cstdio>`, `<ios>`,
|
||||
@@ -252,3 +361,9 @@ those headers are then never processed by the compiler at all.
|
||||
- [Object Order](object_order.md) - `json` vs. `ordered_json` and other `ObjectType` choices
|
||||
- [Template Parameter Requirements](types/template_parameters.md) - custom container and allocator types
|
||||
- [Supported macros](macros.md) - overview of all configuration macros, including the diagnostics ones above
|
||||
- [`JSON_NO_SIMD`](../api/macros/json_no_simd.md) - disable SIMD acceleration
|
||||
- [`JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md) - use simdutf for UTF-8 validation
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md) - disable the stream bulk scan
|
||||
- [`parse`](../api/basic_json/parse.md) - deserialize from a compatible input
|
||||
- [`sax_parse`](../api/basic_json/sax_parse.md) - parse with a SAX interface
|
||||
- [`json_view`](../api/json_view.md) - a non-owning view of a value in a document
|
||||
Reference in new issue
Block a user