Files
json/features/json_view/images.md
T
2026-11-09 18:59:22 +00:00

4.8 KiB

Images

save() writes a document as an image: a byte buffer that load() reads back into a document without parsing — no lexing, no building the node index, nothing but copying the nodes and pointing the text and the decoded strings at the image. Where parse_copy() still has to scan the whole input, load() turns that scan into a copy of the node index alone.

Why

A document that is parsed once and then read many times — a configuration loaded at startup, a template rendered on every request, a large reference dataset a worker process needs in memory — pays for parsing once but can amortize save()'s cost across every later load. That makes images useful for a cache: save a document the first time it is parsed (to a file, a shared-memory segment, an in-process cache), and load() it on every later use instead of parsing the source text again. They are just as useful for handing a parsed document to another process (or a forked worker) running the same build of the library, since load() turns the transfer into a copy of the node index plus pointers into the received bytes, not a re-parse.

Choosing a check

load() takes an image_check that trades validation against speed:

  • image_check::full (the default) checks everything the parser itself guarantees, so a checked image is exactly as safe to read and serialize as a freshly parsed document — the right choice whenever the image did not come straight from this process's own save(), such as a file or a network peer.
  • image_check::bounds only checks structure and bounds — cheaper, since it skips scanning the text and the decoded strings — and fits a cache the process trusts, one it wrote and reads back itself.
  • image_check::none skips validation entirely, for an image trusted as much as the process's own memory.

See load()'s Notes for exactly what each level does and does not guarantee.

??? example "Example: cache a parsed configuration as an image"

```cpp
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
#include <nlohmann/json_view.hpp>

using nlohmann::json_document;

int main()
{
    std::cout << std::boolalpha;

    // a configuration a service parses once and then caches as an image, so
    // that later requests can load() it instead of parsing the text again
    const std::string text = R"({"name": "cache", "host": "db1", "port": 6379, "replicas": ["db2", "db3"]})";
    const json_document config = json_document::parse(text);

    // save() turns the parsed document into a byte buffer: a 64-byte header,
    // the node index, the source text, and the decoded strings
    const std::vector<std::uint8_t> image = config.save();
    std::cout << image.size() << '\n';

    // the same document always saves to the same bytes
    std::cout << (image == json_document::parse(text).save()) << '\n';

    // loading the image back needs no parsing, yet dumps exactly what
    // parsing the text produced
    const json_document reloaded = json_document::load(image);
    std::cout << (reloaded.root().dump() == config.root().dump()) << '\n';
}

```

Output:

```json
316
true
true

```

!!! warning "Experimental"

The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the
library build that wrote it — use it to cache a document or to hand one to another process running the *same*
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
a future library version.

Credits

The idea of a document you can read without parsing comes from zero-copy formats such as FlatBuffers and YaFF; the check load() runs follows the idea of FlatBuffers' Verifier. No code is taken from either.

See also

Version history

  • Added in version 3.13.0.