Files
json/docs/mkdocs/docs/api/basic_json_document/save.md
Niels Lohmann 5a936a2ef3 Document the images of json_documents
Add API pages for basic_json_document::save() and load(), including the
image_check enumeration and its three levels. Add examples that show
caching a parsed document as an image, loading it without parsing, the
difference between a borrowed and an owned image, and a full check
rejecting a damaged image that a bounds check still reads safely.

Add an "Images" section to the json_view feature page, register the new
pages in mkdocs.yml and docSet.sql, group basic_json_document's member
list by parsing/access/images/edits, and document parse_error.116 and
type_error.320 on the exceptions page, extending out_of_range.416 for
images.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-29 14:03:21 +02:00

4.7 KiB

nlohmann::basic_json_document::save

std::vector<std::uint8_t> save() const;

Writes the document as an image: a byte buffer that load reads back without parsing. The image holds the node index, the source text (plus, for an edited document, the number tokens edits wrote), and the decoded strings (plus the strings edits wrote) -- everything root() needs, with nothing left to parse.

An edited document is written in its current state, with its values in document order, the way the library's own parser would have produced them for that JSON text: a member set added goes at the end, an erased member leaves no trace, and a float that is not finite (NaN or positive/negative infinity) becomes null, the same substitution dump() makes. The same document always saves to the same bytes -- also across BasicJsonType and #!cpp Editable, since the image reflects document order and values only, not which specialization produced them.

Return value

The image, as a #!cpp std::vector<std::uint8_t>. Pass it, or a pointer to its data together with its size, to load to read the document back.

Exception safety

Strong guarantee: save() does not modify #!cpp *this (it is #!cpp const), so if it throws, the document is left exactly as it was, and the partially built image is discarded with the exception.

Exceptions

Throws type_error.320 if the document is discarded -- a default-constructed document, or one a failed parse()/ read() with allow_exceptions == false left discarded.

On a big-endian target, throws type_error.320 with a different message instead: the image format is little-endian only (see Notes).

Throws out_of_range.416 if the node count, the text, or the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets parse() and, for edits, set/push_back are already limited to.

!!! failure "Example messages"

```
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
```
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
```

Complexity

Linear in the size of the document: the number of nodes, plus the length of the text and the decoded strings that end up in the image.

Notes

Format. The image begins with a 64-byte header (the magic bytes #!cpp "NJVI", a version number, the node count, and the sizes of the text and the decoded strings, all little-endian), followed by the nodes (16 bytes each), the text and a #!cpp '\0', and the decoded strings and a #!cpp '\0'. load checks the header, and the sizes it describes, before reading anything else -- see load's Exceptions.

!!! warning "Experimental"

The image format is versioned but not yet stable: it may change in an incompatible way before it is declared
stable. Use images to cache a document within one build of the library, or to hand one to another process running
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
JSON text if you need to read a saved document back with a future library version.

Little-endian only. The image is written as raw little-endian bytes, with no byte-swapping. save() (and load) throw type_error.320 on a big-endian target rather than silently produce bytes a big-endian reader could not interpret correctly.

Examples

??? example "Caching a parsed document as an image"

The example below saves a parsed configuration as an image -- the way a service might cache one to answer later
requests without parsing the text again -- and confirms that loading it back gives exactly the same result as
parsing did, and that saving is deterministic.

```cpp
--8<-- "examples/basic_json_document__save.cpp"
```

Output:

```json
--8<-- "examples/basic_json_document__save.output"
```

See also

  • load - read an image written by save()
  • owns_source - return whether the document holds its own copy of the text
  • basic_json_view::dump - serialize the document to JSON text instead of an image
  • Images - why and when to use images

Version history

  • Added in version 3.13.0.