Compare commits

..
Author SHA1 Message Date
Niels Lohmann 7857e2a015 Merge branch 'develop' into claude/json-view-docs-split-48c8e0
Port the json_view.md change of #6017 (reading a file into a string)
into json_view/differences.md, and point the links to json_view.md that
develop added in files.md, performance.md and parsing/index.md at
json_view/index.md.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-06 09:23:29 +01:00
Niels Lohmann 51134ac7fc Docs: fix stale comments and trim repeated text in json_view pages
- fig-jsonview.js/.css: point the header comments at the new pages
- reading.md: views' strings are valid as long as the document (and a
  borrowed source text), as lifetime.md says
- reading.md, generic_code.md: link to differences.md instead of
  restating the member-order and repeated-key rules
- differences.md: drop the third mention of ordering comparisons, name
  rbegin()/rend() in the iterator row
- exceptions.md: link editable documents to editing.md

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-05 21:21:07 +01:00
Niels Lohmann 9d532b381d Merge branch 'develop' into claude/json-view-docs-split-48c8e0
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-03 17:44:02 +01:00
Niels Lohmann f64464daf1 Split the json_view feature page into sub-pages
The single features/json_view.md page grew to ~600 lines covering eight
topics. Split it into features/json_view/ with an overview page and
pages for ownership and lifetime, differences from basic_json, reading
values, generic code, editing, and images.

The new differences page collects what was spread over several sections
("What is the same", "What is different", "Duplicate keys", and notes in
the conversion and serialization sections) under one summary table, and
adds the parts of the basic_json interface a view does not have. The
other pages now link to it instead of restating the rules.

Internal links across the documentation point to the new pages.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 20:42:55 +01:00
130 changed files with 909 additions and 75259 deletions

No files matched your search

+2 -2
View File
@@ -50,7 +50,7 @@ Besides `basic_json`, the library offers a second way to hold a parsed JSON text
[`basic_json_document`](../basic_json_document/index.md), which owns or borrows the text and holds a flat index of the
values in it, and a [`basic_json_view`](../basic_json_view/index.md), a read-only handle to one value of such a document.
Both are defined in the header `<nlohmann/json_view.hpp>`; see
[Zero-copy JSON views](../../features/json_view.md) for the concept and the trade-offs.
[Zero-copy JSON views](../../features/json_view/index.md) for the concept and the trade-offs.
- [**json_document**](../json_document.md) / [**ordered_json_document**](../ordered_json_document.md) - read-only
documents of the `basic_json` specialization they belong to
@@ -363,7 +363,7 @@ Access to the JSON value
specification of the JSON data interchange format
- [`basic_json_document`](../basic_json_document/index.md) - / [`basic_json_view`](../basic_json_view/index.md) - parse a JSON
text into a flat index and read it through a view
- [Zero-copy JSON views](../../features/json_view.md) - when to use a document and a view instead of a `basic_json`
- [Zero-copy JSON views](../../features/json_view/index.md) - when to use a document and a view instead of a `basic_json`
- [Types](../../features/types/index.md) - how JSON values are stored and which types exist
- [Converting values](../../features/conversions.md) - get values out of a JSON value and put values in
- [Creating JSON values](../../features/creating_values.md) - all the ways to build a JSON value
+1 -1
View File
@@ -124,7 +124,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by
[`basic_json_document::parse`](../basic_json_document/parse.md) accepts the same inputs and the same options, but
keeps the result as a flat index of the parsed values instead of a tree of `basic_json` values. It is faster and uses
less memory when only parts of the document are read, and it also accepts a pointer to a null-terminated wide string,
which `parse()` does not. See [Zero-copy JSON views](../../features/json_view.md).
which `parse()` does not. See [Zero-copy JSON views](../../features/json_view/index.md).
!!! tip "Performance"
@@ -77,7 +77,7 @@ compile; see [`parse`](parse.md#notes).
- [`parse`](parse.md) - deserialize from a compatible input
- [`BasicJsonType::accept`](../basic_json/accept.md) - the corresponding function of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#what-is-the-same-as-parse) - how parsing a document differs from, and matches, basic_json::parse
- [Zero-copy JSON views](../../features/json_view/differences.md#what-is-the-same) - how parsing a document differs from, and matches, basic_json::parse
## Version history
@@ -52,7 +52,7 @@ Constant.
- [`parse`](parse.md) - deserialize from a compatible input
- [`is_discarded`](is_discarded.md) - return whether the last parse failed
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - who owns the source text and for how long
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - who owns the source text and for how long
## Version history
@@ -123,7 +123,7 @@ by an erase, not only those at or after the removed element, since the container
- [`root`](root.md) - the view of the root value, the starting point of overload 3
- [`BasicJsonType::erase`](../basic_json/erase.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
- [Zero-copy JSON views](../../features/json_view.md#editing-a-document) - what an edit guarantees and costs
- [Zero-copy JSON views](../../features/json_view/editing.md) - what an edit guarantees and costs
## Version history
@@ -109,7 +109,7 @@ points apply to every edit:
anything `BasicJsonType` can be constructed from (numbers, strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
- [`dump()`](../basic_json_view/dump.md) writes an edited document with members in document order, new members at
the end, and, with [`number_format::source`](../basic_json_view/number_format.md), keeps the spelling of every
number that was not itself edited — see [Editing a document](../../features/json_view.md#editing-a-document) for
number that was not itself edited — see [Editing a document](../../features/json_view/editing.md) for
why this matters.
- [`read()`](read.md) discards all edits, [`shrink_to_fit()`](shrink_to_fit.md) does not move the node index once
there are edits, and [`memory_usage()`](memory_usage.md) includes the memory edits use.
@@ -118,7 +118,7 @@ points apply to every edit:
## See also
- [Zero-copy JSON views](../../features/json_view.md) - guide to documents and views
- [Zero-copy JSON views](../../features/json_view/index.md) - guide to documents and views
- [`basic_json_view`](../basic_json_view/index.md) - the non-owning handle to a value in a document
- [`json_document`](../json_document.md) - and [`json_editable_document`](../json_editable_document.md) - the default specializations
- [`materialize`](../basic_json_view/materialize.md) - build a `basic_json` value from a view
@@ -108,7 +108,7 @@ an edit in general.
- [`set`](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
- [`BasicJsonType::insert`](../basic_json/insert.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
- [Zero-copy JSON views](../../features/json_view.md#editing-a-document) - what an edit guarantees and costs
- [Zero-copy JSON views](../../features/json_view/editing.md) - what an edit guarantees and costs
## Version history
@@ -43,7 +43,7 @@ When the document is discarded, [`root()`](root.md) returns a discarded view (it
- [`parse`](parse.md) - deserialize from a compatible input
- [`basic_json_view::is_discarded`](../basic_json_view/is_discarded.md) - return whether a view is invalid
- [Zero-copy JSON views](../../features/json_view.md#what-is-the-same-as-parse) - how a discarded document arises
- [Zero-copy JSON views](../../features/json_view/differences.md#what-is-the-same) - how a discarded document arises
## Version history
@@ -24,7 +24,7 @@ static basic_json_document load(std::vector<std::uint8_t>&& image,
In every overload, the node index is copied into storage the document itself owns — so that it is properly aligned,
and, for an [editable](index.md#edits) document, can be edited — while the text and the decoded strings stay in
`image`. The hash indexes [large objects](../../features/json_view.md) use for lookup are rebuilt, exactly as after
`image`. The hash indexes [large objects](../../features/json_view/index.md) use for lookup are rebuilt, exactly as after
parsing.
## Parameters
@@ -172,7 +172,7 @@ returned document, and any [view](../basic_json_view/index.md) taken from it, is
- [`save`](save.md) - write the document as an image
- [`owns_source`](owns_source.md) - return whether the document holds its own copy of the text
- [`parse`](parse.md) - deserialize from JSON text instead of an image
- [Images](../../features/json_view.md#images) - why and when to use images
- [Images](../../features/json_view/images.md) - why and when to use images
## Version history
@@ -44,7 +44,7 @@ to observe the effect of [`shrink_to_fit()`](shrink_to_fit.md).
- [`node_count`](node_count.md) - the number of index entries
- [`shrink_to_fit`](shrink_to_fit.md) - release unused index capacity
- [Zero-copy JSON views](../../features/json_view.md#the-idea) - the flat node index and its memory
- [Zero-copy JSON views](../../features/json_view/index.md#the-idea) - the flat node index and its memory
## Version history
@@ -43,7 +43,7 @@ strings and, for an owned document, the text).
- [`memory_usage`](memory_usage.md) - the number of bytes held by the document
- [`shrink_to_fit`](shrink_to_fit.md) - release unused index capacity
- [Zero-copy JSON views](../../features/json_view.md#the-idea) - the flat node index and its memory
- [Zero-copy JSON views](../../features/json_view/index.md#the-idea) - the flat node index and its memory
## Version history
@@ -43,7 +43,7 @@ document (`#!cpp owns_source() == false`) is only valid while the buffer it was
- [`parse`](parse.md) - deserialize from a compatible input
- [`parse_copy`](parse_copy.md) - deserialize a copy of a compatible input, always owned
- [`source`](source.md) - the parsed text
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - who owns the source text and for how long
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - who owns the source text and for how long
## Version history
@@ -112,7 +112,7 @@ told apart from other class-type iterators, so their range is read into an owned
range (e.g. of a `#!cpp std::list<char>`).
See [`owns_source`](owns_source.md) to check which happened after a call, and the
[feature page](../../features/json_view.md) for the reasoning.
[feature page](../../features/json_view/index.md) for the reasoning.
**Numbers.** As for [`BasicJsonType::parse()`](../basic_json/parse.md), an integer literal too large for the 64-bit
integer type becomes a floating-point value.
@@ -74,7 +74,7 @@ compile; see [`parse`](parse.md#notes).
- [`parse`](parse.md) - deserialize from a compatible input, borrowing it where possible
- [`owns_source`](owns_source.md) - return whether the document holds its own copy of the text
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - borrowing or copying the source text
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - borrowing or copying the source text
## Version history
@@ -96,7 +96,7 @@ Like [`set`](set.md) on a member or an element, `push_back` never moves an exist
- [`root`](root.md) - the view of the root value
- [`BasicJsonType::push_back`](../basic_json/push_back.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
- [Zero-copy JSON views](../../features/json_view.md#editing-a-document) - what an edit guarantees and costs
- [Zero-copy JSON views](../../features/json_view/editing.md) - what an edit guarantees and costs
## Version history
@@ -81,7 +81,7 @@ compile; see [`parse`](parse.md#notes).
- [`parse`](parse.md) - deserialize from a compatible input
- [`root`](root.md) - the view of the root value
- [`load`](load.md) - read a document from an image instead of parsing JSON text
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - reusing a document and what it invalidates
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - reusing a document and what it invalidates
## Version history
@@ -40,7 +40,7 @@ auto v = doc.root();
returned view is valid under the same conditions as any other view of the document — see
[Object inspection](../basic_json_view/index.md) — in particular, it is invalidated by the next
[`read()`](read.md) or [`shrink_to_fit()`](shrink_to_fit.md) on this document. A view can dangle, like a
`#!cpp std::string_view`; see [Ownership and lifetime](../../features/json_view.md#ownership-and-lifetime).
`#!cpp std::string_view`; see [Ownership and lifetime](../../features/json_view/lifetime.md).
## Examples
@@ -91,7 +91,7 @@ big-endian reader could not interpret correctly.
- [`load`](load.md) - read an image written by `save()`
- [`owns_source`](owns_source.md) - return whether the document holds its own copy of the text
- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document to JSON text instead of an image
- [Images](../../features/json_view.md#images) - why and when to use images
- [Images](../../features/json_view/images.md) - why and when to use images
## Version history
@@ -195,7 +195,7 @@ one-node scalar.
- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document, keeping an untouched number's
spelling with `#!cpp number_format::source`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
- [Editing a document](../../features/json_view.md#editing-a-document) - why editable documents keep the source
- [Editing a document](../../features/json_view/editing.md) - why editable documents keep the source
text's order and number spelling
## Version history
@@ -56,7 +56,7 @@ possible would be an internal optimization only, not a guarantee to rely on.
- [`node_count`](node_count.md) - the number of index entries
- [`memory_usage`](memory_usage.md) - the number of bytes held by the document
- [`root`](root.md) - the view of the root value
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - what releasing memory invalidates
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - what releasing memory invalidates
## Version history
@@ -42,7 +42,7 @@ is; see [`owns_source`](owns_source.md).
- [`owns_source`](owns_source.md) - return whether the document holds its own copy of the text
- [`source_offset`](../basic_json_view/source_offset.md) - byte offset of a value in the source text
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - who owns the source text and for how long
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - who owns the source text and for how long
## Version history
+1 -1
View File
@@ -92,7 +92,7 @@ Pointer path of the value within the document, and with
If the source text repeats a key, this resolves to the *first* member with it, not to the last one that
[`materialize()`](materialize.md) and `parse()` keep. See the [Notes on duplicate keys](operator[].md#notes) of
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
`operator[]` and [Duplicate keys](../../features/json_view/differences.md#duplicate-keys) for the reasons and for how to get
the last value.
Unlike [`operator[]`](operator[].md), which returns a [discarded](is_discarded.md) view for a missing key or an
@@ -58,7 +58,7 @@ placeholder for "no value yet" and later be assigned a real view.
- [`is_discarded`](is_discarded.md) - return whether the view is invalid
- [`root`](../basic_json_document/root.md) - the view of a document's root value
- [`view_mode`](../view_mode.md) - whether a document and its views can be edited
- [Zero-copy JSON views](../../features/json_view.md#ownership-and-lifetime) - how long a view stays valid
- [Zero-copy JSON views](../../features/json_view/lifetime.md) - how long a view stays valid
## Version history
@@ -47,7 +47,7 @@ No-throw guarantee: this function never throws exceptions.
If the source text repeats a key, this resolves to the *first* member with it, not to the last one that
[`materialize()`](materialize.md) and `parse()` keep. See the [Notes on duplicate keys](operator[].md#notes) of
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
`operator[]` and [Duplicate keys](../../features/json_view/differences.md#duplicate-keys) for the reasons and for how to get
the last value.
Overload 1 always returns `#!cpp false` when the value is not an object — including a [discarded](is_discarded.md)
+2 -2
View File
@@ -70,7 +70,7 @@ except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
for `#!cpp -0` — `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
digits than any number type holds (such a literal is itself classified as a float, see
[What is different](../../features/json_view.md#what-is-different)) — something `BasicJsonType` cannot do, since
[What is different](../../features/json_view/differences.md)) — something `BasicJsonType` cannot do, since
parsing already reduces every number to its parsed value.
## Examples
@@ -98,7 +98,7 @@ parsing already reduces every number to its parsed value.
- [`operator<<`](operator_ltlt.md) - serialize this value to a stream
- [`materialize`](materialize.md) - build a `BasicJsonType` value, e.g. to use `BasicJsonType::dump`'s `error_handler`
- [`BasicJsonType::dump`](../basic_json/dump.md) - the corresponding function of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#writing-a-view-back) - writing a view back without building a tree
- [Zero-copy JSON views](../../features/json_view/reading.md#writing-a-view-back) - writing a view back without building a tree
## Version history
+1 -1
View File
@@ -37,7 +37,7 @@ constant time on average.
If the source text repeats a key, this resolves to the *first* member with it, not to the last one that
[`materialize()`](materialize.md) and `parse()` keep. See the [Notes on duplicate keys](operator[].md#notes) of
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
`operator[]` and [Duplicate keys](../../features/json_view/differences.md#duplicate-keys) for the reasons and for how to get
the last value.
Unlike [`BasicJsonType::find`](../basic_json/find.md), which always returns `#!cpp end()` for a non-object type, this
+3 -3
View File
@@ -39,14 +39,14 @@ as [`BasicJsonType::parse()`](../basic_json/parse.md) does), as well as the type
accept views, e.g. with [`is_json_view`](../is_json_view.md). A `from_json()` that also accepts types that are no JSON
values at all, such as the unconstrained `#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType&,
T&)` of [arbitrary type conversions](../../features/arbitrary_types.md), is not called with a view: it may use
`BasicJsonType` functions a view does not have. See [Writing generic code](../../features/json_view.md#writing-generic-code).
`BasicJsonType` functions a view does not have. See [Writing generic code](../../features/json_view/generic_code.md).
!!! warning "Duplicate keys"
Such a `from_json()` looks members up in the view, where a repeated key finds the **first** member, while
`#!cpp materialize().get<T>()` sees the **last** one, as [`BasicJsonType::parse()`](../basic_json/parse.md)
keeps it: for `#!cpp {"x":1,"x":2}`, `#!cpp get<point>()` reads `#!cpp x == 1`. See
[Duplicate keys](../../features/json_view.md#duplicate-keys).
[Duplicate keys](../../features/json_view/differences.md#duplicate-keys).
Every other `T` — user types whose `from_json()` is written for `BasicJsonType` only, types without a default
constructor, `#!cpp std::tuple`s holding references, ... — is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
@@ -152,7 +152,7 @@ instead: its path is relative to the root of the view's subtree, because `materi
- [`number_token`](number_token.md) - a number's token text, without a copy
- [`materialize`](materialize.md) - build the `BasicJsonType` value of this subtree
- [`BasicJsonType::get`](../basic_json/get.md) - the corresponding function of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#getting-values-out-without-copying) - which conversions avoid building a basic_json value
- [Zero-copy JSON views](../../features/json_view/reading.md#getting-values-out-without-copying) - which conversions avoid building a basic_json value
## Version history
@@ -70,7 +70,7 @@ since floating-point values and unescaped strings are read from the source lazil
- [`get`](get.md) - convert the value to a given type (`#!cpp get<string_view_t>()` is equivalent to this function)
- [`number_token`](number_token.md) - a number's token text, without a copy
- [`BasicJsonType::get_ref`](../basic_json/get_ref.md) - the closest counterpart of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#getting-values-out-without-copying) - borrowing strings instead of copying them
- [Zero-copy JSON views](../../features/json_view/reading.md#getting-values-out-without-copying) - borrowing strings instead of copying them
## Version history
@@ -75,7 +75,7 @@ them with those of a default-constructed `T`.
- [`get`](get.md) - convert the value to a given type
- [`BasicJsonType::get_to`](../basic_json/get_to.md) - the corresponding function of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#getting-values-out-without-copying) - which conversions avoid building a basic_json value
- [Zero-copy JSON views](../../features/json_view/reading.md#getting-values-out-without-copying) - which conversions avoid building a basic_json value
## Version history
@@ -147,7 +147,7 @@ still refers to it — including ones taken before the change — reads the new
## See also
- [Zero-copy JSON views](../../features/json_view.md) - guide to documents and views
- [Zero-copy JSON views](../../features/json_view/index.md) - guide to documents and views
- [`basic_json_document`](../basic_json_document/index.md) - the document that owns the parsed data
- [`json_view`](../json_view.md) - and [`json_editable_view`](../json_editable_view.md) - the default specializations
- [`materialize`](materialize.md) - build a `basic_json` value from a view
@@ -54,7 +54,7 @@ A `basic_json_view` is not convertible to `#!cpp bool`: such a conversion would
- [`(constructor)`](basic_json_view.md) - the default constructor creates a discarded view
- [`basic_json_document::is_discarded`](../basic_json_document/is_discarded.md) - return whether the last parse failed
- [`BasicJsonType::is_discarded`](../basic_json/is_discarded.md) - the corresponding function of `basic_json`
- [Zero-copy JSON views](../../features/json_view.md#what-is-different) - how views differ from basic_json
- [Zero-copy JSON views](../../features/json_view/differences.md) - how views differ from basic_json
## Version history
@@ -78,7 +78,7 @@ never caches the result.
- [`root`](../basic_json_document/root.md) - the view of a document's root value
- [`BasicJsonType::parse`](../basic_json/parse.md) - build a `BasicJsonType` value directly from a JSON text
- [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) - source positions on parsed values
- [Zero-copy JSON views](../../features/json_view.md#getting-values-out-without-copying) - when to build a basic_json value from a view
- [Zero-copy JSON views](../../features/json_view/reading.md#getting-values-out-without-copying) - when to build a basic_json value from a view
## Version history
@@ -45,7 +45,7 @@ source
- [`number_token`](number_token.md) - get a single number's token text without dumping the whole value
- [`BasicJsonType::error_handler_t`](../basic_json/error_handler_t.md) - the analogous enumeration for
`BasicJsonType::dump`'s decoding-error behavior
- [Zero-copy JSON views](../../features/json_view.md#writing-a-view-back) - writing numbers as they appeared in the source
- [Zero-copy JSON views](../../features/json_view/reading.md#writing-a-view-back) - writing numbers as they appeared in the source
## Version history
@@ -68,7 +68,7 @@ buffer — and is valid exactly as long as that text is, see the [validity rules
- [`BasicJsonType::number_integer_t`](../basic_json/number_integer_t.md),
[`number_unsigned_t`](../basic_json/number_unsigned_t.md), [`number_float_t`](../basic_json/number_float_t.md) - the
number types `#!cpp get<T>()` and `materialize()` convert into
- [Zero-copy JSON views](../../features/json_view.md#getting-values-out-without-copying) - reading a number exactly as written
- [Zero-copy JSON views](../../features/json_view/reading.md#getting-values-out-without-copying) - reading a number exactly as written
## Version history
@@ -120,7 +120,7 @@ document.
[`materialize()`](materialize.md) or iterate the members with [`items()`](items.md) and keep the last match.
The key hash index of a larger object (128 members or more) leads to the first member of a key as well.
[`begin()`](begin.md)/[`end()`](end.md) and [`items()`](items.md) iterate over *all* members, including
duplicates, in document order. See [Duplicate keys](../../features/json_view.md#duplicate-keys) and
duplicates, in document order. See [Duplicate keys](../../features/json_view/differences.md#duplicate-keys) and
[`size()`](size.md#notes).
!!! info "JSON pointer resolution"
@@ -19,7 +19,7 @@ Neither overload builds a `BasicJsonType` value for a view to do the comparison
compare by value across their types (`#!cpp 1 == 1.0`), and an object compares by its members, with duplicate keys
resolved exactly as `parse()` resolves them — the last value, at the position of the first occurrence of the key.
This is not what [`operator[]`](operator[].md) and the other lookups return for a duplicate key: they find the *first*
member (see [Duplicate keys](../../features/json_view.md#duplicate-keys)).
member (see [Duplicate keys](../../features/json_view/differences.md#duplicate-keys)).
## Parameters
@@ -68,7 +68,7 @@ Linear, as [`dump`](dump.md#complexity).
- [`dump`](dump.md) - serialize to a JSON-formatted string
- [`operator<<(std::ostream&)`](../operator_ltlt.md) - the corresponding operator for `basic_json`
- [`JSON_NO_IO`](../macros/json_no_io.md) - switch off functions relying on certain C++ I/O headers
- [Zero-copy JSON views](../../features/json_view.md#writing-a-view-back) - writing a view back without building a tree
- [Zero-copy JSON views](../../features/json_view/reading.md#writing-a-view-back) - writing a view back without building a tree
## Version history
@@ -49,7 +49,7 @@ string, whose token length is not the same as its decoded [`size()`](size.md).
- [`source`](../basic_json_document/source.md) - the parsed text
- [`is_string`](is_string.md) - return whether the value is a string
- [Zero-copy JSON views](../../features/json_view.md#images) - images and the source text
- [Zero-copy JSON views](../../features/json_view/images.md) - images and the source text
## Version history
@@ -84,7 +84,7 @@ Pointer path of the value within the document, and with
If the source text repeats a key, this resolves to the *first* member with it, not to the last one that
[`materialize()`](materialize.md) and `parse()` keep. See the [Notes on duplicate keys](operator[].md#notes) of
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
`operator[]` and [Duplicate keys](../../features/json_view/differences.md#duplicate-keys) for the reasons and for how to get
the last value.
!!! info "Differences to `at` and `operator[]`"
+1 -1
View File
@@ -49,7 +49,7 @@ view class.
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
- [get](basic_json_view/get.md) - which conversions read the view directly
- [view_mode](view_mode.md) - read-only or editable
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions and `from_json()` for views
- [Writing generic code](../features/json_view/generic_code.md) - functions and `from_json()` for views
## Version history
+1 -1
View File
@@ -29,7 +29,7 @@ specialization.
- [`json_view`](json_view.md) - a view of a value of a `json_document`
- [`ordered_json_document`](ordered_json_document.md) - the corresponding document for `ordered_json`
- [Zero-copy JSON views](../features/json_view.md) - how to parse, inspect and edit a document without building a tree
- [Zero-copy JSON views](../features/json_view/index.md) - how to parse, inspect and edit a document without building a tree
## Version history
@@ -10,7 +10,7 @@ This type is an **editable** [`basic_json_document`](basic_json_document/index.m
[`json`](json.md) specialization: in addition to everything [`json_document`](json_document.md) offers,
[`set`](basic_json_document/set.md) and [`push_back`](basic_json_document/push_back.md) change values after
parsing, without ever rewriting the source text — see [Edits](basic_json_document/index.md#edits) and
[Editing a document](../features/json_view.md#editing-a-document).
[Editing a document](../features/json_view/editing.md).
## Examples
+1 -1
View File
@@ -35,7 +35,7 @@ still referring to it seeing the change, see [Edits](basic_json_document/index.m
- [`json_view`](json_view.md) - the corresponding read-only view
- [`ordered_json_editable_view`](ordered_json_editable_view.md) - the corresponding view for
`ordered_json_editable_document`
- [Zero-copy JSON views](../features/json_view.md#editing-a-document) - editing a document in place and writing it back
- [Zero-copy JSON views](../features/json_view/editing.md) - editing a document in place and writing it back
## Version history
+1 -1
View File
@@ -28,7 +28,7 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a [`j
- [`json_document`](json_document.md) - the document type this view refers into
- [`ordered_json_view`](ordered_json_view.md) - the corresponding view for `ordered_json_document`
- [Zero-copy JSON views](../features/json_view.md) - how to parse, inspect and edit a document without building a tree
- [Zero-copy JSON views](../features/json_view/index.md) - how to parse, inspect and edit a document without building a tree
## Version history
@@ -5,9 +5,7 @@
```
When defined to `1`, parsing from a `#!cpp FILE*` reads every character with `std::fgetc`, as in version 3.12.0 and
earlier, instead of locking the file once and reading it with the unlocked stdio functions. This also turns off the
scan of the `FILE`'s buffer in bulk (see below), which [`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)
does not affect.
earlier, instead of locking the file once and reading it with the unlocked stdio functions.
It does not change any result: values, exceptions, and the position of the file after parsing are the same either way.
Only the speed and the locking of the file differ (see the notes on locking below).
@@ -39,17 +37,9 @@ The default value is `0`: the file is locked once and read with the unlocked std
| Microsoft (MSVC, clang-cl) | `_lock_file`, `_fgetc_nolock`, `_unlock_file` |
| others (e.g., musl, MinGW, newlib) | `std::fgetc`, as before |
With glibc and the Apple C library, the parser also scans the characters that the `FILE` already holds in its
buffer in bulk, as it scans the get area of a stream (see
[`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)): it reads the same fields of the `FILE` that
the C library's own `getc_unlocked` reads, and it consumes exactly the characters that `getc_unlocked` would have
returned, so the file is left where it was left before.
Locking the file once makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3
times as fast with glibc, whose locking is cheaper. Scanning the buffer in bulk makes `parse()` another 1.7 to 2.6
times as fast (and `accept()` 2.9 to 4.4 times), about as fast as parsing from a `std::ifstream`. The binary
formats ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md), ...) read
from a `FILE*` the same way.
This makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with
glibc, whose locking is cheaper. The binary formats ([`from_cbor`](../basic_json/from_cbor.md),
[`from_msgpack`](../basic_json/from_msgpack.md), ...) read from a `FILE*` the same way.
!!! note "Locking"
+1 -1
View File
@@ -80,7 +80,7 @@ By default, `#!cpp JSON_NO_SIMD` is not defined, and vector instructions are use
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance) - how input
sources affect parsing performance
- [Serialization](../../features/serialization.md) - pretty-printing, UTF-8 handling, and number output
- [Zero-copy JSON views](../../features/json_view.md) - the zero-copy view, whose parser the macro also affects
- [Zero-copy JSON views](../../features/json_view/index.md) - the zero-copy view, whose parser the macro also affects
## Version history
@@ -32,7 +32,7 @@ of object keys, instead of sorting them like [`json_document`](json_document.md)
- [`ordered_json_view`](ordered_json_view.md) - a view of a value of an `ordered_json_document`
- [`json_document`](json_document.md) - the corresponding document for the default `json` specialization
- [Object Order](../features/object_order.md) - preserving the insertion order of object keys
- [Zero-copy JSON views](../features/json_view.md) - how to parse, inspect and edit a document without building a tree
- [Zero-copy JSON views](../features/json_view/index.md) - how to parse, inspect and edit a document without building a tree
## Version history
@@ -41,7 +41,7 @@ members [`set`](basic_json_document/set.md) added — instead of sorting them li
specialization
- [Object Order](../features/object_order.md) - preserving the insertion order of object keys
- [Edits](basic_json_document/index.md#edits) - what an edit guarantees
- [Zero-copy JSON views](../features/json_view.md#editing-a-document) - editing a document in place and writing it back
- [Zero-copy JSON views](../features/json_view/editing.md) - editing a document in place and writing it back
## Version history
@@ -34,7 +34,7 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
- [`ordered_json_editable_document`](ordered_json_editable_document.md) - the document type this view refers into
- [`ordered_json_view`](ordered_json_view.md) - the corresponding read-only view
- [`json_editable_view`](json_editable_view.md) - the corresponding view for `json_editable_document`
- [Zero-copy JSON views](../features/json_view.md#editing-a-document) - editing a document in place and writing it back
- [Zero-copy JSON views](../features/json_view/editing.md) - editing a document in place and writing it back
## Version history
+1 -1
View File
@@ -29,7 +29,7 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
- [`ordered_json_document`](ordered_json_document.md) - the document type this view refers into
- [`json_view`](json_view.md) - the corresponding view for `json_document`
- [Zero-copy JSON views](../features/json_view.md) - how to parse, inspect and edit a document without building a tree
- [Zero-copy JSON views](../features/json_view/index.md) - how to parse, inspect and edit a document without building a tree
## Version history
+1 -1
View File
@@ -82,7 +82,7 @@ nor a [`json_editable_view`](json_editable_view.md). Views of the two modes comp
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
- [json_editable_document](json_editable_document.md) - an editable document of `json`
- [(constructor)](basic_json_view/basic_json_view.md) - the conversion from a read-only to an editable view
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions that accept views
- [Writing generic code](../features/json_view/generic_code.md) - functions that accept views
## Version history
+1 -25
View File
@@ -759,14 +759,9 @@ body:has(.nj-hero) .md-content {
}
}
/* blog posts: author and date right below the title */
.md-typeset .nj-byline { margin: -.8rem 0 1.6rem; font-size: .75rem; color: var(--md-default-fg-color--light); }
.md-typeset .nj-byline a { color: inherit; }
.md-typeset .nj-byline a:hover { color: var(--md-accent-fg-color); }
/* figure captions: "Figure N." in bold, close to the figure, set in from the text column; figures and tables are
numbered per page, each with its own counter */
.md-content__inner { counter-reset: nj-figure nj-table nj-listing; }
.md-content__inner { counter-reset: nj-figure nj-table; }
.md-typeset :is(.nj-caption, .nj-charts-caption) {
max-width: none;
margin: .3rem 2rem 1.5rem;
@@ -787,25 +782,6 @@ body:has(.nj-hero) .md-content {
.md-typeset :is(.nj-caption, .nj-charts-caption) { margin-inline: 1rem; }
}
/* code captions: "Listing N." in bold, directly below the code block, in the figure caption style */
.md-typeset .nj-code-caption {
max-width: none;
margin: -.4rem 2rem 1.5rem;
font-size: .75rem;
line-height: 1.5;
text-align: left;
color: var(--md-default-fg-color--light);
}
.md-typeset .nj-code-caption::before {
counter-increment: nj-listing;
content: "Listing " counter(nj-listing) ". ";
font-weight: 700;
color: var(--md-default-fg-color);
}
@media screen and (max-width: 44.9375em) {
.md-typeset .nj-code-caption { margin-inline: 1rem; }
}
/* table captions: "Table N." in bold, directly below the table, in the figure caption style */
.md-typeset .nj-table-caption {
max-width: none;
-44
View File
@@ -27,10 +27,6 @@
.md-typeset svg.nj-charts--compile, .md-typeset svg.nj-charts--scaling { max-width: 26rem; }
.md-typeset svg.nj-charts--sizes { max-width: 26rem; }
/* home/blog/how_3_13_0_got_faster.md (scripts/figures/perf_blog.py) */
.md-typeset svg.nj-charts--blog { max-width: 34rem; }
.md-typeset svg.nj-charts--swar { max-width: 34rem; }
.md-typeset svg.nj-charts--timeline { max-width: 22rem; }
.nj-charts text { fill: currentColor; font-size: 13px; }
.nj-charts .nj-charts-leg { font-size: 13.5px; }
@@ -47,34 +43,10 @@
paint-order: stroke; stroke: var(--md-default-bg-color); stroke-width: 4px; stroke-linejoin: round; }
.nj-charts .nj-charts-factor { fill: var(--nj-charts-ink2); font-size: 12px; font-weight: 600; text-anchor: middle; }
.nj-charts .nj-charts-note { fill: var(--nj-charts-ink2); font-size: 12px; }
/* heatmap cells (perf_blog_usecases_*.svg): green for the fastest, gray around twice the time, red for the slowest;
adjacent steps checked for CVD separation on the light and the slate surface; the numbers are in every cell */
.md-typeset svg.nj-charts--heat { max-width: 49rem; }
.nj-charts--heat { --nj-heat-0: #3fa557; --nj-heat-1: #8bcc95; --nj-heat-2: #ebeae6; --nj-heat-3: #f2ae9b;
--nj-heat-4: #dc5a43; --nj-heat-ink: #1b1b1b; --nj-heat-ink-strong: #1b1b1b; }
[data-md-color-scheme="slate"] .nj-charts--heat { --nj-heat-0: #3a9d50; --nj-heat-1: #2c6b3a; --nj-heat-2: #33353a;
--nj-heat-3: #8a3f2e; --nj-heat-4: #d95b3a; --nj-heat-ink: #e8e8e6; --nj-heat-ink-strong: #141414; }
.nj-charts .nj-heat-0 { fill: var(--nj-heat-0); }
.nj-charts .nj-heat-1 { fill: var(--nj-heat-1); }
.nj-charts .nj-heat-2 { fill: var(--nj-heat-2); }
.nj-charts .nj-heat-3 { fill: var(--nj-heat-3); }
.nj-charts .nj-heat-4 { fill: var(--nj-heat-4); }
.nj-charts .nj-heat-na { fill: none; stroke: var(--nj-charts-grid); stroke-width: 1; }
.nj-charts .nj-charts-cell { fill: var(--nj-heat-ink); font-size: 12px; font-variant-numeric: tabular-nums; }
.nj-charts :is(.nj-heat-0, .nj-heat-4) ~ .nj-charts-cell { fill: var(--nj-heat-ink-strong); }
.nj-charts .nj-charts-cell--small { font-size: 10.5px; }
.nj-charts .nj-heat-cell { cursor: default; outline: none; }
.nj-charts .nj-heat-cell:is(:hover, :focus-visible, .nj-heat-on) rect { stroke: var(--md-default-fg-color); stroke-width: 1.5; }
.nj-heat-tip { position: absolute; z-index: 5; max-width: 24rem; padding: .5rem .7rem; border-radius: 6px;
background: var(--md-default-bg-color); color: var(--md-default-fg-color);
box-shadow: 0 2px 10px rgba(0, 0, 0, .25); font-size: .68rem; line-height: 1.45; pointer-events: none; }
.nj-heat-tip strong { display: block; margin-bottom: .2rem; }
.nj-heat-tip[hidden] { display: none; }
.nj-charts .nj-charts-grid { stroke: var(--nj-charts-grid); stroke-width: 1; }
.nj-charts .nj-charts-zero, .nj-charts .nj-charts-axis { stroke: var(--nj-charts-base); stroke-width: 1.5; }
.nj-charts .nj-charts-ref { stroke: currentColor; stroke-width: 1.5; }
.nj-charts .nj-charts-head { fill: var(--nj-charts-base); }
.nj-charts .nj-charts-c1 { fill: var(--nj-charts-c1); }
.nj-charts .nj-charts-c2 { fill: var(--nj-charts-c2); }
@@ -168,19 +140,3 @@
/* direct line labels replace the legend */
.nj-charts .nj-charts-name-json { fill: var(--nj-charts-json-c); font-weight: 600; }
.nj-charts .nj-charts-name-ojson { fill: var(--nj-charts-ojson-c); font-weight: 600; }
/* theme badges of home/blog/how_3_13_0_got_faster.md: the number of one of the eight themes, as a digit in a blue
circle, in headings, text, tables and the timeline figures (nj-theme-dot); "U" and other marks are gray */
.md-typeset .nj-theme { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;
min-width: 1.45em; height: 1.45em; padding: 0 .3em; border-radius: .725em; vertical-align: .08em;
background: var(--nj-blue); color: var(--md-default-bg-color); font-size: .78em; font-weight: 700; line-height: 1;
font-variant-numeric: tabular-nums; text-decoration: none; }
.md-typeset a.nj-theme:is(:hover, :focus-visible) { background: var(--nj-blue-deep); color: var(--md-default-bg-color); }
.md-typeset .nj-theme--other { background: var(--md-default-fg-color--light); }
.md-typeset h2 .nj-theme { margin-right: .35em; vertical-align: .12em; }
.md-typeset .nj-theme-list > ul { list-style: none; margin-left: 0; }
.md-typeset .nj-theme-list > ul > li { margin-left: 0; padding-left: 2em; text-indent: -2em; }
.md-typeset .nj-theme-list > ul > li > .nj-theme { margin-right: .55em; text-indent: 0; }
.nj-charts .nj-theme-dot { fill: var(--nj-blue); }
.nj-charts .nj-theme-dot--other { fill: var(--nj-charts-ink2); }
.nj-charts .nj-theme-num { fill: var(--md-default-bg-color); font-size: 11px; font-weight: 700; }
+1 -1
View File
@@ -1,4 +1,4 @@
/* figures: jsonview (features/json_view.md; SVGs from scripts/figures/json_view_layout.py, stepper in js/fig-jsonview.js) */
/* figures: jsonview (features/json_view/*.md; SVGs from scripts/figures/json_view_layout.py, stepper in js/fig-jsonview.js) */
/* one colour per concept, the same in every figure: structure (object/array, views) blue, keys navy, strings green,
numbers orange, decoded strings purple, owned edit storage teal, dangling/invalid red */
+2 -2
View File
@@ -48,7 +48,7 @@ which avoids repeating it:
[`number_token()`](../api/basic_json_view/number_token.md) returns a number exactly as it was written. Every other
type is obtained from a subtree that is built on demand with
[`materialize()`](../api/basic_json_view/materialize.md). See
[Zero-copy JSON views](json_view.md#getting-values-out-without-copying).
[Zero-copy JSON views](json_view/reading.md#getting-values-out-without-copying).
The library already knows how to convert to and from the scalar types and the STL containers (such as
`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::array`, `#!cpp std::optional`, and many more). Converting a JSON
@@ -269,7 +269,7 @@ The conversions above are built in for standard types. To make the same syntax w
- [`get_ref`](../api/basic_json/get_ref.md) - / [`get_ptr`](../api/basic_json/get_ptr.md) - access the stored value without copying
- [Arbitrary types conversions](arbitrary_types.md) - support your own types
- [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md) - toggle implicit conversions
- [Zero-copy JSON views](json_view.md) - get values out of a document or a view
- [Zero-copy JSON views](json_view/index.md) - get values out of a document or a view
- [`adl_serializer`](../api/adl_serializer/index.md) - the default serializer behind the conversions
- [`type`](../api/basic_json/type.md) - query the type of a value
- [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md) - toggle conversion to tuples of references
+2 -2
View File
@@ -3,7 +3,7 @@
There are several ways to create a JSON value in memory. This page gives an overview; to read a value from JSON text
instead, see [parsing](parsing/index.md). A JSON text can also be parsed into a
[document](../api/basic_json_document/index.md) and read through a [view](../api/basic_json_view/index.md) instead of
into a value; see [Zero-copy JSON views](json_view.md).
into a value; see [Zero-copy JSON views](json_view/index.md).
## From C++ values
@@ -122,7 +122,7 @@ string `#!json "42"`.
- [`operator""_json`](../api/operator_literal_json.md) - the `_json` literal
- [Converting values](conversions.md) - which C++ types can be used
- [Parsing](parsing/index.md) - create a value from JSON text
- [Zero-copy JSON views](json_view.md) - create a document and a view from JSON text instead of a value
- [Zero-copy JSON views](json_view/index.md) - create a document and a view from JSON text instead of a value
- [`basic_json`](../api/basic_json/index.md) - the class template and its member functions
- [Types](types/index.md) - the JSON value types
- [`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md) - change how a single braced value is interpreted
+1 -1
View File
@@ -37,7 +37,7 @@ json read_json_file(const std::string& path)
[input sources and performance](parsing/index.md#input-sources-and-performance)). The common way to read a file with
`#!cpp std::istreambuf_iterator<char>` is so slow that it takes about twice as long as parsing from the stream. Read
the file into a string only if you need the text itself, for example for an error message. This advice is for
`#!cpp json::parse`. [`json_document`](json_view.md) reads a stream into a buffer that it owns anyway, so there is no
`#!cpp json::parse`. [`json_document`](json_view/index.md) reads a stream into a buffer that it owns anyway, so there is no
copy to save: reading the file into a `#!cpp std::string` yourself and passing that as an lvalue, which the document
borrows, was about 6 to 12 % faster than parsing from the stream, with the same single buffer.
- `parse` requires the file to hold exactly one JSON value. Files with one value per line are read with
+3 -3
View File
@@ -13,10 +13,10 @@ C++ types, and finally serialize it again.
[SAX interface](parsing/sax_interface.md), [error handling](parsing/parse_exceptions.md),
[large and partial input](parsing/large_and_partial_input.md), and
[parsing untrusted input](parsing/untrusted_input.md).
- [Zero-copy JSON views](json_view.md) — read a JSON text through a flat index instead of building a `json` tree;
- [Zero-copy JSON views](json_view/index.md) — read a JSON text through a flat index instead of building a `json` tree;
strings and numbers stay in the input and are only decoded when needed.
- [Editable documents](json_view.md#editing-a-document) — modify a parsed document without building a `json` tree.
- [Images](json_view.md#images) — save a parsed document and load it again without parsing it.
- [Editable documents](json_view/editing.md) — modify a parsed document without building a `json` tree.
- [Images](json_view/images.md) — save a parsed document and load it again without parsing it.
- [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar.
## Accessing and modifying values
-591
View File
@@ -1,591 +0,0 @@
# Zero-copy JSON views
`#!cpp <nlohmann/json_view.hpp>` adds a read-only, non-owning way to look at a parsed JSON text, as an alternative to
building a [`basic_json`](../api/basic_json/index.md) tree with [`parse()`](../api/basic_json/parse.md).
## The problem
[`basic_json::parse()`](../api/basic_json/parse.md) builds a tree of `basic_json` values: one allocation for every
array and object, and every string copied into its own `std::string`. That is the right trade-off when the program
goes on to read and write the value freely, but it does more work than necessary when only a small part of a large
JSON text is actually needed, or when the same text is parsed over and over (many small messages, for instance) and
most of the resulting tree is thrown away almost immediately.
## The idea
[`basic_json_document::parse()`](../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
options, but instead of a tree it builds a flat index of the values it found: one
[16-byte entry](../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
order. Integers are converted while parsing and stored in their entry. Floating-point numbers and strings are
referenced in place in the source text: a float is converted when it is read, and only strings that contain escape
sequences are decoded, into one shared buffer owned by the document.
[`basic_json_view`](../api/basic_json_view/index.md) is a small, trivially copyable handle (two pointers) into that
index. It gives you the read-only, type-inspection part of the `basic_json` interface —
[`type()`](../api/basic_json_view/type.md) and the `is_*()` predicates,
[`size()`](../api/basic_json_view/size.md)/[`empty()`](../api/basic_json_view/empty.md) — as well as element access
([`operator[]`](../api/basic_json_view/operator%5B%5D.md), [`at`](../api/basic_json_view/at.md),
[`front`](../api/basic_json_view/front.md)/[`back`](../api/basic_json_view/back.md)), lookup
([`find`](../api/basic_json_view/find.md), [`contains`](../api/basic_json_view/contains.md),
[`count`](../api/basic_json_view/count.md)), and iteration
([`begin`](../api/basic_json_view/begin.md)/[`end`](../api/basic_json_view/end.md),
[`items`](../api/basic_json_view/items.md)) — without ever allocating a `basic_json` value. When you do need an
actual `basic_json` value for a subtree, [`materialize()`](../api/basic_json_view/materialize.md) builds exactly the
one [`parse()`](../api/basic_json/parse.md) would have produced for it.
The same small text, parsed both ways:
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_layout.svg"
</div>
<p class="nj-caption" markdown>Top: the tree of separate heap allocations that `basic_json::parse()` builds. Bottom: `json_document::parse()` keeps the source text and builds one flat index of 16-byte nodes that point back into it, plus a buffer of decoded strings.</p>
## How to use it
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
[`json_document`](../api/json_document.md), inspect its [`root()`](../api/basic_json_document/root.md), and
`materialize()` when you need a real value. `materialize()` works on any view, not just the root, so you can turn just
the subtree you need into a value:
??? example "Example: parse a document, inspect its root, and materialize it"
```cpp
--8<-- "examples/json_document.cpp"
```
Output:
```json
--8<-- "examples/json_document.output"
```
[`ordered_json_document`](../api/ordered_json_document.md) is the equivalent for
[`ordered_json`](../api/ordered_json.md), just as [`ordered_json`](../api/ordered_json.md) is to
[`json`](../api/json.md).
## Ownership and lifetime
A document either **borrows** the text it was parsed from, or **owns** its own copy of it; call
[`owns_source()`](../api/basic_json_document/owns_source.md) to find out which happened.
[`parse()`](../api/basic_json_document/parse.md) decides this from the value category and type of its argument (an
lvalue `#!cpp std::string` is borrowed; an rvalue `#!cpp std::string` is moved in, owned without a copy; a stream is
read into an owned buffer; and so on — see [`parse`'s Notes](../api/basic_json_document/parse.md#notes) for the full
table). [`parse_copy()`](../api/basic_json_document/parse_copy.md) always owns a copy, regardless of the input.
!!! warning "A borrowed document depends on your buffer"
If a document borrows its text, that text **must outlive the document** (and every view taken from it) and must
stay **unmodified** for as long as the document exists, since floating-point values and unescaped strings are
read from it lazily. Reading or writing through a view after the underlying buffer is gone is undefined behavior,
exactly as it would be for a dangling `#!cpp std::string_view`.
A view is valid only while all of the following hold:
- the document is alive,
- the document has not been re-parsed since the view was taken (with [`read()`](../api/basic_json_document/read.md)
or [`parse()`](../api/basic_json_document/parse.md) into it),
- the document has not had [`shrink_to_fit()`](../api/basic_json_document/shrink_to_fit.md) called on it since, and
- if the document borrows its source text, that text is still alive and unmodified.
Moving the `basic_json_document<>` itself is fine and does **not** invalidate its views: the index is a separate heap
allocation that keeps its address across the move. Take a fresh view from [`root()`](../api/basic_json_document/root.md)
whenever any of the other conditions above was not met.
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_lifetime.svg"
</div>
<p class="nj-caption" markdown>Four timelines of a document and its views, each bar showing when an object is alive or valid and when it dangles. Destroying the borrowed text, re-parsing, or shrinking the document invalidates the views taken before; moving the document does not.</p>
A view can dangle, exactly like a `#!cpp std::string_view`: nothing stops you from using it after its document is
gone. This is deliberate. A view is two pointers and trivially copyable; making it safe (a `#!cpp std::shared_ptr` in
the document and a `#!cpp std::weak_ptr` in each view) would make it larger, add reference counting to every copy,
and a `lock()` to every access — exactly the costs the view exists to avoid. What is caught is the obvious case:
because a view dies with its document, [`root()`](../api/basic_json_document/root.md) is not callable on a temporary
document: `#!cpp auto v = json_document::parse(text).root();` does not compile. Give the document a name first.
??? example "Example: borrowed and owned documents, and when views become invalid"
```cpp
--8<-- "examples/json_view_ownership.cpp"
```
Output:
```json
--8<-- "examples/json_view_ownership.output"
```
## What is the same as `parse()`
- **Accept/reject.** [`accept()`](../api/basic_json_document/accept.md) and
[`parse()`](../api/basic_json_document/parse.md) accept and reject exactly the same inputs as
[`basic_json::accept()`](../api/basic_json/accept.md)/[`basic_json::parse()`](../api/basic_json/parse.md), with the
same `ignore_comments` and `ignore_trailing_commas` options.
- **Errors.** A failing parse throws the same exception — the same id, message, and position — because on failure
the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and
the replay builds no values: it costs about a lexing pass up to the error.
`#!cpp allow_exceptions == false` skips the replay and gives a
[discarded](../api/basic_json_document/is_discarded.md) document instead of throwing, just as it gives a discarded
value for `#!cpp basic_json::parse()`.
- **Number classification.** An integer literal that does not fit into the 64-bit integer type becomes a
floating-point value, exactly as it does for `#!cpp basic_json::parse()`.
- **Macros.** [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) and
[`JSON_NOEXCEPTION`](../api/macros/json_noexception.md)/[`JSON_THROW_USER`](../api/macros/json_throw_user.md)
behave the same way they do for `<nlohmann/json.hpp>`. These are the macros that change what the parser accepts or
how it reports errors. Two more macros add context to the exceptions of views, as they do for those of
`#!cpp basic_json`:
- With [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md), an exception names the JSON Pointer path of the
value within the document.
- With [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md), an exception names the bytes of
the value in the source text.
A view has neither parent pointers nor stored positions, so both are found from the document's index when the
exception is thrown. This takes time linear in the size of the document. One exception has neither:
`key()` of an iterator over an array or a primitive value
([`invalid_iterator.207`](../home/exceptions.md#jsonexceptioninvalid_iterator207)), because a view's iterator does
not know the value it iterates over.
The other macros only affect the values `materialize()` produces, through `BasicJsonType`.
## What is different
- **Only 64-bit integers.** `basic_json_document<BasicJsonType>` requires `BasicJsonType::number_integer_t` and
`number_unsigned_t` to both be 64 bits wide; this is a compile-time `#!cpp static_assert`.
- **A 4 GiB input limit.** An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws
[`out_of_range.416`](../home/exceptions.md#jsonexceptionout_of_range416), a limit
`#!cpp basic_json::parse()` does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits
wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the
end must still fit.
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`: the stream
is read to its end into a buffer the document owns, and parsing starts after that. For a file, reading it into a
`#!cpp std::string` yourself and parsing that (an lvalue is borrowed) is therefore not more expensive in memory, and
was about 6 to 12 % faster than parsing from an `#!cpp std::ifstream`.
- **Fewer source positions after edits.** With
[`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) enabled,
[`materialize()`](../api/basic_json_view/materialize.md) sets the same positions as `#!cpp basic_json::parse()`.
In an [editable document](../api/json_editable_document.md), a value written by an edit has none, and neither has
an array or object whose elements changed or whose last element has none; a `basic_json` value keeps its positions
when it is changed. See [`materialize()`](../api/basic_json_view/materialize.md#notes).
- **Objects iterate in document order.** [`begin()`](../api/basic_json_view/begin.md)/
[`end()`](../api/basic_json_view/end.md) and [`items()`](../api/basic_json_view/items.md) visit an object's
members in the order they appear in the source text. `basic_json`'s default `object_t` is a `std::map`, which
sorts by key, so iterating a [`materialize()`](../api/basic_json_view/materialize.md)d value can print members in
a different order than iterating the view they came from.
- **Chained access is safe.** [`operator[]`](../api/basic_json_view/operator%5B%5D.md) with a missing key, an index
out of range, or an unresolvable JSON pointer returns a [discarded](../api/basic_json_view/is_discarded.md) view, and
`operator[]` on a discarded view returns a discarded view without throwing: `#!cpp v["a"]["b"][0]` can be tested
once at the end. Type errors on values that exist (a key on an array, an index on an object) still throw, and
[`at`](../api/basic_json_view/at.md) throws for every missing value.
- **Duplicate keys: lookups find the first member, `parse()` keeps the last.** See [Duplicate keys](#duplicate-keys)
below.
- **Ordering comparisons are not provided** by `basic_json_view` — there is no `#!cpp operator<`.
[`operator==`](../api/basic_json_view/operator_eq.md) and [`operator!=`](../api/basic_json_view/operator_ne.md) are
provided, though: two views, or a view and a `BasicJsonType` value, compare equal exactly when
[`materialize()`](../api/basic_json_view/materialize.md) or [`parse()`](../api/basic_json/parse.md) would produce
equal values for them, without ever building a tree to do it. For ordering, too,
[`materialize()`](../api/basic_json_view/materialize.md) is the way to get a value you can compare.
## Duplicate keys
!!! warning "A lookup in a view and in the parsed value can give different answers"
If an object in the source text repeats a key, [`operator[]`](../api/basic_json_view/operator%5B%5D.md),
[`at`](../api/basic_json_view/at.md), [`find`](../api/basic_json_view/find.md),
[`value`](../api/basic_json_view/value.md), [`contains`](../api/basic_json_view/contains.md), and JSON pointer
resolution all return the **first** member with that key. `basic_json::parse()` instead keeps the **last** value
of a repeated key, so for `#!cpp {"a":1,"a":2}`, `#!cpp view["a"]` is `#!cpp 1` while `#!cpp parse(text)["a"]` is
`#!cpp 2`. [`count`](../api/basic_json_view/count.md) counts every member with the key, so it is `#!cpp 2` here.
[`begin()`](../api/basic_json_view/begin.md)/[`end()`](../api/basic_json_view/end.md) and
[`items()`](../api/basic_json_view/items.md) visit *every* occurrence, in document order, and
[`size()`](../api/basic_json_view/size.md) counts all of them, so `#!cpp view.size()` can be larger than
`#!cpp view.materialize().size()`.
**Why the first?** A lookup can stop as soon as it finds a match. Returning the last member would force every lookup
to scan all members of the object, even when the key is found at the very first one: this made lookups in small
objects 1.6 to 3.4 times slower. The hash index of the keys of objects with 128 members or more leads to the first member of a
key as well. Other zero-copy parsers that index the source text, such as yyjson and simdjson, also return the first
member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees
duplicates is unpredictable, so neither choice is wrong.
The same holds for [`get<T>()`](../api/basic_json_view/get.md) of a type whose `from_json()` reads the view, such as
the types of the `NLOHMANN_DEFINE_TYPE_*` macros: their members are looked up, so `#!cpp get<point>()` of
`#!cpp {"x":1,"x":2}` reads `#!cpp x == 1`, while `#!cpp materialize().get<point>()` reads `#!cpp 2`.
**What stays the same as `parse()`?** [`materialize()`](../api/basic_json_view/materialize.md) and
[`get<std::map<...>>()`](../api/basic_json_view/get.md) replay every member in order, so they keep the *last* value
exactly like `#!cpp basic_json::parse()` (at the position of the first occurrence of the key, for an
[`ordered_json`](../api/ordered_json.md)).
**How do I get the value `parse()` would give?** Either call `#!cpp view.materialize()` and look the key up in the
result, or iterate the members and keep the last match:
```cpp
// the last member with the key "a", as parse() would keep it
json_view last;
for (const auto item : view.items())
{
if (item.key() == "a")
{
last = item.value();
}
}
```
If you cannot trust the source text to have unique keys, check [`size()`](../api/basic_json_view/size.md) against the
number of distinct keys, or reject duplicates when iterating.
## Getting values out without copying
[`get<T>()`](../api/basic_json_view/get.md) converts most `T` directly from the flat index, without ever building a
`basic_json` value for the conversion: `#!cpp bool`, arithmetic types, `#!cpp std::nullptr_t`,
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json_view` itself, the standard containers
and other types the library converts (`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::list`, `#!cpp std::array`,
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, ...), and the types of the `NLOHMANN_DEFINE_TYPE_*` and
`NLOHMANN_JSON_SERIALIZE_ENUM` macros. Types whose `from_json()` is written for `basic_json` only go through
[`materialize()`](../api/basic_json_view/materialize.md)`.get<T>()` instead: the subtree is built into a real
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there. See
[Writing generic code](#writing-generic-code) for how to write a `from_json()` that reads views.
Two conversions never copy at all:
- [`get_string()`](../api/basic_json_view/get_string.md) (equivalently, `#!cpp get<string_view_t>()`) returns a
string as a `string_view_t` pointing into the document's [`source()`](../api/basic_json_document/source.md) text —
or, for a string that contains escape sequences, into the document's own buffer of decoded strings — instead of
allocating a new `#!cpp std::string`.
- [`number_token()`](../api/basic_json_view/number_token.md) returns a number exactly as it was written in the
source, e.g. `#!cpp "1.50"`, `#!cpp "1E2"`, or an integer with more digits than any number type holds, instead of
rounding it into a `#!cpp double`/`#!cpp int64_t` the way `#!cpp get<T>()` (and
[`basic_json::parse()`](../api/basic_json/parse.md)) would.
Both results are only valid as long as the view — and, for a string with no escapes, the borrowed source text — is.
### `string_view` members
A struct whose member is a `#!cpp std::string_view` (C++17) can be decoded from a view with the
`NLOHMANN_DEFINE_TYPE_*` macros, and the member is not copied either: for a string without escape sequences it points
into the document's source text, and for a string with escape sequences into the document's buffer of decoded strings.
The member is valid as long as the document is alive and, for a document that
[borrows its source text](#ownership-and-lifetime) (as [`parse()`](../api/basic_json_document/parse.md) does for
an lvalue `#!cpp std::string`, a `#!cpp std::string_view`, or a C string), as long as that text is.
```cpp
struct record
{
std::string_view name;
int count;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(record, name, count)
};
const std::string text = R"({"name": "widget", "count": 3})";
const json_document doc = json_document::parse(text); // borrows text
const record r = doc.root().get<record>(); // r.name points into text, valid while text and doc are
```
!!! warning "Decoding into a `string_view` from a `json` value dangles at once"
The same struct also compiles with `#!cpp json::parse(text).get<record>()`, but there `name` points into the
temporary `json` value, which is destroyed at the end of the statement. Use a named
[`json_document`](../api/json_document.md), as above, to decode such a struct.
## Writing generic code
A view's type names its `BasicJsonType` and its [`view_mode`](../api/view_mode.md):
[`json_view`](../api/json_view.md) is `#!cpp basic_json_view<json, view_mode::read_only>`, and
[`json_editable_view`](../api/json_editable_view.md) is `#!cpp basic_json_view<json, view_mode::editable>`. These are
different types. The only conversion between them turns a view of a read-only document into a view of an editable
document of the same `BasicJsonType`, so a function written for one shortcut accepts few other views:
```cpp
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
void print_names(json_editable_view v); // also accepts a json_view, but no ordered_json_view
```
This is the same pitfall as a `to_json`/`from_json` written for `json` instead of any `BasicJsonType`, which then does
not work for `ordered_json`. The shortcuts are for declaring documents and views; a function that takes a view names
the views it accepts with a template:
```cpp
// views of editable documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
// views of read-only documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
// views of either document type
template<typename BasicJsonType, view_mode Mode>
void f(basic_json_view<BasicJsonType, Mode> v);
```
Views are passed by value: they are two pointers, cheap to copy, like a `#!cpp std::string_view`. A `const&` works as
well, but a non-`const` reference does not bind to the views that [`root()`](../api/basic_json_document/root.md),
[`operator[]`](../api/basic_json_view/operator%5B%5D.md), and [`at()`](../api/basic_json_view/at.md) return, so
`#!cpp f(doc.root())` would not compile.
There is no conversion from an editable view to a read-only one, by design: the mode decides how a view walks the
index. A read-only view reads a container in place, while a view of an editable document follows the links that edits
leave behind, so a read-only view of an edited document would read stale values. The other direction is safe: a
read-only document has no edits, so a view of it [converts](../api/basic_json_view/basic_json_view.md) to an
editable view, which reads it like an editable document before its first edit. A template deduces the mode without
conversions, so the template forms above still accept only the modes they name. Views of both modes compare with
[`operator==`](../api/basic_json_view/operator_eq.md).
[`is_json_view<T>`](../api/is_json_view.md) tells views from other types, for constraints that cannot be written as a
`basic_json_view<...>` parameter.
### A `from_json()` that reads views
[`get<T>()`](../api/basic_json_view/get.md) on a view calls `T`'s `from_json()` with the view itself if that
`from_json()` accepts views, and with [`materialize()`](../api/basic_json_view/materialize.md) otherwise. The
`from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](../api/macros/nlohmann_define_type_intrusive.md),
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../api/macros/nlohmann_define_derived_type.md), and
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md) macros, and those of the library
for the standard types, accept views, so these types need nothing else. For decoding the statuses of
twitter.json into structs, reading the view is about 5 times faster than `#!cpp materialize().get<T>()`.
A hand-written `from_json()` reads views if it is constrained to `json` values and views:
```cpp
template < typename J, typename std::enable_if <
nlohmann::is_json_view<J>::value || std::is_same<J, nlohmann::json>::value, int >::type = 0 >
void from_json(const J& j, person& p)
{
p.name = j.at("name").template get<std::string>();
p.age = j.at("age").template get<int>();
}
```
Its body may only use what views and `basic_json` have in common: the type checks, `at()`, `operator[]`, `contains()`,
`value()`, `size()`, iteration and `items()`, and `get<T>()`/`get_to()`. An unconstrained
`#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in
[arbitrary type conversions](arbitrary_types.md), is never called with a view, as it might use `basic_json` functions
a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is
converted through `materialize()` as well.
One thing differs when a `from_json()` reads the view: members looked up by name (`at()`, `value()`, ... and thus
the macros) find the **first** member with a repeated key, see [Duplicate keys](#duplicate-keys);
`#!cpp materialize().get<T>()` would see the last one. Containers built from an object, such as `#!cpp std::map`,
keep the **last** value either way, as [`parse()`](../api/basic_json/parse.md) does.
`to_json()` is unaffected: it writes `basic_json` values, never views.
## Writing a view back
[`dump()`](../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
`basic_json` value. An object's members are written in document order, not sorted by key, and *every* occurrence of a
repeated key is written, not only the last one — the same two ways [iteration](#what-is-different) already differs
from a [`materialize()`](../api/basic_json_view/materialize.md)d value, see [Duplicate keys](#duplicate-keys).
`#!cpp materialize().dump()` gives a different result in both respects for a `json_view`.
By default, numbers are written the way [`basic_json::dump()`](../api/basic_json/dump.md) would.
[`number_format::source`](../api/basic_json_view/number_format.md) instead copies every number exactly as it was
written in the source text — a price like `#!cpp 19.90`, a long order or account ID with more digits than any number
type holds, or a high-precision coordinate — something `basic_json` cannot do at all, since parsing already reduces
a number to its parsed `#!cpp double`/`#!cpp int64_t` value.
[`operator<<`](../api/basic_json_view/operator_ltlt.md) writes a view to a stream the way `basic_json`'s does, using
the stream's `width`/`fill` for indentation.
## Editing a document
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but
not change it. [`basic_json_document<BasicJsonType, view_mode::editable>`](../api/basic_json_document/index.md) — more conveniently
spelled [`json_editable_document`](../api/json_editable_document.md) or
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) — also lets you
[`set`](../api/basic_json_document/set.md) a value, [`push_back`](../api/basic_json_document/push_back.md) onto or
[`insert`](../api/basic_json_document/insert.md) into an array, and [`erase`](../api/basic_json_document/erase.md)
an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
The [mode](../api/view_mode.md) defaults to `#!cpp view_mode::read_only`, so `json_document`/`ordered_json_document` are unaffected — they carry
none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
runtime one.
### Why: editing without reformatting
The `#!cpp 19.90` price from [above](#writing-a-view-back) is exactly the kind of value that makes editing a `json`
or `ordered_json` value in place lossy. Say you parse a configuration file, patch one field, and write it back:
- **`json`** re-sorts every key on the way in (`object_t` is a `#!cpp std::map`) and rewrites every number to its
shortest round-trip form on the way out — a one-field patch turns into a diff that reorders the whole file and
rewrites `#!cpp 19.90` to `#!cpp 19.9`.
- **`ordered_json`** keeps the key order, but still rewrites every number the same way: parsing has already reduced
it to a `#!cpp double`/`#!cpp int64_t`, and there is no way back to how it was spelled in the source text.
The patch of the example below (set `"host"`, add `"retries"`) written back by each of them:
<div class="nj-jsonview-cmp" role="group" aria-label="The same patch written back by json, ordered_json, and json_editable_document">
<div><p class="nj-jsonview-cmp-h"><code>json</code></p><p class="nj-jsonview-cmp-v">keys sorted, numbers rewritten</p><pre>{<span class="nj-jsonview-bad">"host"</span>:"db2",
"name":"cache",
"port":6379,
"price":<span class="nj-jsonview-bad">19.9</span>,
"retries":3}</pre></div>
<div><p class="nj-jsonview-cmp-h"><code>ordered_json</code></p><p class="nj-jsonview-cmp-v">key order kept, numbers rewritten</p><pre>{"name":"cache",
"host":"db2",
"port":6379,
"price":<span class="nj-jsonview-bad">19.9</span>,
"retries":3}</pre></div>
<div class="nj-jsonview-cmp--best"><p class="nj-jsonview-cmp-h"><code>json_editable_document</code></p><p class="nj-jsonview-cmp-v">order and spelling kept</p><pre>{"name":"cache",
"host":"db2",
"port":6379,
"price":<span class="nj-jsonview-ok">19.90</span>,
"retries":3}</pre></div>
</div>
An editable document keeps both. [`dump()`](../api/basic_json_view/dump.md) of an edited document writes members in
document order — a member [`set`](../api/basic_json_document/set.md) added goes at the end, exactly where it was
inserted, and an [`erase`](../api/basic_json_document/erase.md)d member simply leaves a gap: everything around it
keeps its place — and [`number_format::source`](../api/basic_json_view/number_format.md) keeps the exact spelling
of every number an edit did not itself touch; a number an edit *did* touch is written the way
[`BasicJsonType::dump()`](../api/basic_json/dump.md) would write it, since there is no source spelling for a brand
new value.
??? example "Example: patch a configuration, keeping member order and number spellings"
```cpp
--8<-- "examples/json_editable_document.cpp"
```
Output:
```json
--8<-- "examples/json_editable_document.output"
```
### What stays valid, and what an edit costs
The source text itself is **never written**, and the parsed index never moves — a value keeps the node it was
parsed into for as long as it is not itself replaced. So every [view](../api/basic_json_view/index.md) taken before
an edit, including a previously obtained [`root()`](../api/basic_json_document/root.md), stays valid and, if it
still refers to the edited value, sees the edit; a view of a value a later edit drops or replaces just keeps showing
what it last held. New values go to storage the document allocates and owns on demand. The one thing an edit does
invalidate is the **iterators** taken over an edited array or object: the first time an element is added to it,
inserted into it, erased from it, or replaced by a value that spans a different number of nodes, its elements move from the parsed, fixed layout to a growable block of links
so that [`push_back`](../api/basic_json_document/push_back.md) can later grow it in amortized constant time —
existing elements are not touched, but an iterator that was walking the old layout no longer matches. A string
obtained with
[`get_string()`](../api/basic_json_view/get_string.md) is unaffected either way and stays valid across further
edits. See [`basic_json_document`'s Edits](../api/basic_json_document/index.md#edits) for the details, and
[`set`'s Exception safety](../api/basic_json_document/set.md#exception-safety) for what an edit guarantees if it
throws (the *basic* guarantee, not the strong one `dump()` and the read-only functions provide). How edits are kept in
the index is described in the [architecture overview](../home/architecture.md#node-index-of-json-views).
Step through the edits of a small document (the node fields follow the [architecture overview](../home/architecture.md#node-index-of-json-views)):
<div class="nj-jsonview-steps" data-nj-jsonview-steps>
<figure class="nj-jsonview-step" data-label="After parsing">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_0.svg"
</div>
<figcaption>Step 1 of 5. After parsing: nine nodes in the parsed index, no owned storage yet.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="set an existing member">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_1.svg"
</div>
<figcaption>Step 2 of 5. <code>doc.set(doc.root(), "port", 6380)</code> overwrites the node of the integer in place; no member is added or removed, so the object keeps its parsed layout.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="erase an array element">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_2.svg"
</div>
<figcaption>Step 3 of 5. <code>doc.erase(doc.root()["tags"], 0)</code>: the array is edited for the first time, so its elements move to a block of links in owned storage. The node of <code>"eu"</code> stays in the index, but nothing refers to it any more; iterators over the array taken before are invalid.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="push_back onto the array">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_3.svg"
</div>
<figcaption>Step 4 of 5. <code>doc.push_back(doc.root()["tags"], "new")</code>: the new string gets its own node, its text goes to the buffer of edited text, and a link to it is appended to the block of the array.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="set a new member">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_4.svg"
</div>
<figcaption>Step 5 of 5. <code>doc.set(doc.root(), "retries", 3)</code>: a new member, so the object moves to a block too: copies of its keys, links to the values it already had, then the new key and a link to the new integer.</figcaption>
</figure>
</div>
<p class="nj-caption" markdown>The node index and the owned storage of the document after each of five edits. Use *Back*, *Next*, or the numbered buttons to switch between the steps; without JavaScript all steps are shown one below the other.</p>
## Images
[`save()`](../api/basic_json_document/save.md) writes a document as an *image*: a byte buffer that
[`load()`](../api/basic_json_document/load.md) 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()`](../api/basic_json_document/parse_copy.md) still has to scan the whole input,
[`load()`](../api/basic_json_document/load.md) 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()`](../api/basic_json_document/save.md)'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()`](../api/basic_json_document/load.md) 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()`](../api/basic_json_document/load.md) turns the transfer into a copy of the node index
plus pointers into the received bytes, not a re-parse.
**Choosing a check.** [`load()`](../api/basic_json_document/load.md) takes an
[`image_check`](../api/basic_json_document/load.md#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()`](../api/basic_json_document/save.md), 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](../api/basic_json_document/load.md#notes) for exactly what each level does and does not guarantee.
??? example "Example: cache a parsed configuration as an image"
```cpp
--8<-- "examples/basic_json_document__save.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__save.output"
```
!!! 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.
The idea of a document you can read without parsing comes from zero-copy formats such as
[FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
[`load()`](../api/basic_json_document/load.md) runs follows the idea of FlatBuffers' Verifier. No code is taken from
either.
## Choosing between `json`, `ordered_json`, the SAX interface, and `json_view`
| | [`json`](../api/json.md) / [`ordered_json`](../api/ordered_json.md) | [SAX interface](parsing/sax_interface.md) | [`json_document`](../api/json_document.md) / [`json_view`](../api/json_view.md) | [`json_editable_document`](../api/json_editable_document.md) / [`json_editable_view`](../api/json_editable_view.md) |
|---|---|---|---|---|
| **Ownership** | owns every value | owns nothing; you decide what to keep, in your handler | borrows or owns the *text*; the index is always owned by the document | same as `json_document`; edits go to storage the document owns |
| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../api/basic_json_document/set.md)/[`push_back`](../api/basic_json_document/push_back.md)/[`insert`](../api/basic_json_document/insert.md)/[`erase`](../api/basic_json_document/erase.md) edit in place; the source text is never rewritten |
| **What you get** | a full tree you can read, write, and keep as long as you like | a sequence of callbacks; whatever your handler builds from them | a flat index plus, on demand, [`materialize()`](../api/basic_json_view/materialize.md)d `json`/`ordered_json` values for the parts you actually use | the same, plus [`dump()`](../api/basic_json_view/dump.md) of an edited document that keeps the member order and, with [`number_format::source`](../api/basic_json_view/number_format.md), the spelling of every untouched number |
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back — a configuration file, for instance — where the rest of it should come back exactly as it was |
| **Caching/reload** | not applicable — re-parse, or roll your own serialization | not applicable | [`save()`](../api/basic_json_document/save.md)/[`load()`](../api/basic_json_document/load.md): cache the parsed index as an image and reload it without parsing | same, saving the document's current — possibly edited — state |
<p class="nj-table-caption" markdown>Each column is one way to work with JSON in this library, and each row compares one property of them.</p>
## See also
- [`basic_json_document`](../api/basic_json_document/index.md) - the document that owns the parsed index (parse, access, images, edits)
- [`basic_json_view`](../api/basic_json_view/index.md) - the non-owning handle to a value in a document
- [`json_document`](../api/json_document.md) - and [`ordered_json_document`](../api/ordered_json_document.md) - the read-only documents
- [`json_editable_document`](../api/json_editable_document.md) - and [`ordered_json_editable_document`](../api/ordered_json_editable_document.md) - the documents that can be edited in place
- [Architecture](../home/architecture.md#node-index-of-json-views) - the layout of the node index
- [SAX interface](parsing/sax_interface.md) - event-based parsing without building a tree
- [Performance](performance.md) - benchmarks and tuning of parsing and serialization
- [Large, Streamed, and Partial Input](parsing/large_and_partial_input.md) - reading only the part of a text you need
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,220 @@
# Differences from `basic_json`
A [`basic_json_view`](../../api/basic_json_view/index.md) offers the read-only part of the
[`basic_json`](../../api/basic_json/index.md) interface, and in most respects it behaves exactly like the value
[`basic_json::parse()`](../../api/basic_json/parse.md) would have built from the same text. This page lists where it
does not: what a document parses differently, what a view's functions do differently, and which parts of the
`basic_json` interface a view does not have.
## Summary
| | `basic_json` value from `parse()` | view of a `json_document` | to get the `basic_json` behavior |
|---|---|---|---|
| [Integer types](#parsing) | any `number_integer_t`/`number_unsigned_t` | 64-bit only (compile-time check) | — |
| [Input size](#parsing) | unlimited | less than 4 GiB | — |
| [Parser callbacks](#parsing) | `parser_callback_t` | none | filter while iterating |
| [`operator[]` on a missing key or index](#element-access) | inserts (non-`const`) or undefined behavior (`const`) | returns a discarded view | — |
| [Object member order](#object-member-order) | sorted by key (`json`), insertion order (`ordered_json`) | document order | `materialize()` |
| [Repeated keys](#duplicate-keys) | the last value is kept | lookups find the first member; iteration, `size()`, and `dump()` see all of them | `materialize()` |
| [Conversions](#conversions) | `get<T>()`, implicit conversions, `get_ptr()`, `get_ref()` | `get<T>()`, `get_string()`, `number_token()` | `materialize()` |
| [Number spelling](#serialization) | lost when parsing | kept: `number_token()`, `number_format::source` | — |
| [Comparison](#comparison) | `==`, `!=`, `<`, `<=>`, ... | `==` and `!=` only | `materialize()` |
| [Modification](#what-a-view-does-not-have) | member functions of the value | only through an [editable document](editing.md) | `materialize()` |
| [Iterators](#what-a-view-does-not-have) | bidirectional (`rbegin()`/`rend()`) | forward only | `materialize()` |
<p class="nj-table-caption" markdown>Each row is one difference; the last column names the way to get `basic_json`'s behavior from a view, where there is one.</p>
## Parsing
### What is the same
- **Accept/reject.** [`accept()`](../../api/basic_json_document/accept.md) and
[`parse()`](../../api/basic_json_document/parse.md) accept and reject exactly the same inputs as
[`basic_json::accept()`](../../api/basic_json/accept.md)/[`basic_json::parse()`](../../api/basic_json/parse.md),
with the same `ignore_comments` and `ignore_trailing_commas` options.
- **Errors.** A failing parse throws the same exception — the same id, message, and position — because on failure
the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and
the replay builds no values: it costs about a lexing pass up to the error.
`#!cpp allow_exceptions == false` skips the replay and gives a
[discarded](../../api/basic_json_document/is_discarded.md) document instead of throwing, just as it gives a
discarded value for `#!cpp basic_json::parse()`.
- **Number classification.** An integer literal that does not fit into the 64-bit integer type becomes a
floating-point value, exactly as it does for `#!cpp basic_json::parse()`.
- **Macros.** [`JSON_STRICT_NUL_HANDLING`](../../api/macros/json_strict_nul_handling.md) and
[`JSON_NOEXCEPTION`](../../api/macros/json_noexception.md)/[`JSON_THROW_USER`](../../api/macros/json_throw_user.md)
behave the same way they do for `<nlohmann/json.hpp>`. These are the macros that change what the parser accepts or
how it reports errors. The other macros only affect the values `materialize()` produces, through `BasicJsonType`.
Two of them also add context to the exceptions of views, see [Exception context](#exception-context).
### What is different
- **Only 64-bit integers.** `basic_json_document<BasicJsonType>` requires `BasicJsonType::number_integer_t` and
`number_unsigned_t` to both be 64 bits wide; this is a compile-time `#!cpp static_assert`.
- **A 4 GiB input limit.** An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws
[`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416), a limit
`#!cpp basic_json::parse()` does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits
wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the
end must still fit.
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`: the stream
is read to its end into a buffer the document owns, and parsing starts after that. For a file, reading it into a
`#!cpp std::string` yourself and parsing that (an lvalue is borrowed) is therefore not more expensive in memory, and
was about 6 to 12 % faster than parsing from an `#!cpp std::ifstream`.
- **No parser callbacks.** [`parse()`](../../api/basic_json_document/parse.md) takes no
[`parser_callback_t`](../../api/basic_json/parser_callback_t.md): a document always indexes the whole text. Skip
the values you do not need when reading the view instead.
- **JSON text only.** A document is parsed from JSON text; there is no counterpart of
[`from_cbor()`](../../api/basic_json/from_cbor.md) and the other binary formats, and
[`is_binary()`](../../api/basic_json_view/is_binary.md) is always `#!cpp false`.
## Element access
**Chained access is safe.** [`operator[]`](../../api/basic_json_view/operator%5B%5D.md) with a missing key, an index
out of range, or an unresolvable JSON pointer returns a [discarded](../../api/basic_json_view/is_discarded.md) view,
and `operator[]` on a discarded view returns a discarded view without throwing: `#!cpp v["a"]["b"][0]` can be tested
once at the end. Type errors on values that exist (a key on an array, an index on an object) still throw, and
[`at`](../../api/basic_json_view/at.md) throws for every missing value.
`basic_json`'s non-`const` `operator[]` instead inserts a missing key, and its `const` `operator[]` has undefined
behavior for one.
## Objects
### Object member order
[`begin()`](../../api/basic_json_view/begin.md)/[`end()`](../../api/basic_json_view/end.md) and
[`items()`](../../api/basic_json_view/items.md) visit an object's members in the order they appear in the source text.
`basic_json`'s default `object_t` is a `std::map`, which sorts by key, so iterating a
[`materialize()`](../../api/basic_json_view/materialize.md)d value can print members in a different order than
iterating the view they came from. [`dump()`](../../api/basic_json_view/dump.md) of a view writes members in document
order as well.
### Duplicate keys
!!! warning "A lookup in a view and in the parsed value can give different answers"
If an object in the source text repeats a key, [`operator[]`](../../api/basic_json_view/operator%5B%5D.md),
[`at`](../../api/basic_json_view/at.md), [`find`](../../api/basic_json_view/find.md),
[`value`](../../api/basic_json_view/value.md), [`contains`](../../api/basic_json_view/contains.md), and JSON
pointer resolution all return the **first** member with that key. `basic_json::parse()` instead keeps the **last**
value of a repeated key, so for `#!cpp {"a":1,"a":2}`, `#!cpp view["a"]` is `#!cpp 1` while
`#!cpp parse(text)["a"]` is `#!cpp 2`. [`count`](../../api/basic_json_view/count.md) counts every member with the
key, so it is `#!cpp 2` here.
[`begin()`](../../api/basic_json_view/begin.md)/[`end()`](../../api/basic_json_view/end.md) and
[`items()`](../../api/basic_json_view/items.md) visit *every* occurrence, in document order, and
[`size()`](../../api/basic_json_view/size.md) counts all of them, so `#!cpp view.size()` can be larger than
`#!cpp view.materialize().size()`. [`dump()`](../../api/basic_json_view/dump.md) writes every occurrence, too, so
`#!cpp materialize().dump()` gives a different result for such an object.
**Why the first?** A lookup can stop as soon as it finds a match. Returning the last member would force every lookup
to scan all members of the object, even when the key is found at the very first one: this made lookups in small
objects 1.6 to 3.4 times slower. The hash index of the keys of objects with 128 members or more leads to the first
member of a key as well. Other zero-copy parsers that index the source text, such as yyjson and simdjson, also return
the first member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver
that sees duplicates is unpredictable, so neither choice is wrong.
The same holds for [`get<T>()`](../../api/basic_json_view/get.md) of a type whose `from_json()` reads the view, such
as the types of the `NLOHMANN_DEFINE_TYPE_*` macros: their members are looked up, so `#!cpp get<point>()` of
`#!cpp {"x":1,"x":2}` reads `#!cpp x == 1`, while `#!cpp materialize().get<point>()` reads `#!cpp 2`.
**What stays the same as `parse()`?** [`materialize()`](../../api/basic_json_view/materialize.md) and
[`get<std::map<...>>()`](../../api/basic_json_view/get.md) (and the other containers built from an object) replay
every member in order, so they keep the *last* value exactly like `#!cpp basic_json::parse()` (at the position of the
first occurrence of the key, for an [`ordered_json`](../../api/ordered_json.md)).
**How do I get the value `parse()` would give?** Either call `#!cpp view.materialize()` and look the key up in the
result, or iterate the members and keep the last match:
```cpp
// the last member with the key "a", as parse() would keep it
json_view last;
for (const auto item : view.items())
{
if (item.key() == "a")
{
last = item.value();
}
}
```
If you cannot trust the source text to have unique keys, check [`size()`](../../api/basic_json_view/size.md) against
the number of distinct keys, or reject duplicates when iterating.
## Conversions
- **No implicit conversions.** A view has no `#!cpp operator ValueType()`, no `#!cpp get_ptr()`, and no
`#!cpp get_ref()`; use [`get<T>()`](../../api/basic_json_view/get.md), or
[`get_string()`](../../api/basic_json_view/get_string.md) for a string without a copy.
- **`from_json()` overloads.** [`get<T>()`](../../api/basic_json_view/get.md) calls `T`'s `from_json()` with the view
only if that `from_json()` accepts views, and with [`materialize()`](../../api/basic_json_view/materialize.md)
otherwise; see [A `from_json()` that reads views](generic_code.md#a-from_json-that-reads-views). Both give the same
result except for [repeated keys](#duplicate-keys).
- **`string_view` members.** A struct with a `#!cpp std::string_view` member decoded from a view points into the
document, see [`string_view` members](reading.md#string_view-members). Decoding the same struct from a `json` value
compiles, too, but dangles at once if the value is a temporary.
## Serialization
[`dump()`](../../api/basic_json_view/dump.md) writes numbers the way
[`basic_json::dump()`](../../api/basic_json/dump.md) would by default, but writes object members in
[document order](#object-member-order) and writes [every occurrence of a repeated key](#duplicate-keys).
A view can also do what a `basic_json` value cannot: [`number_token()`](../../api/basic_json_view/number_token.md)
and [`number_format::source`](../../api/basic_json_view/number_format.md) give every number exactly as it was spelled
in the source text, while parsing into `basic_json` already reduces a number to its `#!cpp double`/`#!cpp int64_t`
value. See [Writing a view back](reading.md#writing-a-view-back).
## Comparison
**Ordering comparisons are not provided** by `basic_json_view` — there is no `#!cpp operator<`.
[`operator==`](../../api/basic_json_view/operator_eq.md) and [`operator!=`](../../api/basic_json_view/operator_ne.md)
are provided, though: two views, or a view and a `BasicJsonType` value, compare equal exactly when
[`materialize()`](../../api/basic_json_view/materialize.md) or [`parse()`](../../api/basic_json/parse.md) would produce
equal values for them, without ever building a tree to do it. For ordering,
[`materialize()`](../../api/basic_json_view/materialize.md) is the way to get a value you can compare.
## Exception context
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md), an exception of a view names the JSON Pointer path of
the value within the document, and with
[`JSON_DIAGNOSTIC_POSITIONS`](../../api/macros/json_diagnostic_positions.md), it names the bytes of the value in the
source text, as they do for the exceptions of `#!cpp basic_json`.
A view has neither parent pointers nor stored positions, so both are found from the document's index when the
exception is thrown. This takes time linear in the size of the document. One exception has neither: `key()` of an
iterator over an array or a primitive value
([`invalid_iterator.207`](../../home/exceptions.md#jsonexceptioninvalid_iterator207)), because a view's iterator does
not know the value it iterates over.
**Fewer source positions after edits.** With
[`JSON_DIAGNOSTIC_POSITIONS`](../../api/macros/json_diagnostic_positions.md) enabled,
[`materialize()`](../../api/basic_json_view/materialize.md) sets the same positions as `#!cpp basic_json::parse()`. In
an [editable document](editing.md), a value written by an edit has none, and neither has an array or object whose
elements changed or whose last element has none; a `basic_json` value keeps its positions when it is changed. See
[`materialize()`](../../api/basic_json_view/materialize.md#notes).
## What a view does not have
A view is a read-only handle. These parts of the `basic_json` interface have no counterpart on a view;
[`materialize()`](../../api/basic_json_view/materialize.md) the subtree to use them:
- **Modifiers** such as `push_back`, `insert`, `erase`, `update`, or `operator=`. A view never changes a value
itself; an [editable document](editing.md) changes the values its views refer to through
[`set`](../../api/basic_json_document/set.md), [`push_back`](../../api/basic_json_document/push_back.md),
[`insert`](../../api/basic_json_document/insert.md), and [`erase`](../../api/basic_json_document/erase.md).
- **Reverse iteration.** A view's iterator is a forward iterator; there is no `rbegin()`/`rend()`.
- **JSON Patch and friends**: [`patch()`](../../api/basic_json/patch.md),
[`merge_patch()`](../../api/basic_json/merge_patch.md), [`diff()`](../../api/basic_json/diff.md),
[`flatten()`](../../api/basic_json/flatten.md).
- **Binary formats**: [`to_cbor()`](../../api/basic_json/to_cbor.md) and the other writers, and binary values
([`get_binary()`](../../api/basic_json/get_binary.md)).
## See also
- [Zero-copy JSON views](index.md) - overview
- [`basic_json_view`](../../api/basic_json_view/index.md) - the full interface of a view
- [`materialize()`](../../api/basic_json_view/materialize.md) - build the `basic_json` value of a view
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,133 @@
# Editing a document
A [`json_document`](../../api/json_document.md)/[`json_view`](../../api/json_view.md) lets you look at a parsed text
without copying it, but not change it.
[`basic_json_document<BasicJsonType, view_mode::editable>`](../../api/basic_json_document/index.md) — more
conveniently spelled [`json_editable_document`](../../api/json_editable_document.md) or
[`ordered_json_editable_document`](../../api/ordered_json_editable_document.md) — also lets you
[`set`](../../api/basic_json_document/set.md) a value, [`push_back`](../../api/basic_json_document/push_back.md) onto
or [`insert`](../../api/basic_json_document/insert.md) into an array, and
[`erase`](../../api/basic_json_document/erase.md) an object member or an array element, still without ever building a
`basic_json` tree for parts you do not touch.
The [mode](../../api/view_mode.md) defaults to `#!cpp view_mode::read_only`, so
`json_document`/`ordered_json_document` are unaffected — they carry none of the bookkeeping edits need, and calling
`set`/`push_back`/`insert`/`erase` on one is a compile error, not a runtime one.
## Why: editing without reformatting
A price like `#!cpp 19.90` is exactly the kind of value that makes editing a `json` or `ordered_json` value in place
lossy. Say you parse a configuration file, patch one field, and write it back:
- **`json`** re-sorts every key on the way in (`object_t` is a `#!cpp std::map`) and rewrites every number to its
shortest round-trip form on the way out — a one-field patch turns into a diff that reorders the whole file and
rewrites `#!cpp 19.90` to `#!cpp 19.9`.
- **`ordered_json`** keeps the key order, but still rewrites every number the same way: parsing has already reduced
it to a `#!cpp double`/`#!cpp int64_t`, and there is no way back to how it was spelled in the source text.
The patch of the example below (set `"host"`, add `"retries"`) written back by each of them:
<div class="nj-jsonview-cmp" role="group" aria-label="The same patch written back by json, ordered_json, and json_editable_document">
<div><p class="nj-jsonview-cmp-h"><code>json</code></p><p class="nj-jsonview-cmp-v">keys sorted, numbers rewritten</p><pre>{<span class="nj-jsonview-bad">"host"</span>:"db2",
"name":"cache",
"port":6379,
"price":<span class="nj-jsonview-bad">19.9</span>,
"retries":3}</pre></div>
<div><p class="nj-jsonview-cmp-h"><code>ordered_json</code></p><p class="nj-jsonview-cmp-v">key order kept, numbers rewritten</p><pre>{"name":"cache",
"host":"db2",
"port":6379,
"price":<span class="nj-jsonview-bad">19.9</span>,
"retries":3}</pre></div>
<div class="nj-jsonview-cmp--best"><p class="nj-jsonview-cmp-h"><code>json_editable_document</code></p><p class="nj-jsonview-cmp-v">order and spelling kept</p><pre>{"name":"cache",
"host":"db2",
"port":6379,
"price":<span class="nj-jsonview-ok">19.90</span>,
"retries":3}</pre></div>
</div>
An editable document keeps both. [`dump()`](../../api/basic_json_view/dump.md) of an edited document writes members in
document order — a member [`set`](../../api/basic_json_document/set.md) added goes at the end, exactly where it was
inserted, and an [`erase`](../../api/basic_json_document/erase.md)d member simply leaves a gap: everything around it
keeps its place — and [`number_format::source`](../../api/basic_json_view/number_format.md) keeps the exact spelling
of every number an edit did not itself touch; a number an edit *did* touch is written the way
[`BasicJsonType::dump()`](../../api/basic_json/dump.md) would write it, since there is no source spelling for a brand
new value. See [Writing a view back](reading.md#writing-a-view-back).
??? example "Example: patch a configuration, keeping member order and number spellings"
```cpp
--8<-- "examples/json_editable_document.cpp"
```
Output:
```json
--8<-- "examples/json_editable_document.output"
```
## What stays valid, and what an edit costs
The source text itself is **never written**, and the parsed index never moves — a value keeps the node it was
parsed into for as long as it is not itself replaced. So every [view](../../api/basic_json_view/index.md) taken before
an edit, including a previously obtained [`root()`](../../api/basic_json_document/root.md), stays valid and, if it
still refers to the edited value, sees the edit; a view of a value a later edit drops or replaces just keeps showing
what it last held. New values go to storage the document allocates and owns on demand. The one thing an edit does
invalidate is the **iterators** taken over an edited array or object: the first time an element is added to it,
inserted into it, erased from it, or replaced by a value that spans a different number of nodes, its elements move
from the parsed, fixed layout to a growable block of links so that
[`push_back`](../../api/basic_json_document/push_back.md) can later grow it in amortized constant time — existing
elements are not touched, but an iterator that was walking the old layout no longer matches. A string obtained with
[`get_string()`](../../api/basic_json_view/get_string.md) is unaffected either way and stays valid across further
edits. See [`basic_json_document`'s Edits](../../api/basic_json_document/index.md#edits) for the details, and
[`set`'s Exception safety](../../api/basic_json_document/set.md#exception-safety) for what an edit guarantees if it
throws (the *basic* guarantee, not the strong one `dump()` and the read-only functions provide). How edits are kept in
the index is described in the [architecture overview](../../home/architecture.md#node-index-of-json-views).
Step through the edits of a small document (the node fields follow the
[architecture overview](../../home/architecture.md#node-index-of-json-views)):
<div class="nj-jsonview-steps" data-nj-jsonview-steps>
<figure class="nj-jsonview-step" data-label="After parsing">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_0.svg"
</div>
<figcaption>Step 1 of 5. After parsing: nine nodes in the parsed index, no owned storage yet.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="set an existing member">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_1.svg"
</div>
<figcaption>Step 2 of 5. <code>doc.set(doc.root(), "port", 6380)</code> overwrites the node of the integer in place; no member is added or removed, so the object keeps its parsed layout.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="erase an array element">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_2.svg"
</div>
<figcaption>Step 3 of 5. <code>doc.erase(doc.root()["tags"], 0)</code>: the array is edited for the first time, so its elements move to a block of links in owned storage. The node of <code>"eu"</code> stays in the index, but nothing refers to it any more; iterators over the array taken before are invalid.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="push_back onto the array">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_3.svg"
</div>
<figcaption>Step 4 of 5. <code>doc.push_back(doc.root()["tags"], "new")</code>: the new string gets its own node, its text goes to the buffer of edited text, and a link to it is appended to the block of the array.</figcaption>
</figure>
<figure class="nj-jsonview-step" data-label="set a new member">
<div class="nj-jsonview-scroll">
--8<-- "images/json_view_edit_4.svg"
</div>
<figcaption>Step 5 of 5. <code>doc.set(doc.root(), "retries", 3)</code>: a new member, so the object moves to a block too: copies of its keys, links to the values it already had, then the new key and a link to the new integer.</figcaption>
</figure>
</div>
<p class="nj-caption" markdown>The node index and the owned storage of the document after each of five edits. Use *Back*, *Next*, or the numbered buttons to switch between the steps; without JavaScript all steps are shown one below the other.</p>
## See also
- [Zero-copy JSON views](index.md) - overview
- [`json_editable_document`](../../api/json_editable_document.md) - and [`ordered_json_editable_document`](../../api/ordered_json_editable_document.md) - the documents that can be edited in place
- [`basic_json_document`'s Edits](../../api/basic_json_document/index.md#edits) - the rules of edits in detail
- [Differences from `basic_json`](differences.md#exception-context) - source positions after edits
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,93 @@
# Writing generic code
## View types
A view's type names its `BasicJsonType` and its [`view_mode`](../../api/view_mode.md):
[`json_view`](../../api/json_view.md) is `#!cpp basic_json_view<json, view_mode::read_only>`, and
[`json_editable_view`](../../api/json_editable_view.md) is `#!cpp basic_json_view<json, view_mode::editable>`. These
are different types. The only conversion between them turns a view of a read-only document into a view of an
editable document of the same `BasicJsonType`, so a function written for one shortcut accepts few other views:
```cpp
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
void print_names(json_editable_view v); // also accepts a json_view, but no ordered_json_view
```
This is the same pitfall as a `to_json`/`from_json` written for `json` instead of any `BasicJsonType`, which then does
not work for `ordered_json`. The shortcuts are for declaring documents and views; a function that takes a view names
the views it accepts with a template:
```cpp
// views of editable documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
// views of read-only documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
// views of either document type
template<typename BasicJsonType, view_mode Mode>
void f(basic_json_view<BasicJsonType, Mode> v);
```
Views are passed by value: they are two pointers, cheap to copy, like a `#!cpp std::string_view`. A `const&` works as
well, but a non-`const` reference does not bind to the views that
[`root()`](../../api/basic_json_document/root.md), [`operator[]`](../../api/basic_json_view/operator%5B%5D.md), and
[`at()`](../../api/basic_json_view/at.md) return, so `#!cpp f(doc.root())` would not compile.
There is no conversion from an editable view to a read-only one, by design: the mode decides how a view walks the
index. A read-only view reads a container in place, while a view of an editable document follows the links that edits
leave behind, so a read-only view of an edited document would read stale values. The other direction is safe: a
read-only document has no edits, so a view of it [converts](../../api/basic_json_view/basic_json_view.md) to an
editable view, which reads it like an editable document before its first edit. A template deduces the mode without
conversions, so the template forms above still accept only the modes they name. Views of both modes compare with
[`operator==`](../../api/basic_json_view/operator_eq.md).
[`is_json_view<T>`](../../api/is_json_view.md) tells views from other types, for constraints that cannot be written as
a `basic_json_view<...>` parameter.
## A `from_json()` that reads views
[`get<T>()`](../../api/basic_json_view/get.md) on a view calls `T`'s `from_json()` with the view itself if that
`from_json()` accepts views, and with [`materialize()`](../../api/basic_json_view/materialize.md) otherwise. The
`from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](../../api/macros/nlohmann_define_type_intrusive.md),
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../../api/macros/nlohmann_define_derived_type.md), and
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../../api/macros/nlohmann_json_serialize_enum.md) macros, and those of the library
for the standard types, accept views, so these types need nothing else. For decoding the statuses of
twitter.json into structs, reading the view is about 5 times faster than `#!cpp materialize().get<T>()`.
A hand-written `from_json()` reads views if it is constrained to `json` values and views:
```cpp
template < typename J, typename std::enable_if <
nlohmann::is_json_view<J>::value || std::is_same<J, nlohmann::json>::value, int >::type = 0 >
void from_json(const J& j, person& p)
{
p.name = j.at("name").template get<std::string>();
p.age = j.at("age").template get<int>();
}
```
Its body may only use what views and `basic_json` have in common: the type checks, `at()`, `operator[]`,
`contains()`, `value()`, `size()`, iteration and `items()`, and `get<T>()`/`get_to()`. An unconstrained
`#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in
[arbitrary type conversions](../arbitrary_types.md), is never called with a view, as it might use `basic_json`
functions a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is
converted through `materialize()` as well.
Reading the view and `#!cpp materialize().get<T>()` give the same result, except for an object with a repeated key;
see [Duplicate keys](differences.md#duplicate-keys).
`to_json()` is unaffected: it writes `basic_json` values, never views.
## See also
- [Zero-copy JSON views](index.md) - overview
- [`is_json_view`](../../api/is_json_view.md) - type trait to detect views
- [`view_mode`](../../api/view_mode.md) - read-only and editable views
- [Reading values](reading.md) - what `get<T>()` converts without materializing
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,70 @@
# Images
[`save()`](../../api/basic_json_document/save.md) writes a document as an *image*: a byte buffer that
[`load()`](../../api/basic_json_document/load.md) 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()`](../../api/basic_json_document/parse_copy.md) still has to scan the whole input,
[`load()`](../../api/basic_json_document/load.md) 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()`](../../api/basic_json_document/save.md)'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()`](../../api/basic_json_document/load.md) 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()`](../../api/basic_json_document/load.md) turns the transfer into a copy of the node
index plus pointers into the received bytes, not a re-parse.
## Choosing a check
[`load()`](../../api/basic_json_document/load.md) takes an
[`image_check`](../../api/basic_json_document/load.md#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()`](../../api/basic_json_document/save.md), 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](../../api/basic_json_document/load.md#notes) for exactly what each level does and does not
guarantee.
??? example "Example: cache a parsed configuration as an image"
```cpp
--8<-- "examples/basic_json_document__save.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__save.output"
```
!!! 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](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
[`load()`](../../api/basic_json_document/load.md) runs follows the idea of FlatBuffers' Verifier. No code is taken from
either.
## See also
- [Zero-copy JSON views](index.md) - overview
- [`save()`](../../api/basic_json_document/save.md) - write a document as an image
- [`load()`](../../api/basic_json_document/load.md) - read an image back into a document
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,106 @@
# Zero-copy JSON views
`#!cpp <nlohmann/json_view.hpp>` adds a read-only, non-owning way to look at a parsed JSON text, as an alternative to
building a [`basic_json`](../../api/basic_json/index.md) tree with [`parse()`](../../api/basic_json/parse.md).
## The problem
[`basic_json::parse()`](../../api/basic_json/parse.md) builds a tree of `basic_json` values: one allocation for every
array and object, and every string copied into its own `std::string`. That is the right trade-off when the program
goes on to read and write the value freely, but it does more work than necessary when only a small part of a large
JSON text is actually needed, or when the same text is parsed over and over (many small messages, for instance) and
most of the resulting tree is thrown away almost immediately.
## The idea
[`basic_json_document::parse()`](../../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
options, but instead of a tree it builds a flat index of the values it found: one
[16-byte entry](../../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
order. Integers are converted while parsing and stored in their entry. Floating-point numbers and strings are
referenced in place in the source text: a float is converted when it is read, and only strings that contain escape
sequences are decoded, into one shared buffer owned by the document.
[`basic_json_view`](../../api/basic_json_view/index.md) is a small, trivially copyable handle (two pointers) into that
index. It gives you the read-only, type-inspection part of the `basic_json` interface —
[`type()`](../../api/basic_json_view/type.md) and the `is_*()` predicates,
[`size()`](../../api/basic_json_view/size.md)/[`empty()`](../../api/basic_json_view/empty.md) — as well as element
access ([`operator[]`](../../api/basic_json_view/operator%5B%5D.md), [`at`](../../api/basic_json_view/at.md),
[`front`](../../api/basic_json_view/front.md)/[`back`](../../api/basic_json_view/back.md)), lookup
([`find`](../../api/basic_json_view/find.md), [`contains`](../../api/basic_json_view/contains.md),
[`count`](../../api/basic_json_view/count.md)), and iteration
([`begin`](../../api/basic_json_view/begin.md)/[`end`](../../api/basic_json_view/end.md),
[`items`](../../api/basic_json_view/items.md)) — without ever allocating a `basic_json` value. When you do need an
actual `basic_json` value for a subtree, [`materialize()`](../../api/basic_json_view/materialize.md) builds exactly the
one [`parse()`](../../api/basic_json/parse.md) would have produced for it.
The same small text, parsed both ways:
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_layout.svg"
</div>
<p class="nj-caption" markdown>Top: the tree of separate heap allocations that `basic_json::parse()` builds. Bottom: `json_document::parse()` keeps the source text and builds one flat index of 16-byte nodes that point back into it, plus a buffer of decoded strings.</p>
## How to use it
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
[`json_document`](../../api/json_document.md), inspect its [`root()`](../../api/basic_json_document/root.md), and
`materialize()` when you need a real value. `materialize()` works on any view, not just the root, so you can turn just
the subtree you need into a value:
??? example "Example: parse a document, inspect its root, and materialize it"
```cpp
--8<-- "examples/json_document.cpp"
```
Output:
```json
--8<-- "examples/json_document.output"
```
[`ordered_json_document`](../../api/ordered_json_document.md) is the equivalent for
[`ordered_json`](../../api/ordered_json.md), just as [`ordered_json`](../../api/ordered_json.md) is to
[`json`](../../api/json.md).
A view behaves like a `basic_json` value in most respects, but not in all: lookups of a repeated key, the order in
which an object's members are visited, and what a missing key does to chained `operator[]` are the most visible
differences. [Differences from `basic_json`](differences.md) lists all of them.
## Where to go next
- [Ownership and lifetime](lifetime.md) - when a document borrows its source text, and how long a view stays valid
- [Differences from `basic_json`](differences.md) - everything a view does differently from a parsed `basic_json` value
- [Reading values](reading.md) - converting with `get<T>()`, reading strings and numbers without copying, and writing a
view back with `dump()`
- [Writing generic code](generic_code.md) - functions and `from_json()` overloads that accept views
- [Editing a document](editing.md) - patching a document in place, keeping its member order and number spellings
- [Images](images.md) - saving a parsed document and loading it back without parsing
## Choosing between `json`, `ordered_json`, the SAX interface, and `json_view`
| | [`json`](../../api/json.md) / [`ordered_json`](../../api/ordered_json.md) | [SAX interface](../parsing/sax_interface.md) | [`json_document`](../../api/json_document.md) / [`json_view`](../../api/json_view.md) | [`json_editable_document`](../../api/json_editable_document.md) / [`json_editable_view`](../../api/json_editable_view.md) |
|---|---|---|---|---|
| **Ownership** | owns every value | owns nothing; you decide what to keep, in your handler | borrows or owns the *text*; the index is always owned by the document | same as `json_document`; edits go to storage the document owns |
| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../../api/basic_json_document/set.md)/[`push_back`](../../api/basic_json_document/push_back.md)/[`insert`](../../api/basic_json_document/insert.md)/[`erase`](../../api/basic_json_document/erase.md) edit in place; the source text is never rewritten |
| **What you get** | a full tree you can read, write, and keep as long as you like | a sequence of callbacks; whatever your handler builds from them | a flat index plus, on demand, [`materialize()`](../../api/basic_json_view/materialize.md)d `json`/`ordered_json` values for the parts you actually use | the same, plus [`dump()`](../../api/basic_json_view/dump.md) of an edited document that keeps the member order and, with [`number_format::source`](../../api/basic_json_view/number_format.md), the spelling of every untouched number |
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back — a configuration file, for instance — where the rest of it should come back exactly as it was |
| **Caching/reload** | not applicable — re-parse, or roll your own serialization | not applicable | [`save()`](../../api/basic_json_document/save.md)/[`load()`](../../api/basic_json_document/load.md): cache the parsed index as an [image](images.md) and reload it without parsing | same, saving the document's current — possibly edited — state |
<p class="nj-table-caption" markdown>Each column is one way to work with JSON in this library, and each row compares one property of them.</p>
## See also
- [`basic_json_document`](../../api/basic_json_document/index.md) - the document that owns the parsed index (parse, access, images, edits)
- [`basic_json_view`](../../api/basic_json_view/index.md) - the non-owning handle to a value in a document
- [`json_document`](../../api/json_document.md) - and [`ordered_json_document`](../../api/ordered_json_document.md) - the read-only documents
- [`json_editable_document`](../../api/json_editable_document.md) - and [`ordered_json_editable_document`](../../api/ordered_json_editable_document.md) - the documents that can be edited in place
- [Architecture](../../home/architecture.md#node-index-of-json-views) - the layout of the node index
- [SAX interface](../parsing/sax_interface.md) - event-based parsing without building a tree
- [Performance](../performance.md) - benchmarks and tuning of parsing and serialization
- [Large, Streamed, and Partial Input](../parsing/large_and_partial_input.md) - reading only the part of a text you need
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,73 @@
# Ownership and lifetime
A document either **borrows** the text it was parsed from, or **owns** its own copy of it; call
[`owns_source()`](../../api/basic_json_document/owns_source.md) to find out which happened.
[`parse()`](../../api/basic_json_document/parse.md) decides this from the value category and type of its argument (an
lvalue `#!cpp std::string` is borrowed; an rvalue `#!cpp std::string` is moved in, owned without a copy; a stream is
read into an owned buffer; and so on — see [`parse`'s Notes](../../api/basic_json_document/parse.md#notes) for the
full table). [`parse_copy()`](../../api/basic_json_document/parse_copy.md) always owns a copy, regardless of the input.
!!! warning "A borrowed document depends on your buffer"
If a document borrows its text, that text **must outlive the document** (and every view taken from it) and must
stay **unmodified** for as long as the document exists, since floating-point values and unescaped strings are
read from it lazily. Reading or writing through a view after the underlying buffer is gone is undefined behavior,
exactly as it would be for a dangling `#!cpp std::string_view`.
## When a view is valid
A view is valid only while all of the following hold:
- the document is alive,
- the document has not been re-parsed since the view was taken (with
[`read()`](../../api/basic_json_document/read.md) or [`parse()`](../../api/basic_json_document/parse.md) into it),
- the document has not had [`shrink_to_fit()`](../../api/basic_json_document/shrink_to_fit.md) called on it since, and
- if the document borrows its source text, that text is still alive and unmodified.
Moving the `basic_json_document<>` itself is fine and does **not** invalidate its views: the index is a separate heap
allocation that keeps its address across the move. Take a fresh view from
[`root()`](../../api/basic_json_document/root.md) whenever any of the other conditions above was not met. Edits of an
[editable document](editing.md) keep views valid, too; see [What stays valid](editing.md#what-stays-valid-and-what-an-edit-costs).
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_lifetime.svg"
</div>
<p class="nj-caption" markdown>Four timelines of a document and its views, each bar showing when an object is alive or valid and when it dangles. Destroying the borrowed text, re-parsing, or shrinking the document invalidates the views taken before; moving the document does not.</p>
## Why views can dangle
A view can dangle, exactly like a `#!cpp std::string_view`: nothing stops you from using it after its document is
gone. This is deliberate. A view is two pointers and trivially copyable; making it safe (a `#!cpp std::shared_ptr` in
the document and a `#!cpp std::weak_ptr` in each view) would make it larger, add reference counting to every copy,
and a `lock()` to every access — exactly the costs the view exists to avoid. What is caught is the obvious case:
because a view dies with its document, [`root()`](../../api/basic_json_document/root.md) is not callable on a
temporary document: `#!cpp auto v = json_document::parse(text).root();` does not compile. Give the document a name
first.
The same holds for what a view hands out without copying: a string from
[`get_string()`](../../api/basic_json_view/get_string.md), a token from
[`number_token()`](../../api/basic_json_view/number_token.md), and [`string_view` members](reading.md#string_view-members)
of decoded structs are valid only as long as the document and, if it borrows, its source text.
??? example "Example: borrowed and owned documents, and when views become invalid"
```cpp
--8<-- "examples/json_view_ownership.cpp"
```
Output:
```json
--8<-- "examples/json_view_ownership.output"
```
## See also
- [Zero-copy JSON views](index.md) - overview
- [`basic_json_document`](../../api/basic_json_document/index.md) - the document that owns the parsed index
- [`owns_source()`](../../api/basic_json_document/owns_source.md) - whether a document borrows its source text
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,83 @@
# Reading values
## Getting values out without copying
[`get<T>()`](../../api/basic_json_view/get.md) converts most `T` directly from the flat index, without ever building a
`basic_json` value for the conversion: `#!cpp bool`, arithmetic types, `#!cpp std::nullptr_t`,
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json_view` itself, the standard containers
and other types the library converts (`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::list`, `#!cpp std::array`,
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, ...), and the types of the `NLOHMANN_DEFINE_TYPE_*` and
`NLOHMANN_JSON_SERIALIZE_ENUM` macros. Types whose `from_json()` is written for `basic_json` only go through
[`materialize()`](../../api/basic_json_view/materialize.md)`.get<T>()` instead: the subtree is built into a real
`basic_json` value first, exactly as [`parse()`](../../api/basic_json/parse.md) would, and converted from there. See
[A `from_json()` that reads views](generic_code.md#a-from_json-that-reads-views) for how to write a `from_json()` that
reads views, and [Duplicate keys](differences.md#duplicate-keys) for the one case in which the two ways give different
results.
Two conversions never copy at all:
- [`get_string()`](../../api/basic_json_view/get_string.md) (equivalently, `#!cpp get<string_view_t>()`) returns a
string as a `string_view_t` pointing into the document's [`source()`](../../api/basic_json_document/source.md) text
— or, for a string that contains escape sequences, into the document's own buffer of decoded strings — instead of
allocating a new `#!cpp std::string`.
- [`number_token()`](../../api/basic_json_view/number_token.md) returns a number exactly as it was written in the
source, e.g. `#!cpp "1.50"`, `#!cpp "1E2"`, or an integer with more digits than any number type holds, instead of
rounding it into a `#!cpp double`/`#!cpp int64_t` the way `#!cpp get<T>()` (and
[`basic_json::parse()`](../../api/basic_json/parse.md)) would.
Both results are only valid as long as the document and, if it [borrows its source text](lifetime.md), that text.
### `string_view` members
A struct whose member is a `#!cpp std::string_view` (C++17) can be decoded from a view with the
`NLOHMANN_DEFINE_TYPE_*` macros, and the member is not copied either: for a string without escape sequences it points
into the document's source text, and for a string with escape sequences into the document's buffer of decoded
strings. The member is valid as long as the document is alive and, for a document that
[borrows its source text](lifetime.md) (as [`parse()`](../../api/basic_json_document/parse.md) does for an lvalue
`#!cpp std::string`, a `#!cpp std::string_view`, or a C string), as long as that text is.
```cpp
struct record
{
std::string_view name;
int count;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(record, name, count)
};
const std::string text = R"({"name": "widget", "count": 3})";
const json_document doc = json_document::parse(text); // borrows text
const record r = doc.root().get<record>(); // r.name points into text, valid while text and doc are
```
!!! warning "Decoding into a `string_view` from a `json` value dangles at once"
The same struct also compiles with `#!cpp json::parse(text).get<record>()`, but there `name` points into the
temporary `json` value, which is destroyed at the end of the statement. Use a named
[`json_document`](../../api/json_document.md), as above, to decode such a struct.
## Writing a view back
[`dump()`](../../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
`basic_json` value. It writes object members in document order and every occurrence of a repeated key, so it can
differ from `#!cpp materialize().dump()`; see [Serialization](differences.md#serialization).
By default, numbers are written the way [`basic_json::dump()`](../../api/basic_json/dump.md) would.
[`number_format::source`](../../api/basic_json_view/number_format.md) instead copies every number exactly as it was
written in the source text — a price like `#!cpp 19.90`, a long order or account ID with more digits than any number
type holds, or a high-precision coordinate — something `basic_json` cannot do at all, since parsing already reduces
a number to its parsed `#!cpp double`/`#!cpp int64_t` value. Together with an [editable document](editing.md), this
lets you patch a file without reformatting the rest of it.
[`operator<<`](../../api/basic_json_view/operator_ltlt.md) writes a view to a stream the way `basic_json`'s does, using
the stream's `width`/`fill` for indentation.
## See also
- [Zero-copy JSON views](index.md) - overview
- [`get`](../../api/basic_json_view/get.md) - convert a view
- [`dump`](../../api/basic_json_view/dump.md) - serialize a view
- [Writing generic code](generic_code.md) - functions and `from_json()` overloads that accept views
## Version history
- Added in version 3.13.0.
@@ -88,7 +88,7 @@ a.erase(1); // [1,3,4] (erase by index)
## Editing a document
The operations above work on a `basic_json` value. A JSON text that was parsed into a
[document](json_view.md#editing-a-document) can also be changed in place, without building a `basic_json` tree for the
[document](json_view/editing.md) can also be changed in place, without building a `basic_json` tree for the
parts that are not touched: [`set`](../api/basic_json_document/set.md) replaces a value, adds or replaces an object
member, or replaces an array element (also through a JSON pointer),
[`push_back`](../api/basic_json_document/push_back.md) appends to an array,
@@ -105,7 +105,7 @@ editable document types, such as [`json_editable_document`](../api/json_editable
- [`merge_patch`](../api/basic_json/merge_patch.md) - apply an RFC 7396 merge patch
- [`erase`](../api/basic_json/erase.md) - / [`clear`](../api/basic_json/clear.md) - remove elements
- [JSON Patch and Diff](json_patch.md) - and [JSON Merge Patch](merge_patch.md) - structured modifications
- [Editing a document](json_view.md#editing-a-document) - change a parsed document in place
- [Editing a document](json_view/editing.md) - change a parsed document in place
- [`insert`](../api/basic_json/insert.md) - insert elements at an iterator position or merge a range
- [`operator+=`](../api/basic_json/operator+=.md) - shorthand for `push_back`
- [Element Access](element_access/index.md) - read elements
+5 -5
View File
@@ -77,7 +77,7 @@ them faster than others:
|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| strings, string views, string literals, contiguous containers, pointer or iterator ranges over contiguous memory | the whole input is scanned in bulk: runs of string characters, numbers, and indentation are recognized several bytes at a time |
| `#!cpp std::istream` (`#!cpp std::ifstream`, `#!cpp std::istringstream`, ...) | the characters the stream buffer holds are scanned in bulk like a string; the stream buffer is asked for more when they are used up |
| `#!cpp FILE*` | with glibc and the Apple C library, the characters the `FILE` holds in its buffer are scanned in bulk like a stream's; elsewhere one character at a time; the file is locked once for the whole parse |
| `#!cpp FILE*` | one character at a time, with the file locked once for the whole parse |
| other iterator ranges (e.g., `#!cpp std::list<char>`, `#!cpp std::istreambuf_iterator<char>`), wide strings | one character at a time |
Parsing a file from a `#!cpp std::ifstream` is therefore only about 10 to 20 % slower than reading the whole file into a
@@ -86,7 +86,7 @@ ahead: after parsing, it is positioned exactly as if every character had been re
[`operator>>`](../../api/operator_gtgt.md) can still read several values from one stream (see also
[JSON Lines](json_lines.md)).
This does not hold for [`json_document`](../json_view.md): it reads a stream into a buffer it owns, so the stream saves
This does not hold for [`json_document`](../json_view/index.md): it reads a stream into a buffer it owns, so the stream saves
no memory, and reading the file into a `#!cpp std::string` yourself and borrowing it is about 6 to 12 % faster.
Two macros switch these optimizations off without changing any result:
@@ -115,7 +115,7 @@ The library offers two parsing models, and a third, read-only alternative:
reads the same JSON grammar but builds a flat, read-only index of the values instead of a `basic_json` tree. Strings and
floating-point numbers are read from the text on demand, and only the parts you
[`materialize()`](../../api/basic_json_view/materialize.md) become `basic_json` values. This avoids most of the work when you
need only a few values from a large or frequently parsed text; see [Zero-copy JSON views](../json_view.md). It is read-only, so use
need only a few values from a large or frequently parsed text; see [Zero-copy JSON views](../json_view/index.md). It is read-only, so use
`parse` when you need to modify the value.
You can influence a DOM parse without switching to the SAX interface by passing a
@@ -139,7 +139,7 @@ json_document doc = json_document::parse(R"({"happy": true, "pi": 3.141})");
std::cout << doc.root()["happy"].get<bool>() << '\n';
```
See [Zero-copy JSON views](../json_view.md) for the concept and the trade-offs.
See [Zero-copy JSON views](../json_view/index.md) for the concept and the trade-offs.
## Exceptions
@@ -158,7 +158,7 @@ options.
- [Large, streamed, and partial input](large_and_partial_input.md) - chunked, concatenated, and very large input
- [parser callbacks](parser_callbacks.md) - influence the parsing by a callback function
- [SAX interface](sax_interface.md) - implement a custom SAX handler
- [Zero-copy JSON views](../json_view.md) - parse into a read-only document and read it through views
- [Zero-copy JSON views](../json_view/index.md) - parse into a read-only document and read it through views
- [parsing and exceptions](parse_exceptions.md) - control error handling
- [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources
- [`operator>>`](../../api/operator_gtgt.md) - deserialize from stream
@@ -156,11 +156,11 @@ record the reason in the handler (here: `id`) if you need to tell the two apart.
### Read parts of a large document with a view
If the whole text is available and you only need to read some of it, a [`json_document`](../json_view.md) from
If the whole text is available and you only need to read some of it, a [`json_document`](../json_view/index.md) from
`<nlohmann/json_view.hpp>` (added in version 3.13.0) avoids the `basic_json` tree altogether: it keeps the text, builds a flat index of the values,
and gives read-only [views](../../api/basic_json_view/index.md) of the parts you look at. Only what you
[`materialize()`](../../api/basic_json_view/materialize.md) becomes a `basic_json` value. See
[Zero-copy JSON views](../json_view.md) for details and for the lifetime rules.
[Zero-copy JSON views](../json_view/index.md) for details and for the lifetime rules.
## See also
@@ -168,7 +168,7 @@ and gives read-only [views](../../api/basic_json_view/index.md) of the parts you
- [JSON Lines](json_lines.md) - newline-delimited JSON
- [Parser callbacks](parser_callbacks.md) - discard values while parsing
- [SAX interface](sax_interface.md) - event-based parsing
- [Zero-copy JSON views](../json_view.md) - read parts of a large document without building a tree
- [Zero-copy JSON views](../json_view/index.md) - read parts of a large document without building a tree
- [Untrusted input](untrusted_input.md) - limits for input you do not control
- [`operator>>`](../../api/operator_gtgt.md) - deserialize from stream
- [`parse`](../../api/basic_json/parse.md) - deserialize from a compatible input
+8 -8
View File
@@ -27,8 +27,8 @@ A `#!cpp std::istream` (including `#!cpp std::ifstream`) gets the same bulk scan
characters its stream buffer already holds (the *get area*) and asks the stream buffer for more only when they are used
up. Nothing is read ahead, so the stream is left exactly where it would be after reading one character at a time, and
[`operator>>`](../api/operator_gtgt.md) can still read several values from one stream. A stream buffer without a get
area is read one character at a time. A `#!cpp FILE*` is locked once per parse instead of once per character, and with
glibc and the Apple C library, the characters in its buffer are scanned in bulk as a stream's get area is. See
area is read one character at a time. A `#!cpp FILE*` is still read one character at a time, but `file_input_adapter`
locks the file once per parse instead of once per character. See
[input sources and performance](parsing/index.md#input-sources-and-performance) for the full table. According to the
description of [#5828](https://github.com/nlohmann/json/pull/5828), parsing from a stream is within about 10 to 20 % of
parsing an equivalent `#!cpp std::string`.
@@ -40,7 +40,7 @@ optimization but not the second, since the byte-scanning fast path requires cont
Practically: a file can be passed directly to `parse`, which also avoids the memory for a copy of the file. Reading it
into a string first is no longer necessary for speed (this is for `#!cpp json::parse`; a
[`json_document`](json_view.md) reads a stream into an owned buffer anyway, so for it reading the file into a string
[`json_document`](json_view/index.md) reads a stream into an owned buffer anyway, so for it reading the file into a string
and borrowing that is the faster way):
```cpp
@@ -73,12 +73,12 @@ a DOM, three alternatives avoid building it:
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
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
- Parse into a [`json_document`](json_view/index.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
read from the text when needed. Read-only [views](../api/basic_json_view/index.md) give the familiar element access, and only the
parts you [`materialize()`](../api/basic_json_view/materialize.md) become `basic_json` values. A document that
borrows the text instead of owning a copy needs the text to outlive it; see
[choosing between `json`, the SAX interface, and `json_view`](json_view.md#choosing-between-json-ordered_json-the-sax-interface-and-json_view).
[choosing between `json`, the SAX interface, and `json_view`](json_view/index.md#choosing-between-json-ordered_json-the-sax-interface-and-json_view).
If the data is naturally record-oriented, consider [JSON Lines](parsing/json_lines.md) instead of one large JSON
document: reading and parsing it line by line with `#!cpp std::getline` means only one line's value is ever in memory
@@ -182,11 +182,11 @@ an adapter, since their template argument order does not match what `basic_json`
large value therefore doubles its memory; see [Avoiding copies](#avoiding-copies). `#!cpp auto x = j["key"];` is a
copy, `#!cpp auto& x = j["key"];` is not.
- **A moved-from value is `null`.** After `#!cpp json c = std::move(a);` the value `a` is `#!json null` and owns nothing.
- **Reading does not require a tree.** If you only read the data, parse it into a [`json_document`](json_view.md)
- **Reading does not require a tree.** If you only read the data, parse it into a [`json_document`](json_view/index.md)
(`#!cpp <nlohmann/json_view.hpp>`, added in version 3.13.0) instead of a `basic_json`. It stores 16 bytes per value, does not copy floating-point
numbers or strings without escape sequences out of the text, and creates no `basic_json` value except for the parts
you [`materialize()`](../api/basic_json_view/materialize.md). A document that borrows the text needs the text to
outlive it; see [Zero-copy JSON views](json_view.md).
outlive it; see [Zero-copy JSON views](json_view/index.md).
- **Containers keep their capacity.** `clear()` and `erase()` on an array remove the elements, but the underlying
`#!cpp std::vector` keeps its allocated capacity, like `#!cpp std::vector::clear` does. To give the memory back,
assign a new value (`#!cpp j = json::array();`) or destroy the value.
@@ -267,7 +267,7 @@ those headers are then never processed by the compiler at all.
- [Architecture](../home/architecture.md) - how input adapters, the lexer, and the serializer fit together
- [Parsing](parsing/index.md) - the available parsing functions and inputs
- [SAX interface](parsing/sax_interface.md) - parse without building a DOM
- [Zero-copy JSON views](json_view.md) - parse into a flat index of the text and read it without building a DOM
- [Zero-copy JSON views](json_view/index.md) - parse into a flat index of the text and read it without building a DOM
- [Binary formats](binary_formats/index.md) - compact alternatives to JSON text
- [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
+3 -3
View File
@@ -56,7 +56,7 @@ The public headers are in [`include/nlohmann`](https://github.com/nlohmann/json/
- [`json_view.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_view.hpp) is a separate,
optional header that defines [`basic_json_document`](../api/basic_json_document/index.md) and
[`basic_json_view`](../api/basic_json_view/index.md), a flat-index, read-only, non-owning way to look at a parsed
JSON text; see [Zero-copy JSON views](../features/json_view.md). It builds on `json.hpp` internals (it requires the
JSON text; see [Zero-copy JSON views](../features/json_view/index.md). It builds on `json.hpp` internals (it requires the
same library version) and has its own `detail/view/` subdirectory.
Everything else lives in [`detail/`](https://github.com/nlohmann/json/tree/develop/include/nlohmann/detail) and namespace `nlohmann::detail`, which is not part of the public API. Paths
@@ -175,7 +175,7 @@ maintains the invariant that the pointer matching `m_type` is never null; `asser
## Node index of JSON views
A [`basic_json_document`](../api/basic_json_document/index.md) (see [Zero-copy JSON views](../features/json_view.md))
A [`basic_json_document`](../api/basic_json_document/index.md) (see [Zero-copy JSON views](../features/json_view/index.md))
does not build a tree of values. Its parser
([`detail/view/builder.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/view/builder.hpp))
writes a flat array of 16-byte nodes, one per value and one per object key, in document order. A
@@ -466,7 +466,7 @@ release. Besides the components above, it contains:
- [`adl_serializer`](../api/adl_serializer/index.md) - customization point for type conversions
- [`json_sax`](../api/json_sax/index.md) - interface of the SAX parser events
- [SAX Interface](../features/parsing/sax_interface.md) - how to consume parser events without building a DOM
- [Zero-copy JSON views](../features/json_view.md) - the flat node index that backs views and documents
- [Zero-copy JSON views](../features/json_view/index.md) - the flat node index that backs views and documents
- [Template Parameter Requirements](../features/types/template_parameters.md) - the template parameters of basic_json
- [Serialization](../features/serialization.md) - the output side of the library
- [`nlohmann` Namespace](../features/namespace.md) - how the library namespace is structured
File diff suppressed because it is too large. Load diff
+7 -7
View File
@@ -438,7 +438,7 @@ A UBJSON or BJData high-precision number could not be parsed.
### json.exception.parse_error.116
[`basic_json_document::load()`](../api/basic_json_document/load.md) rejected an
[image](../features/json_view.md#images): either the bytes are not one [`save()`](../api/basic_json_document/save.md)
[image](../features/json_view/images.md): either the bytes are not one [`save()`](../api/basic_json_document/save.md)
could have written (too short, an unknown magic number or format version, or sizes that do not fit the buffer), or
they are, but fail the requested [`image_check`](../api/basic_json_document/load.md#image_check).
@@ -450,7 +450,7 @@ they are, but fail the requested [`image_check`](../api/basic_json_document/load
!!! note
This exception was added in version 3.13.0, together with [images](../features/json_view.md#images).
This exception was added in version 3.13.0, together with [images](../features/json_view/images.md).
## Iterator errors
@@ -889,12 +889,12 @@ from JSON text.
!!! note
This exception was added in version 3.13.0, together with editable [`json_document`s](../features/json_view.md).
This exception was added in version 3.13.0, together with editable [`json_document`s](../features/json_view/editing.md).
### json.exception.type_error.320
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
[image](../features/json_view.md#images) of a [discarded](../api/basic_json_document/is_discarded.md) document.
[image](../features/json_view/images.md) of a [discarded](../api/basic_json_document/is_discarded.md) document.
!!! failure "Example messages"
@@ -904,7 +904,7 @@ from JSON text.
!!! note
This exception was added in version 3.13.0, together with [images](../features/json_view.md#images).
This exception was added in version 3.13.0, together with [images](../features/json_view/images.md).
### json.exception.type_error.321
@@ -1192,7 +1192,7 @@ so they do not support an input of 4294967280 bytes (4 GiB minus 16 bytes) or mo
storage: [`set`](../api/basic_json_document/set.md) and [`push_back`](../api/basic_json_document/push_back.md) throw
this exception once the strings and number tokens written by edits reach 4 GiB in total, or once more than
4294967295 arrays/objects have had an element set or appended to them. The same limit applies to an
[image](../features/json_view.md#images): [`save()`](../api/basic_json_document/save.md) throws it if the node
[image](../features/json_view/images.md): [`save()`](../api/basic_json_document/save.md) throws it if the node
count, the text, or the decoded strings it would write would individually reach 4 GiB.
!!! failure "Example messages"
@@ -1209,7 +1209,7 @@ count, the text, or the decoded strings it would write would individually reach
!!! note
This exception was added in version 3.13.0, together with [`<nlohmann/json_view.hpp>`](../features/json_view.md).
This exception was added in version 3.13.0, together with [`<nlohmann/json_view.hpp>`](../features/json_view/index.md).
[`basic_json::parse()`](../api/basic_json/parse.md) has no such limit.
## Further exceptions
+1 -1
View File
@@ -140,7 +140,7 @@ Read newline-delimited input line by line ([JSON Lines](../features/parsing/json
Handle and discard the records of a large array with a [parser callback](../features/parsing/parser_callbacks.md), stop
early with the [SAX interface](../features/parsing/sax_interface.md), or read parts of the text through a
[`json_document`](../features/json_view.md) (added in version 3.13.0). See
[`json_document`](../features/json_view/index.md) (added in version 3.13.0). See
[Input too large for memory](../features/parsing/large_and_partial_input.md#input-too-large-for-memory).
### Position of a parse error
+5 -5
View File
@@ -17,16 +17,16 @@
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M76 115 L106 115" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="108" y="98" width="84" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="150" y="120" text-anchor="middle" xml:space="preserve">std::map</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 67" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 67 226 67" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="50" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="72" xml:space="preserve">&quot;port&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="72" text-anchor="end" xml:space="preserve">6379</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 115" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 115 226 115" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="98" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="120" xml:space="preserve">&quot;price&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="120" text-anchor="end" xml:space="preserve">19.9</text>
<text class="nj-jsonview-note" x="418" y="120" xml:space="preserve">double: 19.90 is gone</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 163" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 163 226 163" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="146" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="168" xml:space="preserve">&quot;tags&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-line" x="396" y="168" text-anchor="end" xml:space="preserve">•</text>
@@ -38,8 +38,8 @@
<path class="nj-jsonview-sep" d="M624 146 V180"/>
<text class="nj-jsonview-mono" x="601" y="168" text-anchor="middle" xml:space="preserve">json</text>
<text class="nj-jsonview-mono" x="647" y="168" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 130 641 130 706 130" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 196 687 196 706 196" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 126 706 150 706 130" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 200 706 176 706 196" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="708" y="113" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="135" text-anchor="middle" xml:space="preserve">std::string eu</text>
<rect class="nj-jsonview-heap" x="708" y="179" width="126" height="34" rx="5"/>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@@ -1,148 +0,0 @@
<svg class="nj-fig nj-jsonview " viewBox="0 0 840 456" role="img" aria-labelledby="fig-jvli-title fig-jvli-title-d" xmlns="http://www.w3.org/2000/svg">
<title id="fig-jvli-title">The same J&#8203;SON text parsed by json_document::parse()</title>
<desc id="fig-jvli-title-d">The same text parsed by json_document::parse(): it keeps the 54 bytes of source text and builds a flat index of nine 16-byte nodes in document order: object, key port, unsigned integer 6379 (the converted value is in the node), key price, float, key tags, array, string eu, and an escaped string. Keys, the float, and the plain string point back into the source text; the escaped string points into the document&#x27;s buffer of decoded strings. A json_view is two pointers: one to the document and one to a node, here the array.</desc>
<defs>
<marker id="jvli-line" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-str" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-key" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-num" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-dec" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-own" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-struct" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-bad" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
</defs>
<g transform="translate(0 -236)">
<text class="nj-jsonview-h" x="16" y="262" xml:space="preserve">json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes</text>
<text class="nj-jsonview-note" x="16" y="290" xml:space="preserve">source text, 54 bytes (borrowed, or owned by the document)</text>
<rect class="nj-jsonview-ribbon" x="42" y="300" width="756" height="26" rx="4"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="71" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-num" x="169" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="267" y="302" width="68" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-num" x="379" y="302" width="68" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="491" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-str" x="617" y="302" width="26" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-dec" x="701" y="302" width="54" height="22" rx="3"/>
<text class="nj-jsonview-mono nj-jsonview-byte" x="49" y="317.5" text-anchor="middle" xml:space="preserve">{</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="63" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="77" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="91" y="317.5" text-anchor="middle" xml:space="preserve">o</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="105" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="119" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="133" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="147" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="175" y="317.5" text-anchor="middle" xml:space="preserve">6</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="189" y="317.5" text-anchor="middle" xml:space="preserve">3</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="203" y="317.5" text-anchor="middle" xml:space="preserve">7</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="217" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="231" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="259" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="273" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="287" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="301" y="317.5" text-anchor="middle" xml:space="preserve">i</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="315" y="317.5" text-anchor="middle" xml:space="preserve">c</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="329" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="343" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="357" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="385" y="317.5" text-anchor="middle" xml:space="preserve">1</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="399" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="413" y="317.5" text-anchor="middle" xml:space="preserve">.</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="427" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="441" y="317.5" text-anchor="middle" xml:space="preserve">0</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="455" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="483" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="497" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="511" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="525" y="317.5" text-anchor="middle" xml:space="preserve">g</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="539" y="317.5" text-anchor="middle" xml:space="preserve">s</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="553" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="567" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="595" y="317.5" text-anchor="middle" xml:space="preserve">[</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="609" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="623" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="637" y="317.5" text-anchor="middle" xml:space="preserve">u</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="651" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="665" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="693" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="707" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="721" y="317.5" text-anchor="middle" xml:space="preserve">\</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="735" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="749" y="317.5" text-anchor="middle" xml:space="preserve">b</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="763" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="777" y="317.5" text-anchor="middle" xml:space="preserve">]</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="791" y="317.5" text-anchor="middle" xml:space="preserve">}</text>
<text class="nj-jsonview-tiny" x="49" y="340" text-anchor="middle" xml:space="preserve">0</text>
<text class="nj-jsonview-tiny" x="189" y="340" text-anchor="middle" xml:space="preserve">10</text>
<text class="nj-jsonview-tiny" x="329" y="340" text-anchor="middle" xml:space="preserve">20</text>
<text class="nj-jsonview-tiny" x="469" y="340" text-anchor="middle" xml:space="preserve">30</text>
<text class="nj-jsonview-tiny" x="609" y="340" text-anchor="middle" xml:space="preserve">40</text>
<text class="nj-jsonview-tiny" x="749" y="340" text-anchor="middle" xml:space="preserve">50</text>
<rect class="nj-jsonview-frame" x="16" y="366" width="808" height="254" rx="10"/>
<text class="nj-jsonview-note nj-jsonview-strong" x="30" y="602" xml:space="preserve">json_document: owns the node index and the buffer of decoded strings</text>
<text class="nj-jsonview-note" x="30" y="500" xml:space="preserve">node index: 9 nodes × 16 bytes = 144 bytes, in document order</text>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="36" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="42" y="420" xml:space="preserve">0</text>
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="78" y="434" text-anchor="middle" xml:space="preserve">object</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="451" text-anchor="middle" xml:space="preserve">len 3</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="465" text-anchor="middle" xml:space="preserve">next 9</text>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="124" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="130" y="420" xml:space="preserve">1</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="166" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="451" text-anchor="middle" xml:space="preserve">off 2</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M166 406 C166 367 98 367 98 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-num" x="212" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="218" y="420" xml:space="preserve">2</text>
<text class="nj-jsonview-kind nj-jsonview-c-num" x="254" y="434" text-anchor="middle" xml:space="preserve">uint</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="451" text-anchor="middle" xml:space="preserve">6379</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="465" text-anchor="middle" xml:space="preserve">(converted)</text>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="300" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="306" y="420" xml:space="preserve">3</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="342" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="451" text-anchor="middle" xml:space="preserve">off 16</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M342 406 C342 367 301 367 301 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-num" x="388" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="394" y="420" xml:space="preserve">4</text>
<text class="nj-jsonview-kind nj-jsonview-c-num" x="430" y="434" text-anchor="middle" xml:space="preserve">float</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="451" text-anchor="middle" xml:space="preserve">off 24</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
<path class="nj-jsonview-arr nj-jsonview-c-num" d="M430 406 C430 367 413 367 413 328" marker-end="url(#jvli-num)"/>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="476" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="482" y="420" xml:space="preserve">5</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="518" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="451" text-anchor="middle" xml:space="preserve">off 32</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M518 406 C518 367 518 367 518 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="564" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="570" y="420" xml:space="preserve">6</text>
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="606" y="434" text-anchor="middle" xml:space="preserve">array</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="451" text-anchor="middle" xml:space="preserve">len 2</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="465" text-anchor="middle" xml:space="preserve">next 3</text>
<rect class="nj-jsonview-node nj-jsonview-c-str" x="652" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="658" y="420" xml:space="preserve">7</text>
<text class="nj-jsonview-kind nj-jsonview-c-str" x="694" y="434" text-anchor="middle" xml:space="preserve">string</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="451" text-anchor="middle" xml:space="preserve">off 41</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="465" text-anchor="middle" xml:space="preserve">len 2</text>
<path class="nj-jsonview-arr nj-jsonview-c-str" d="M694 406 C694 367 630 367 630 328" marker-end="url(#jvli-str)"/>
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="746" y="420" xml:space="preserve">8</text>
<text class="nj-jsonview-kind nj-jsonview-c-dec" x="782" y="434" text-anchor="middle" xml:space="preserve">string</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="451" text-anchor="middle" xml:space="preserve">escaped</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="465" text-anchor="middle" xml:space="preserve">len 3</text>
<text class="nj-jsonview-note" x="773" y="568" text-anchor="middle" xml:space="preserve">decoded strings</text>
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="518" width="66" height="30" rx="4"/>
<text class="nj-jsonview-mono" x="751" y="538" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono" x="773" y="538" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono" x="795" y="538" text-anchor="middle" xml:space="preserve">b</text>
<path class="nj-jsonview-arr nj-jsonview-c-dec" d="M782 474 C782 496 773 496 773 518" marker-end="url(#jvli-dec)"/>
<text class="nj-jsonview-mono nj-jsonview-sm" x="470" y="670" text-anchor="end" xml:space="preserve">json_view v = doc.root()[&quot;tags&quot;]</text>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="480" y="648" width="140" height="34" rx="6"/>
<path class="nj-jsonview-sep" d="M550 648 V682"/>
<text class="nj-jsonview-mono" x="515" y="670" text-anchor="middle" xml:space="preserve">doc*</text>
<text class="nj-jsonview-mono" x="585" y="670" text-anchor="middle" xml:space="preserve">node*</text>
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M515 648 L515 622" marker-end="url(#jvli-struct)"/>
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M585 648 C585 561 606 561 606 474" marker-end="url(#jvli-struct)"/>
<text class="nj-jsonview-note" x="30" y="524" xml:space="preserve">integers are converted while parsing and kept in their node;</text>
<text class="nj-jsonview-note" x="30" y="542" xml:space="preserve">floats and strings point back into the text</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 17 KiB

@@ -1,49 +0,0 @@
<svg class="nj-fig nj-jsonview " viewBox="0 0 840 222" role="img" aria-labelledby="fig-jvlt-title fig-jvlt-title-d" xmlns="http://www.w3.org/2000/svg">
<title id="fig-jvlt-title">A J&#8203;SON text parsed by basic_json::parse()</title>
<desc id="fig-jvlt-title-d">The text {&quot;port&quot;: 6379, &quot;price&quot;: 19.90, &quot;tags&quot;: [&quot;eu&quot;, &quot;a\&quot;b&quot;]} parsed by basic_json::parse(): the root json value points to a std::map whose three nodes are separate heap allocations; the price is stored as the double 19.9; the tags array is a std::vector of two json values, each pointing to its own std::string.</desc>
<defs>
<marker id="jvlt-line" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-str" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-key" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-num" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-dec" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-own" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-struct" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-bad" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
</defs>
<text class="nj-jsonview-h" x="16" y="26" xml:space="preserve">basic_json::parse(): a tree, every array, object, and string in its own heap allocation</text>
<rect class="nj-jsonview-box" x="16" y="98" width="60" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="46" y="120" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M76 115 L106 115" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="108" y="98" width="84" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="150" y="120" text-anchor="middle" xml:space="preserve">std::map</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 67" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="50" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="72" xml:space="preserve">&quot;port&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="72" text-anchor="end" xml:space="preserve">6379</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 115" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="98" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="120" xml:space="preserve">&quot;price&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="120" text-anchor="end" xml:space="preserve">19.9</text>
<text class="nj-jsonview-note" x="418" y="120" xml:space="preserve">double: 19.90 is gone</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="146" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="168" xml:space="preserve">&quot;tags&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-line" x="396" y="168" text-anchor="end" xml:space="preserve">•</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M408 163 L442 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="444" y="146" width="104" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="496" y="168" text-anchor="middle" xml:space="preserve">std::vector</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M548 163 L576 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="578" y="146" width="92" height="34" rx="5"/>
<path class="nj-jsonview-sep" d="M624 146 V180"/>
<text class="nj-jsonview-mono" x="601" y="168" text-anchor="middle" xml:space="preserve">json</text>
<text class="nj-jsonview-mono" x="647" y="168" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 130 641 130 706 130" marker-end="url(#jvlt-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 196 687 196 706 196" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="708" y="113" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="135" text-anchor="middle" xml:space="preserve">std::string eu</text>
<rect class="nj-jsonview-heap" x="708" y="179" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="201" text-anchor="middle" xml:space="preserve">std::string a&quot;b</text>
<rect class="nj-jsonview-heap" x="16" y="186" width="18" height="14" rx="3"/>
<text class="nj-jsonview-note" x="42" y="198" xml:space="preserve">a separate heap allocation</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

@@ -1,69 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 600 380" role="img" aria-labelledby="nj-blog-cliffs nj-blog-cliffs-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-cliffs">Operations that grew quadratically or worse: time with 3.12.0 and 3.13.0, log scale</title>
<desc id="nj-blog-cliffs-d">Dot plot on a logarithmic time axis, less is better; an arrow leads from each 3.12.0 time to the 3.13.0 time. diff() 64k numbers vs []: 4237 ms to 10.8 ms; diff() 20k objects vs half: 122 ms to 4.13 ms; parse() callback, 32k objects: 1398 ms to 12.1 ms; operator&lt; nested 24 deep: 64.4 ms to 0.002 ms; operator&lt; citm, 10x: 284 ms to 3.94 ms; flatten() citm, ordered_json: 271 ms to 1.45 ms; to_bson() 200 deep, 100x: 20.3 ms to 0.352 ms; push_back() 100k, diagnostics: 1589 ms to 5.32 ms; at(i) 10k, diagnostics: 45.9 ms to 0.088 ms.</desc>
<line class="nj-charts-grid" x1="250" y1="30" x2="250" y2="336"/>
<text class="nj-charts-tick" x="250" y="352">1 µs</text>
<line class="nj-charts-grid" x1="297.857" y1="30" x2="297.857" y2="336"/>
<text class="nj-charts-tick" x="297.857" y="352">10 µs</text>
<line class="nj-charts-grid" x1="345.714" y1="30" x2="345.714" y2="336"/>
<text class="nj-charts-tick" x="345.714" y="352">0.1 ms</text>
<line class="nj-charts-grid" x1="393.571" y1="30" x2="393.571" y2="336"/>
<text class="nj-charts-tick" x="393.571" y="352">1 ms</text>
<line class="nj-charts-grid" x1="441.429" y1="30" x2="441.429" y2="336"/>
<text class="nj-charts-tick" x="441.429" y="352">10 ms</text>
<line class="nj-charts-grid" x1="489.286" y1="30" x2="489.286" y2="336"/>
<text class="nj-charts-tick" x="489.286" y="352">0.1 s</text>
<line class="nj-charts-grid" x1="537.143" y1="30" x2="537.143" y2="336"/>
<text class="nj-charts-tick" x="537.143" y="352">1 s</text>
<line class="nj-charts-grid" x1="585" y1="30" x2="585" y2="336"/>
<text class="nj-charts-tick" x="585" y="352">10 s</text>
<text class="nj-charts-tick" x="417.5" y="370">runtime (log scale), less is better</text>
<defs><marker id="nj-blog-cliffs-head" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path class="nj-charts-head" d="M0 0 L10 5 L0 10 z"/></marker></defs>
<circle class="nj-charts-ojson-dot" cx="250" cy="14" r="5"/><text class="nj-charts-leg" x="260" y="18.5">3.12.0</text>
<circle class="nj-charts-json-dot" cx="330" cy="14" r="5"/><text class="nj-charts-leg" x="340" y="18.5">3.13.0</text>
<text class="nj-charts-rowlabel" x="240" y="52" text-anchor="end">diff() 64k numbers vs []</text>
<line class="nj-charts-axis" x1="561.152" y1="48" x2="450.028" y2="48" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="567.152" cy="48" r="5"><title>diff() 64k numbers vs [], 3.12.0: 4237 ms</title></circle>
<circle class="nj-charts-json-dot" cx="443.028" cy="48" r="5"><title>diff() 64k numbers vs [], 3.13.0: 10.8 ms</title></circle>
<text class="nj-charts-factor" x="505.09" y="41">392&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="86" text-anchor="end">diff() 20k objects vs half</text>
<line class="nj-charts-axis" x1="487.419" y1="82" x2="430.049" y2="82" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="493.419" cy="82" r="5"><title>diff() 20k objects vs half, 3.12.0: 122 ms</title></circle>
<circle class="nj-charts-json-dot" cx="423.049" cy="82" r="5"><title>diff() 20k objects vs half, 3.13.0: 4.13 ms</title></circle>
<text class="nj-charts-factor" x="458.234" y="75">30&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="120" text-anchor="end">parse() callback, 32k objects</text>
<line class="nj-charts-axis" x1="538.106" y1="116" x2="452.39" y2="116" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="544.106" cy="116" r="5"><title>parse() callback, 32k objects, 3.12.0: 1398 ms</title></circle>
<circle class="nj-charts-json-dot" cx="445.39" cy="116" r="5"><title>parse() callback, 32k objects, 3.13.0: 12.1 ms</title></circle>
<text class="nj-charts-factor" x="494.748" y="109">116&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="154" text-anchor="end">operator&lt; nested 24 deep</text>
<line class="nj-charts-axis" x1="474.14" y1="150" x2="271.406" y2="150" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="480.14" cy="150" r="5"><title>operator&lt; nested 24 deep, 3.12.0: 64.4 ms</title></circle>
<circle class="nj-charts-json-dot" cx="264.406" cy="150" r="5"><title>operator&lt; nested 24 deep, 3.13.0: 0.002 ms</title></circle>
<text class="nj-charts-factor" x="372.273" y="143">32200&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="188" text-anchor="end">operator&lt; citm, 10x</text>
<line class="nj-charts-axis" x1="504.98" y1="184" x2="429.07" y2="184" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="510.98" cy="184" r="5"><title>operator&lt; citm, 10x, 3.12.0: 284 ms</title></circle>
<circle class="nj-charts-json-dot" cx="422.07" cy="184" r="5"><title>operator&lt; citm, 10x, 3.13.0: 3.94 ms</title></circle>
<text class="nj-charts-factor" x="466.525" y="177">72&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="222" text-anchor="end">flatten() citm, ordered_json</text>
<line class="nj-charts-axis" x1="504.006" y1="218" x2="408.294" y2="218" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="510.006" cy="218" r="5"><title>flatten() citm, ordered_json, 3.12.0: 271 ms</title></circle>
<circle class="nj-charts-json-dot" cx="401.294" cy="218" r="5"><title>flatten() citm, ordered_json, 3.13.0: 1.45 ms</title></circle>
<text class="nj-charts-factor" x="455.65" y="211">187&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="256" text-anchor="end">to_bson() 200 deep, 100x</text>
<line class="nj-charts-axis" x1="450.144" y1="252" x2="378.87" y2="252" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="456.144" cy="252" r="5"><title>to_bson() 200 deep, 100x, 3.12.0: 20.3 ms</title></circle>
<circle class="nj-charts-json-dot" cx="371.87" cy="252" r="5"><title>to_bson() 200 deep, 100x, 3.13.0: 0.352 ms</title></circle>
<text class="nj-charts-factor" x="414.007" y="245">58&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="290" text-anchor="end">push_back() 100k, diagnostics</text>
<line class="nj-charts-axis" x1="540.768" y1="286" x2="435.311" y2="286" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="546.768" cy="286" r="5"><title>push_back() 100k, diagnostics, 3.12.0: 1589 ms</title></circle>
<circle class="nj-charts-json-dot" cx="428.311" cy="286" r="5"><title>push_back() 100k, diagnostics, 3.13.0: 5.32 ms</title></circle>
<text class="nj-charts-factor" x="487.54" y="279">299&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="324" text-anchor="end">at(i) 10k, diagnostics</text>
<line class="nj-charts-axis" x1="467.101" y1="320" x2="350.057" y2="320" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="473.101" cy="320" r="5"><title>at(i) 10k, diagnostics, 3.12.0: 45.9 ms</title></circle>
<circle class="nj-charts-json-dot" cx="343.057" cy="320" r="5"><title>at(i) 10k, diagnostics, 3.13.0: 0.088 ms</title></circle>
<text class="nj-charts-factor" x="408.079" y="313">522&#215;</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.2 KiB

@@ -1,66 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 600 430" role="img" aria-labelledby="nj-blog-digits nj-blog-digits-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-digits">Converting eight A&#8203;SCII digits to their value with three multiplications</title>
<desc id="nj-blog-digits-d">The text 12345678 as one word. Masking gives the digit values 1 to 8, one per byte. Multiplying by 10 times 2 to the 8 plus 1 and shifting gives 12, 34, 56 and 78 in 16-bit lanes; multiplying by 100 times 2 to the 16 plus 1 gives 1234 and 5678 in 32-bit lanes; multiplying by 10000 times 2 to the 32 plus 1 gives 12345678.</desc>
<text class="fg-h" x="40" y="20">eight A&#8203;SCII digits in one 64-bit word (byte 0 is the lowest)</text>
<rect class="fg-cell" x="40" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="69" y="53" text-anchor="middle">1</text>
<text class="nj-charts-tick" x="69" y="80">0x31</text>
<rect class="fg-cell" x="104" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="133" y="53" text-anchor="middle">2</text>
<text class="nj-charts-tick" x="133" y="80">0x32</text>
<rect class="fg-cell" x="168" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="197" y="53" text-anchor="middle">3</text>
<text class="nj-charts-tick" x="197" y="80">0x33</text>
<rect class="fg-cell" x="232" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="261" y="53" text-anchor="middle">4</text>
<text class="nj-charts-tick" x="261" y="80">0x34</text>
<rect class="fg-cell" x="296" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="325" y="53" text-anchor="middle">5</text>
<text class="nj-charts-tick" x="325" y="80">0x35</text>
<rect class="fg-cell" x="360" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="389" y="53" text-anchor="middle">6</text>
<text class="nj-charts-tick" x="389" y="80">0x36</text>
<rect class="fg-cell" x="424" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="453" y="53" text-anchor="middle">7</text>
<text class="nj-charts-tick" x="453" y="80">0x37</text>
<rect class="fg-cell" x="488" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="517" y="53" text-anchor="middle">8</text>
<text class="nj-charts-tick" x="517" y="80">0x38</text>
<text class="fg-h" x="40" y="112">&amp; 0x0F0F0F0F0F0F0F0F: one digit value per byte</text>
<rect class="fg-cell" x="40" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="69" y="145" text-anchor="middle">1</text>
<rect class="fg-cell" x="104" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="133" y="145" text-anchor="middle">2</text>
<rect class="fg-cell" x="168" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="197" y="145" text-anchor="middle">3</text>
<rect class="fg-cell" x="232" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="261" y="145" text-anchor="middle">4</text>
<rect class="fg-cell" x="296" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="325" y="145" text-anchor="middle">5</text>
<rect class="fg-cell" x="360" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="389" y="145" text-anchor="middle">6</text>
<rect class="fg-cell" x="424" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="453" y="145" text-anchor="middle">7</text>
<rect class="fg-cell" x="488" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="517" y="145" text-anchor="middle">8</text>
<text class="fg-h" x="40" y="186">× (10 · 2⁸ + 1) &gt;&gt; 8, every second byte kept: two digits per 16 bits</text>
<rect class="fg-cell" x="40" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="101" y="219" text-anchor="middle">12</text>
<rect class="fg-cell" x="168" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="229" y="219" text-anchor="middle">34</text>
<rect class="fg-cell" x="296" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="357" y="219" text-anchor="middle">56</text>
<rect class="fg-cell" x="424" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="485" y="219" text-anchor="middle">78</text>
<text class="fg-h" x="40" y="260">× (100 · 2¹⁶ + 1) &gt;&gt; 16, every second lane kept: four digits per 32 bits</text>
<rect class="fg-cell" x="40" y="270" width="250" height="34" rx="4"/>
<text class="fg-code" x="165" y="293" text-anchor="middle">1234</text>
<rect class="fg-cell" x="296" y="270" width="250" height="34" rx="4"/>
<text class="fg-code" x="421" y="293" text-anchor="middle">5678</text>
<text class="fg-h" x="40" y="334">× (10000 · 2³² + 1) &gt;&gt; 32: the value</text>
<rect class="fg-cell" x="40" y="344" width="506" height="34" rx="4"/>
<rect class="nj-charts-c1" fill-opacity=".25" x="40" y="344" width="506" height="34" rx="4"/>
<text class="fg-code" x="293" y="367" text-anchor="middle">12345678</text>
<text class="fg-note fg-note--l" x="40" y="400">Each step combines neighboring lanes, in all lanes of the word at once:</text>
<text class="fg-note fg-note--l" x="40" y="418">three multiplications instead of eight, and no branch.</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

@@ -1,36 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 560 250" role="img" aria-labelledby="nj-blog-dist nj-blog-dist-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-dist">Speedup of 3.13.0 over 3.12.0 for all 182 benchmarks of the suite</title>
<desc id="nj-blog-dist-d">Bars counting the benchmarks per speedup range: below 1x: 2; 1 to 1.5x: 21; 1.5 to 2x: 18; 2 to 3x: 52; 3 to 5x: 48; 5 to 10x: 31; 10x or more: 10. Median 2.9x, geometric mean 3.3x.</desc>
<line class="nj-charts-grid" x1="52" y1="196" x2="548" y2="196"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="200">0</text>
<line class="nj-charts-grid" x1="52" y1="136" x2="548" y2="136"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="140">20</text>
<line class="nj-charts-grid" x1="52" y1="76" x2="548" y2="76"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="80">40</text>
<line class="nj-charts-grid" x1="52" y1="16" x2="548" y2="16"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="20">60</text>
<rect class="nj-charts-c2" x="60.0" y="190.0" width="54.9" height="6.0" rx="3"><title>below 1&#215;: 2</title></rect>
<text class="nj-charts-val" x="87.4" y="185.0" text-anchor="middle">2</text>
<text class="nj-charts-tick" x="87.4" y="212.0">below 1&#215;</text>
<rect class="nj-charts-c1" x="130.9" y="133.0" width="54.9" height="63.0" rx="3"><title>1 to 1.5&#215;: 21</title></rect>
<text class="nj-charts-val" x="158.3" y="128.0" text-anchor="middle">21</text>
<text class="nj-charts-tick" x="158.3" y="212.0">1 to 1.5&#215;</text>
<rect class="nj-charts-c1" x="201.7" y="142.0" width="54.9" height="54.0" rx="3"><title>1.5 to 2&#215;: 18</title></rect>
<text class="nj-charts-val" x="229.1" y="137.0" text-anchor="middle">18</text>
<text class="nj-charts-tick" x="229.1" y="212.0">1.5 to 2&#215;</text>
<rect class="nj-charts-c1" x="272.6" y="40.0" width="54.9" height="156.0" rx="3"><title>2 to 3&#215;: 52</title></rect>
<text class="nj-charts-val" x="300.0" y="35.0" text-anchor="middle">52</text>
<text class="nj-charts-tick" x="300.0" y="212.0">2 to 3&#215;</text>
<rect class="nj-charts-c1" x="343.4" y="52.0" width="54.9" height="144.0" rx="3"><title>3 to 5&#215;: 48</title></rect>
<text class="nj-charts-val" x="370.9" y="47.0" text-anchor="middle">48</text>
<text class="nj-charts-tick" x="370.9" y="212.0">3 to 5&#215;</text>
<rect class="nj-charts-c1" x="414.3" y="103.0" width="54.9" height="93.0" rx="3"><title>5 to 10&#215;: 31</title></rect>
<text class="nj-charts-val" x="441.7" y="98.0" text-anchor="middle">31</text>
<text class="nj-charts-tick" x="441.7" y="212.0">5 to 10&#215;</text>
<rect class="nj-charts-c1" x="485.1" y="166.0" width="54.9" height="30.0" rx="3"><title>10&#215; or more: 10</title></rect>
<text class="nj-charts-val" x="512.6" y="161.0" text-anchor="middle">10</text>
<text class="nj-charts-tick" x="512.6" y="212.0">10&#215; or more</text>
<line class="nj-charts-axis" x1="52" y1="196" x2="548" y2="196"/>
<text class="nj-charts-tick" x="300" y="240">speedup over 3.12.0, more is better</text>
<text class="nj-charts-tick" transform="rotate(-90)" x="-106" y="14">number of benchmarks</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1,102 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 620 482" role="img" aria-labelledby="nj-blog-heldout nj-blog-heldout-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-heldout">Validating 19 files 3.13.0 was not tuned on: json_document&#x27;s time relative to the fastest other library per file</title>
<desc id="nj-blog-heldout-d">Dot plot per file, less is better; below 1.0 json_document is the fastest fully validating library. mesh: Mac 0.72, x86-64 0.44 (serde_json (Rust)); semanticscholar-corpus: Mac 0.78, x86-64 0.63 (sonic-rs (Rust)); gsoc-2018: Mac 0.59, x86-64 0.64 (Boost.J&#8203;SON); marine_ik: Mac 0.62, x86-64 0.64 (Boost.J&#8203;SON); twitter_api_compact_response: Mac 0.91, x86-64 0.66 (yyjson); twitterescaped: Mac 0.94, x86-64 0.76 (simdjson); update-center: Mac 0.88, x86-64 0.77 (simdjson); github_events: Mac 0.78, x86-64 0.78 (simdjson); twitter_api_response: Mac 0.95, x86-64 0.81 (simdjson); twitter_timeline: Mac 0.99, x86-64 0.82 (yyjson); numbers: Mac 0.72, x86-64 0.82 (Boost.J&#8203;SON); random: Mac 0.82, x86-64 0.86 (simdjson); repeat: Mac 0.65, x86-64 0.89 (simdjson); apache_builds: Mac 1.08, x86-64 0.90 (simdjson); instruments: Mac 0.92, x86-64 0.91 (simdjson); google_maps_api_compact_response: Mac 0.87, x86-64 0.92 (yyjson); mesh.pretty: Mac 0.88, x86-64 0.93 (Boost.J&#8203;SON); tree-pretty: Mac 0.96, x86-64 0.94 (simdjson); google_maps_api_response: Mac 0.91, x86-64 1.00 (simdjson).</desc>
<line class="nj-charts-grid" x1="262" y1="50" x2="262" y2="438"/>
<text class="nj-charts-tick" x="262" y="454">0.4&#215;</text>
<line class="nj-charts-grid" x1="291.867" y1="50" x2="291.867" y2="438"/>
<text class="nj-charts-tick" x="291.867" y="454">0.5&#215;</text>
<line class="nj-charts-grid" x1="321.733" y1="50" x2="321.733" y2="438"/>
<text class="nj-charts-tick" x="321.733" y="454">0.6&#215;</text>
<line class="nj-charts-grid" x1="351.6" y1="50" x2="351.6" y2="438"/>
<text class="nj-charts-tick" x="351.6" y="454">0.7&#215;</text>
<line class="nj-charts-grid" x1="381.467" y1="50" x2="381.467" y2="438"/>
<text class="nj-charts-tick" x="381.467" y="454">0.8&#215;</text>
<line class="nj-charts-grid" x1="411.333" y1="50" x2="411.333" y2="438"/>
<text class="nj-charts-tick" x="411.333" y="454">0.9&#215;</text>
<line class="nj-charts-grid" x1="441.2" y1="50" x2="441.2" y2="438"/>
<text class="nj-charts-tick" x="441.2" y="454">1.0&#215;</text>
<line class="nj-charts-grid" x1="471.067" y1="50" x2="471.067" y2="438"/>
<text class="nj-charts-tick" x="471.067" y="454">1.1&#215;</text>
<text class="nj-charts-tick" x="374" y="472">json&#95;document&#8217;s time / the fastest other library&#8217;s, less is better</text>
<circle class="nj-charts-json-dot" cx="13" cy="14" r="5"/><text class="nj-charts-leg" x="23" y="18.5">Apple M1 Max</text>
<circle class="nj-charts-ojson-dot" cx="134.2" cy="14" r="5"/><text class="nj-charts-leg" x="144.2" y="18.5">x86-64, G&#8203;CC 16.2</text>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="48">next on x86-64</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="68" text-anchor="end">mesh</text>
<circle class="nj-charts-json-dot" cx="357.0" cy="60.5" r="4.5"><title>mesh, Apple M1 Max: 0.72&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="273.8" cy="67.5" r="4.5"><title>mesh, x86-64, G&#8203;CC 16.2: 0.44&#215; the time of serde&#95;json (Rust)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="68">serde&#95;json (Rust)</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="88" text-anchor="end">semanticscholar-corpus</text>
<circle class="nj-charts-json-dot" cx="376.0" cy="80.5" r="4.5"><title>semanticscholar-corpus, Apple M1 Max: 0.78&#215; the time of sonic-rs (Rust)</title></circle>
<circle class="nj-charts-ojson-dot" cx="331.5" cy="87.5" r="4.5"><title>semanticscholar-corpus, x86-64, G&#8203;CC 16.2: 0.63&#215; the time of sonic-rs (Rust)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="88">sonic-rs (Rust)</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="108" text-anchor="end">gsoc-2018</text>
<circle class="nj-charts-json-dot" cx="318.5" cy="100.5" r="4.5"><title>gsoc-2018, Apple M1 Max: 0.59&#215; the time of sonic-rs (Rust)</title></circle>
<circle class="nj-charts-ojson-dot" cx="332.3" cy="107.5" r="4.5"><title>gsoc-2018, x86-64, G&#8203;CC 16.2: 0.64&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="108">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="128" text-anchor="end">marine&#95;ik</text>
<circle class="nj-charts-json-dot" cx="326.2" cy="120.5" r="4.5"><title>marine&#95;ik, Apple M1 Max: 0.62&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="333.7" cy="127.5" r="4.5"><title>marine&#95;ik, x86-64, G&#8203;CC 16.2: 0.64&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="128">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="148" text-anchor="end">twitter&#95;api&#95;compact&#95;response</text>
<circle class="nj-charts-json-dot" cx="414.0" cy="140.5" r="4.5"><title>twitter&#95;api&#95;compact&#95;response, Apple M1 Max: 0.91&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="340.0" cy="147.5" r="4.5"><title>twitter&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.66&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="148">yyjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="168" text-anchor="end">twitterescaped</text>
<circle class="nj-charts-json-dot" cx="423.0" cy="160.5" r="4.5"><title>twitterescaped, Apple M1 Max: 0.94&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="368.5" cy="167.5" r="4.5"><title>twitterescaped, x86-64, G&#8203;CC 16.2: 0.76&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="168">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="188" text-anchor="end">update-center</text>
<circle class="nj-charts-json-dot" cx="404.3" cy="180.5" r="4.5"><title>update-center, Apple M1 Max: 0.88&#215; the time of sonic-rs (Rust)</title></circle>
<circle class="nj-charts-ojson-dot" cx="372.0" cy="187.5" r="4.5"><title>update-center, x86-64, G&#8203;CC 16.2: 0.77&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="188">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="208" text-anchor="end">github&#95;events</text>
<circle class="nj-charts-json-dot" cx="375.6" cy="200.5" r="4.5"><title>github&#95;events, Apple M1 Max: 0.78&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="375.2" cy="207.5" r="4.5"><title>github&#95;events, x86-64, G&#8203;CC 16.2: 0.78&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="208">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="228" text-anchor="end">twitter&#95;api&#95;response</text>
<circle class="nj-charts-json-dot" cx="427.3" cy="220.5" r="4.5"><title>twitter&#95;api&#95;response, Apple M1 Max: 0.95&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="384.1" cy="227.5" r="4.5"><title>twitter&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 0.81&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="228">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="248" text-anchor="end">twitter&#95;timeline</text>
<circle class="nj-charts-json-dot" cx="437.3" cy="240.5" r="4.5"><title>twitter&#95;timeline, Apple M1 Max: 0.99&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="386.2" cy="247.5" r="4.5"><title>twitter&#95;timeline, x86-64, G&#8203;CC 16.2: 0.82&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="248">yyjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="268" text-anchor="end">numbers</text>
<circle class="nj-charts-json-dot" cx="358.0" cy="260.5" r="4.5"><title>numbers, Apple M1 Max: 0.72&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="386.3" cy="267.5" r="4.5"><title>numbers, x86-64, G&#8203;CC 16.2: 0.82&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="268">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="288" text-anchor="end">random</text>
<circle class="nj-charts-json-dot" cx="388.2" cy="280.5" r="4.5"><title>random, Apple M1 Max: 0.82&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="400.0" cy="287.5" r="4.5"><title>random, x86-64, G&#8203;CC 16.2: 0.86&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="288">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="308" text-anchor="end">repeat</text>
<circle class="nj-charts-json-dot" cx="336.7" cy="300.5" r="4.5"><title>repeat, Apple M1 Max: 0.65&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="409.2" cy="307.5" r="4.5"><title>repeat, x86-64, G&#8203;CC 16.2: 0.89&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="308">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="328" text-anchor="end">apache&#95;builds</text>
<circle class="nj-charts-json-dot" cx="465.2" cy="320.5" r="4.5"><title>apache&#95;builds, Apple M1 Max: 1.08&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="412.0" cy="327.5" r="4.5"><title>apache&#95;builds, x86-64, G&#8203;CC 16.2: 0.90&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="328">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="348" text-anchor="end">instruments</text>
<circle class="nj-charts-json-dot" cx="417.1" cy="340.5" r="4.5"><title>instruments, Apple M1 Max: 0.92&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="415.6" cy="347.5" r="4.5"><title>instruments, x86-64, G&#8203;CC 16.2: 0.91&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="348">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="368" text-anchor="end">google&#95;maps&#95;api&#95;compact&#95;response</text>
<circle class="nj-charts-json-dot" cx="403.3" cy="360.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, Apple M1 Max: 0.87&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="416.8" cy="367.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.92&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="368">yyjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="388" text-anchor="end">mesh.pretty</text>
<circle class="nj-charts-json-dot" cx="405.5" cy="380.5" r="4.5"><title>mesh.pretty, Apple M1 Max: 0.88&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="419.6" cy="387.5" r="4.5"><title>mesh.pretty, x86-64, G&#8203;CC 16.2: 0.93&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="388">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="408" text-anchor="end">tree-pretty</text>
<circle class="nj-charts-json-dot" cx="427.9" cy="400.5" r="4.5"><title>tree-pretty, Apple M1 Max: 0.96&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="424.3" cy="407.5" r="4.5"><title>tree-pretty, x86-64, G&#8203;CC 16.2: 0.94&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="408">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="428" text-anchor="end">google&#95;maps&#95;api&#95;response</text>
<circle class="nj-charts-json-dot" cx="415.8" cy="420.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, Apple M1 Max: 0.91&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="441.2" cy="427.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="428">simdjson</text>
<line class="nj-charts-ref" x1="441.2" y1="50" x2="441.2" y2="438"/>
<text class="nj-charts-tick" x="441.2" y="44">as fast as the next</text>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

@@ -1,72 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 640 294" role="img" aria-labelledby="nj-blog-overlap nj-blog-overlap-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-overlap">Writing an 18-byte string with two overlapping 16-byte loads and stores</title>
<desc id="nj-blog-overlap-d">The 18 bytes of profile_link_color. Load a covers bytes 0 to 15, load b covers bytes 2 to 17, so bytes 2 to 15 are in both. Neither contains a byte that needs escaping, so a is stored at the destination and b 2 bytes later; the second store writes bytes 2 to 15 again with the same values. This works for any length from 16 to 32 bytes without a loop.</desc>
<text class="fg-h" x="40" y="20">a string of n = 18 bytes: too long for one 16-byte vector, too short for a loop</text>
<rect class="fg-cell" x="40" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="53.5" y="58" text-anchor="middle">p</text>
<rect class="fg-cell" x="71" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="84.5" y="58" text-anchor="middle">r</text>
<rect class="fg-cell" x="102" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="102" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="115.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="133" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="133" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="146.5" y="58" text-anchor="middle">f</text>
<rect class="fg-cell" x="164" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="164" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="177.5" y="58" text-anchor="middle">i</text>
<rect class="fg-cell" x="195" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="195" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="208.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="226" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="226" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="239.5" y="58" text-anchor="middle">e</text>
<rect class="fg-cell" x="257" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="257" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="270.5" y="58" text-anchor="middle">&#95;</text>
<rect class="fg-cell" x="288" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="288" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="301.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="319" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="319" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="332.5" y="58" text-anchor="middle">i</text>
<rect class="fg-cell" x="350" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="350" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="363.5" y="58" text-anchor="middle">n</text>
<rect class="fg-cell" x="381" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="381" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="394.5" y="58" text-anchor="middle">k</text>
<rect class="fg-cell" x="412" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="412" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="425.5" y="58" text-anchor="middle">&#95;</text>
<rect class="fg-cell" x="443" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="443" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="456.5" y="58" text-anchor="middle">c</text>
<rect class="fg-cell" x="474" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="474" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="487.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="505" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="505" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="518.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="536" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="549.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="567" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="580.5" y="58" text-anchor="middle">r</text>
<text class="nj-charts-tick" x="53.5" y="86">0</text>
<text class="nj-charts-tick" x="115.5" y="86">2</text>
<text class="nj-charts-tick" x="518.5" y="86">15</text>
<text class="nj-charts-tick" x="580.5" y="86">17</text>
<rect class="nj-charts-c1" fill-opacity=".22" x="40" y="100" width="492" height="22" rx="4"/>
<rect class="nj-charts-c1" x="40" y="100" width="4" height="22" rx="2"/>
<rect class="nj-charts-c1" x="528" y="100" width="4" height="22" rx="2"/>
<text class="fg-code" x="286" y="116" text-anchor="middle" style="font-size:14px">a = load 16 bytes at p</text>
<rect class="nj-charts-c2" fill-opacity=".22" x="102" y="130" width="492" height="22" rx="4"/>
<rect class="nj-charts-c2" x="102" y="130" width="4" height="22" rx="2"/>
<rect class="nj-charts-c2" x="590" y="130" width="4" height="22" rx="2"/>
<text class="fg-code" x="348" y="146" text-anchor="middle" style="font-size:14px">b = load 16 bytes at p + n &#8722; 16</text>
<text class="fg-note fg-note--l" x="40" y="182">Both loads lie inside the string, and together they cover all of it; bytes 2 to 15 are in both.</text>
<text class="fg-note fg-note--l" x="40" y="204">Test a and b for a quote, a backslash, a control character or 0x7F: none, so write</text>
<text class="fg-code" x="40" y="234">store a at d, store b at d + n &#8722; 16</text>
<text class="fg-note fg-note--l" x="40" y="262">The second store writes bytes 2 to 15 again, with the same values. For any n from 16 to 32:</text>
<text class="fg-note fg-note--l" x="40" y="280">two loads, one test, two stores, no loop and no branch on the length.</text>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

@@ -1,97 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 560 604" role="img" aria-labelledby="nj-blog-overview nj-blog-overview-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-overview">Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang</title>
<desc id="nj-blog-overview-d">Horizontal bars of the speedup, more is better. twitter.json 3.5x; citm_catalog.json 5.1x; canada.json 4.1x; canada.json, indented 7.4x; citm, ordered_json 8.2x; twitter, std::ifstream 2.5x; citm, FILE* 15x; citm, accept() 14x; dump() twitter 6.6x; dump() canada 2.9x; dump(4) citm 4.6x; to_cbor() twitter 4.4x; twitter, memory 3.5x; twitter, FILE* 9.2x; diff() canada 10x; iterate canada 1.96x; copy + destroy citm 1.11x; == citm 1.01x.</desc>
<text class="nj-charts-panel" x="8" y="20">Parsing</text>
<text class="nj-charts-panel" x="8" y="244">Writing</text>
<text class="nj-charts-panel" x="8" y="372">Reading C&#8203;BOR</text>
<text class="nj-charts-panel" x="8" y="452">Values</text>
<line class="nj-charts-grid" x1="210.625" y1="8" x2="210.625" y2="560"/>
<text class="nj-charts-tick" x="210.625" y="576">1&#215;</text>
<line class="nj-charts-grid" x1="231.25" y1="8" x2="231.25" y2="560"/>
<text class="nj-charts-tick" x="231.25" y="576">2&#215;</text>
<line class="nj-charts-grid" x1="251.875" y1="8" x2="251.875" y2="560"/>
<text class="nj-charts-tick" x="251.875" y="576">3&#215;</text>
<line class="nj-charts-grid" x1="272.5" y1="8" x2="272.5" y2="560"/>
<text class="nj-charts-tick" x="272.5" y="576">4&#215;</text>
<line class="nj-charts-grid" x1="293.125" y1="8" x2="293.125" y2="560"/>
<text class="nj-charts-tick" x="293.125" y="576">5&#215;</text>
<line class="nj-charts-grid" x1="313.75" y1="8" x2="313.75" y2="560"/>
<text class="nj-charts-tick" x="313.75" y="576">6&#215;</text>
<line class="nj-charts-grid" x1="334.375" y1="8" x2="334.375" y2="560"/>
<text class="nj-charts-tick" x="334.375" y="576">7&#215;</text>
<line class="nj-charts-grid" x1="355" y1="8" x2="355" y2="560"/>
<text class="nj-charts-tick" x="355" y="576">8&#215;</text>
<line class="nj-charts-grid" x1="375.625" y1="8" x2="375.625" y2="560"/>
<text class="nj-charts-tick" x="375.625" y="576">9&#215;</text>
<line class="nj-charts-grid" x1="396.25" y1="8" x2="396.25" y2="560"/>
<text class="nj-charts-tick" x="396.25" y="576">10&#215;</text>
<line class="nj-charts-grid" x1="416.875" y1="8" x2="416.875" y2="560"/>
<text class="nj-charts-tick" x="416.875" y="576">11&#215;</text>
<line class="nj-charts-grid" x1="437.5" y1="8" x2="437.5" y2="560"/>
<text class="nj-charts-tick" x="437.5" y="576">12&#215;</text>
<line class="nj-charts-grid" x1="458.125" y1="8" x2="458.125" y2="560"/>
<text class="nj-charts-tick" x="458.125" y="576">13&#215;</text>
<line class="nj-charts-grid" x1="478.75" y1="8" x2="478.75" y2="560"/>
<text class="nj-charts-tick" x="478.75" y="576">14&#215;</text>
<line class="nj-charts-grid" x1="499.375" y1="8" x2="499.375" y2="560"/>
<text class="nj-charts-tick" x="499.375" y="576">15&#215;</text>
<line class="nj-charts-grid" x1="520" y1="8" x2="520" y2="560"/>
<text class="nj-charts-tick" x="520" y="576">16&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="42" text-anchor="end">twitter.json</text>
<path class="nj-charts-c1" d="M190 30 H257.981 Q261.981 30 261.981 34 V41 Q261.981 45 257.981 45 H190 Z"><title>twitter.json: 3.5&#215;</title></path>
<text class="nj-charts-val" x="266.981" y="42">3.5&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="66" text-anchor="end">citm_catalog.json</text>
<path class="nj-charts-c1" d="M190 54 H291.394 Q295.394 54 295.394 58 V65 Q295.394 69 291.394 69 H190 Z"><title>citm_catalog.json: 5.1&#215;</title></path>
<text class="nj-charts-val" x="300.394" y="66">5.1&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="90" text-anchor="end">canada.json</text>
<path class="nj-charts-c1" d="M190 78 H270.15 Q274.15 78 274.15 82 V89 Q274.15 93 270.15 93 H190 Z"><title>canada.json: 4.1&#215;</title></path>
<text class="nj-charts-val" x="279.15" y="90">4.1&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="114" text-anchor="end">canada.json, indented</text>
<path class="nj-charts-c1" d="M190 102 H338.831 Q342.831 102 342.831 106 V113 Q342.831 117 338.831 117 H190 Z"><title>canada.json, indented: 7.4&#215;</title></path>
<text class="nj-charts-val" x="347.831" y="114">7.4&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="138" text-anchor="end">citm, ordered_json</text>
<path class="nj-charts-c1" d="M190 126 H354.712 Q358.712 126 358.712 130 V137 Q358.712 141 354.712 141 H190 Z"><title>citm, ordered_json: 8.2&#215;</title></path>
<text class="nj-charts-val" x="363.712" y="138">8.2&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="162" text-anchor="end">twitter, std::ifstream</text>
<path class="nj-charts-c1" d="M190 150 H236.738 Q240.738 150 240.738 154 V161 Q240.738 165 236.738 165 H190 Z"><title>twitter, std::ifstream: 2.5&#215;</title></path>
<text class="nj-charts-val" x="245.738" y="162">2.5&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="186" text-anchor="end">citm, FILE*</text>
<path class="nj-charts-c1" d="M190 174 H494.137 Q498.137 174 498.137 178 V185 Q498.137 189 494.137 189 H190 Z"><title>citm, FILE*: 15&#215;</title></path>
<text class="nj-charts-val" x="503.137" y="186">15&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="210" text-anchor="end">citm, accept()</text>
<path class="nj-charts-c1" d="M190 198 H467.738 Q471.738 198 471.738 202 V209 Q471.738 213 467.738 213 H190 Z"><title>citm, accept(): 14&#215;</title></path>
<text class="nj-charts-val" x="476.738" y="210">14&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="266" text-anchor="end">dump() twitter</text>
<path class="nj-charts-c1" d="M190 254 H322.125 Q326.125 254 326.125 258 V265 Q326.125 269 322.125 269 H190 Z"><title>dump() twitter: 6.6&#215;</title></path>
<text class="nj-charts-val" x="331.125" y="266">6.6&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="290" text-anchor="end">dump() canada</text>
<path class="nj-charts-c1" d="M190 278 H245.812 Q249.812 278 249.812 282 V289 Q249.812 293 245.812 293 H190 Z"><title>dump() canada: 2.9&#215;</title></path>
<text class="nj-charts-val" x="254.812" y="290">2.9&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="314" text-anchor="end">dump(4) citm</text>
<path class="nj-charts-c1" d="M190 302 H281.288 Q285.288 302 285.288 306 V313 Q285.288 317 281.288 317 H190 Z"><title>dump(4) citm: 4.6&#215;</title></path>
<text class="nj-charts-val" x="290.288" y="314">4.6&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="338" text-anchor="end">to_cbor() twitter</text>
<path class="nj-charts-c1" d="M190 326 H276.956 Q280.956 326 280.956 330 V337 Q280.956 341 276.956 341 H190 Z"><title>to_cbor() twitter: 4.4&#215;</title></path>
<text class="nj-charts-val" x="285.956" y="338">4.4&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="394" text-anchor="end">twitter, memory</text>
<path class="nj-charts-c1" d="M190 382 H258.6 Q262.6 382 262.6 386 V393 Q262.6 397 258.6 397 H190 Z"><title>twitter, memory: 3.5&#215;</title></path>
<text class="nj-charts-val" x="267.6" y="394">3.5&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="418" text-anchor="end">twitter, FILE*</text>
<path class="nj-charts-c1" d="M190 406 H376.369 Q380.369 406 380.369 410 V417 Q380.369 421 376.369 421 H190 Z"><title>twitter, FILE*: 9.2&#215;</title></path>
<text class="nj-charts-val" x="385.369" y="418">9.2&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="474" text-anchor="end">diff() canada</text>
<path class="nj-charts-c1" d="M190 462 H401.325 Q405.325 462 405.325 466 V473 Q405.325 477 401.325 477 H190 Z"><title>diff() canada: 10&#215;</title></path>
<text class="nj-charts-val" x="410.325" y="474">10&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="498" text-anchor="end">iterate canada</text>
<path class="nj-charts-c1" d="M190 486 H226.425 Q230.425 486 230.425 490 V497 Q230.425 501 226.425 501 H190 Z"><title>iterate canada: 1.96&#215;</title></path>
<text class="nj-charts-val" x="235.425" y="498">1.96&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="522" text-anchor="end">copy + destroy citm</text>
<path class="nj-charts-c1" d="M190 510 H208.894 Q212.894 510 212.894 514 V521 Q212.894 525 208.894 525 H190 Z"><title>copy + destroy citm: 1.11&#215;</title></path>
<text class="nj-charts-val" x="217.894" y="522">1.11&#215;</text>
<text class="nj-charts-rowlabel nj-charts-tick--r" x="182" y="546" text-anchor="end">== citm</text>
<path class="nj-charts-c1" d="M190 534 H206.831 Q210.831 534 210.831 538 V545 Q210.831 549 206.831 549 H190 Z"><title>== citm: 1.01&#215;</title></path>
<text class="nj-charts-val" x="215.831" y="546">1.01&#215;</text>
<line class="nj-charts-ref" x1="210.625" y1="8" x2="210.625" y2="560"/>
<line class="nj-charts-zero" x1="190" y1="8" x2="190" y2="560"/>
<text class="nj-charts-tick" x="355" y="594">speedup over 3.12.0 (3.12.0 = 1&#215;), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.1 KiB

@@ -1,99 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 600 618" role="img" aria-labelledby="nj-blog-price nj-blog-price-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-price">Compile time of two programs with 3.13.0, alone, with a precompiled header and as a module, compared with 3.12.0</title>
<desc id="nj-blog-price-d">Horizontal bars of the change in compile time against 3.12.0, less is better. Apple clang 21, -O0 (debug), count_numbers, 3.13.0: +36%; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, precompiled header: -23%; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, module: -5%; Apple clang 21, -O0 (debug), server_config, 3.13.0: +36%; Apple clang 21, -O0 (debug), server_config, 3.13.0, precompiled header: -20%; Apple clang 21, -O0 (debug), server_config, 3.13.0, module: +8%; Apple clang 21, -O2, count_numbers, 3.13.0: +43%; Apple clang 21, -O2, count_numbers, 3.13.0, precompiled header: -1%; Apple clang 21, -O2, count_numbers, 3.13.0, module: +12%; Apple clang 21, -O2, server_config, 3.13.0: +42%; Apple clang 21, -O2, server_config, 3.13.0, precompiled header: +12%; Apple clang 21, -O2, server_config, 3.13.0, module: +22%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0: +68%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, precompiled header: +12%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, module: +13%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0: +50%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, precompiled header: +15%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, module: +16%; G&#8203;CC 16, -O2, count_numbers, 3.13.0: +60%; G&#8203;CC 16, -O2, count_numbers, 3.13.0, precompiled header: +28%; G&#8203;CC 16, -O2, count_numbers, 3.13.0, module: +27%; G&#8203;CC 16, -O2, server_config, 3.13.0: +52%; G&#8203;CC 16, -O2, server_config, 3.13.0, precompiled header: +29%; G&#8203;CC 16, -O2, server_config, 3.13.0, module: +31%.</desc>
<rect class="nj-charts-c2" x="8" y="6" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="26" y="16.5">3.13.0</text>
<rect class="nj-charts-c1" x="97.2" y="6" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="115.2" y="16.5">3.13.0, precompiled header</text>
<rect class="nj-charts-c3" x="350.4" y="6" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="368.4" y="16.5">3.13.0, module</text>
<text class="nj-charts-tick" x="320.833" y="46">as fast as 3.12.0</text>
<text class="nj-charts-panel" x="8" y="68">Apple clang 21, -O0 (debug)</text>
<line class="nj-charts-grid" x1="184.167" y1="74" x2="184.167" y2="170"/>
<line class="nj-charts-grid" x1="252.5" y1="74" x2="252.5" y2="170"/>
<line class="nj-charts-grid" x1="389.167" y1="74" x2="389.167" y2="170"/>
<line class="nj-charts-grid" x1="457.5" y1="74" x2="457.5" y2="170"/>
<line class="nj-charts-grid" x1="525.833" y1="74" x2="525.833" y2="170"/>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="101" text-anchor="end">count_numbers</text>
<path class="nj-charts-c2" d="M320.833 78 H439.833 Q443.833 78 443.833 82 V85 Q443.833 89 439.833 89 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0: 1,131 ms against 831 ms with 3.12.0 (+36%)</title></path>
<text class="nj-charts-val" x="448.833" y="87.5">+36%</text>
<path class="nj-charts-c1" d="M320.833 92 H246.25 Q242.25 92 242.25 96 V99 Q242.25 103 246.25 103 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 639 ms against 831 ms with 3.12.0 (&#8722;23%)</title></path>
<text class="nj-charts-val" x="237.25" y="101.5" text-anchor="end">&#8722;23%</text>
<path class="nj-charts-c3" d="M320.833 106 H307.75 Q303.75 106 303.75 110 V113 Q303.75 117 307.75 117 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, module: 790 ms against 831 ms with 3.12.0 (&#8722;5%)</title></path>
<text class="nj-charts-val" x="298.75" y="115.5" text-anchor="end">&#8722;5%</text>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="150" text-anchor="end">server_config</text>
<path class="nj-charts-c2" d="M320.833 127 H439.833 Q443.833 127 443.833 131 V134 Q443.833 138 439.833 138 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0: 1,312 ms against 963 ms with 3.12.0 (+36%)</title></path>
<text class="nj-charts-val" x="448.833" y="136.5">+36%</text>
<path class="nj-charts-c1" d="M320.833 141 H256.5 Q252.5 141 252.5 145 V148 Q252.5 152 256.5 152 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 774 ms against 963 ms with 3.12.0 (&#8722;20%)</title></path>
<text class="nj-charts-val" x="247.5" y="150.5" text-anchor="end">&#8722;20%</text>
<path class="nj-charts-c3" d="M320.833 155 H344.167 Q348.167 155 348.167 159 V162 Q348.167 166 344.167 166 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, module: 1,036 ms against 963 ms with 3.12.0 (+8%)</title></path>
<text class="nj-charts-val" x="353.167" y="164.5">+8%</text>
<text class="nj-charts-panel" x="8" y="198">Apple clang 21, -O2</text>
<line class="nj-charts-grid" x1="184.167" y1="204" x2="184.167" y2="300"/>
<line class="nj-charts-grid" x1="252.5" y1="204" x2="252.5" y2="300"/>
<line class="nj-charts-grid" x1="389.167" y1="204" x2="389.167" y2="300"/>
<line class="nj-charts-grid" x1="457.5" y1="204" x2="457.5" y2="300"/>
<line class="nj-charts-grid" x1="525.833" y1="204" x2="525.833" y2="300"/>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="231" text-anchor="end">count_numbers</text>
<path class="nj-charts-c2" d="M320.833 208 H463.75 Q467.75 208 467.75 212 V215 Q467.75 219 463.75 219 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0: 1,898 ms against 1,328 ms with 3.12.0 (+43%)</title></path>
<text class="nj-charts-val" x="472.75" y="217.5">+43%</text>
<path class="nj-charts-c1" d="M320.833 222 H320.833 Q317.417 222 317.417 225.417 V229.583 Q317.417 233 320.833 233 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, precompiled header: 1,312 ms against 1,328 ms with 3.12.0 (&#8722;1%)</title></path>
<text class="nj-charts-val" x="312.417" y="231.5" text-anchor="end">&#8722;1%</text>
<path class="nj-charts-c3" d="M320.833 236 H357.833 Q361.833 236 361.833 240 V243 Q361.833 247 357.833 247 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, module: 1,491 ms against 1,328 ms with 3.12.0 (+12%)</title></path>
<text class="nj-charts-val" x="366.833" y="245.5">+12%</text>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="280" text-anchor="end">server_config</text>
<path class="nj-charts-c2" d="M320.833 257 H460.333 Q464.333 257 464.333 261 V264 Q464.333 268 460.333 268 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0: 2,251 ms against 1,584 ms with 3.12.0 (+42%)</title></path>
<text class="nj-charts-val" x="469.333" y="266.5">+42%</text>
<path class="nj-charts-c1" d="M320.833 271 H357.833 Q361.833 271 361.833 275 V278 Q361.833 282 357.833 282 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, precompiled header: 1,779 ms against 1,584 ms with 3.12.0 (+12%)</title></path>
<text class="nj-charts-val" x="366.833" y="280.5">+12%</text>
<path class="nj-charts-c3" d="M320.833 285 H392 Q396 285 396 289 V292 Q396 296 392 296 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, module: 1,926 ms against 1,584 ms with 3.12.0 (+22%)</title></path>
<text class="nj-charts-val" x="401" y="294.5">+22%</text>
<text class="nj-charts-panel" x="8" y="328">G&#8203;CC 16, -O0 (debug)</text>
<line class="nj-charts-grid" x1="184.167" y1="334" x2="184.167" y2="430"/>
<line class="nj-charts-grid" x1="252.5" y1="334" x2="252.5" y2="430"/>
<line class="nj-charts-grid" x1="389.167" y1="334" x2="389.167" y2="430"/>
<line class="nj-charts-grid" x1="457.5" y1="334" x2="457.5" y2="430"/>
<line class="nj-charts-grid" x1="525.833" y1="334" x2="525.833" y2="430"/>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="361" text-anchor="end">count_numbers</text>
<path class="nj-charts-c2" d="M320.833 338 H549.167 Q553.167 338 553.167 342 V345 Q553.167 349 549.167 349 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,385 ms against 1,416 ms with 3.12.0 (+68%)</title></path>
<text class="nj-charts-val" x="558.167" y="347.5">+68%</text>
<path class="nj-charts-c1" d="M320.833 352 H357.833 Q361.833 352 361.833 356 V359 Q361.833 363 357.833 363 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 1,593 ms against 1,416 ms with 3.12.0 (+12%)</title></path>
<text class="nj-charts-val" x="366.833" y="361.5">+12%</text>
<path class="nj-charts-c3" d="M320.833 366 H361.25 Q365.25 366 365.25 370 V373 Q365.25 377 361.25 377 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 1,604 ms against 1,416 ms with 3.12.0 (+13%)</title></path>
<text class="nj-charts-val" x="370.25" y="375.5">+13%</text>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="410" text-anchor="end">server_config</text>
<path class="nj-charts-c2" d="M320.833 387 H487.667 Q491.667 387 491.667 391 V394 Q491.667 398 487.667 398 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,820 ms against 1,878 ms with 3.12.0 (+50%)</title></path>
<text class="nj-charts-val" x="496.667" y="396.5">+50%</text>
<path class="nj-charts-c1" d="M320.833 401 H368.083 Q372.083 401 372.083 405 V408 Q372.083 412 368.083 412 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 2,152 ms against 1,878 ms with 3.12.0 (+15%)</title></path>
<text class="nj-charts-val" x="377.083" y="410.5">+15%</text>
<path class="nj-charts-c3" d="M320.833 415 H371.5 Q375.5 415 375.5 419 V422 Q375.5 426 371.5 426 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 2,180 ms against 1,878 ms with 3.12.0 (+16%)</title></path>
<text class="nj-charts-val" x="380.5" y="424.5">+16%</text>
<text class="nj-charts-panel" x="8" y="458">G&#8203;CC 16, -O2</text>
<line class="nj-charts-grid" x1="184.167" y1="464" x2="184.167" y2="560"/>
<line class="nj-charts-grid" x1="252.5" y1="464" x2="252.5" y2="560"/>
<line class="nj-charts-grid" x1="389.167" y1="464" x2="389.167" y2="560"/>
<line class="nj-charts-grid" x1="457.5" y1="464" x2="457.5" y2="560"/>
<line class="nj-charts-grid" x1="525.833" y1="464" x2="525.833" y2="560"/>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="491" text-anchor="end">count_numbers</text>
<path class="nj-charts-c2" d="M320.833 468 H521.833 Q525.833 468 525.833 472 V475 Q525.833 479 521.833 479 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0: 3,464 ms against 2,159 ms with 3.12.0 (+60%)</title></path>
<text class="nj-charts-val" x="530.833" y="477.5">+60%</text>
<path class="nj-charts-c1" d="M320.833 482 H412.5 Q416.5 482 416.5 486 V489 Q416.5 493 412.5 493 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0, precompiled header: 2,765 ms against 2,159 ms with 3.12.0 (+28%)</title></path>
<text class="nj-charts-val" x="421.5" y="491.5">+28%</text>
<path class="nj-charts-c3" d="M320.833 496 H409.083 Q413.083 496 413.083 500 V503 Q413.083 507 409.083 507 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0, module: 2,740 ms against 2,159 ms with 3.12.0 (+27%)</title></path>
<text class="nj-charts-val" x="418.083" y="505.5">+27%</text>
<text class="nj-charts-rowlabel nj-charts-code" x="142" y="540" text-anchor="end">server_config</text>
<path class="nj-charts-c2" d="M320.833 517 H494.5 Q498.5 517 498.5 521 V524 Q498.5 528 494.5 528 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0: 4,388 ms against 2,878 ms with 3.12.0 (+52%)</title></path>
<text class="nj-charts-val" x="503.5" y="526.5">+52%</text>
<path class="nj-charts-c1" d="M320.833 531 H415.917 Q419.917 531 419.917 535 V538 Q419.917 542 415.917 542 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, precompiled header: 3,722 ms against 2,878 ms with 3.12.0 (+29%)</title></path>
<text class="nj-charts-val" x="424.917" y="540.5">+29%</text>
<path class="nj-charts-c3" d="M320.833 545 H422.75 Q426.75 545 426.75 549 V552 Q426.75 556 422.75 556 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, module: 3,774 ms against 2,878 ms with 3.12.0 (+31%)</title></path>
<text class="nj-charts-val" x="431.75" y="554.5">+31%</text>
<line class="nj-charts-ref" x1="320.833" y1="52" x2="320.833" y2="574"/>
<text class="nj-charts-tick" x="184.167" y="590">&#8722;40%</text>
<text class="nj-charts-tick" x="252.5" y="590">&#8722;20%</text>
<text class="nj-charts-tick" x="320.833" y="590">0</text>
<text class="nj-charts-tick" x="389.167" y="590">+20%</text>
<text class="nj-charts-tick" x="457.5" y="590">+40%</text>
<text class="nj-charts-tick" x="525.833" y="590">+60%</text>
<text class="nj-charts-tick" x="355" y="608">compile time compared with 3.12.0, less is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

@@ -1,60 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 640 312" role="img" aria-labelledby="nj-blog-swar nj-blog-swar-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-swar">Finding the end of a run of ordinary string characters eight bytes at a time</title>
<desc id="nj-blog-swar-d">The eight bytes w, i, t, t, e, r, quote and comma are loaded as one word. The test sets the high bit only in byte 6, the quote. Counting trailing zero bits gives 55, divided by eight gives 6: bytes 0 to 5 are copied at once, then the quote ends the string.</desc>
<text class="fg-h" x="40" y="20">eight input bytes, loaded as one 64-bit word (byte 0 is the lowest)</text>
<rect class="fg-cell" x="40" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="72" y="60" text-anchor="middle">w</text>
<text class="nj-charts-tick" x="72" y="92">0x77</text>
<text class="nj-charts-tick" x="72" y="108">byte 0</text>
<rect class="fg-cell" x="110" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="142" y="60" text-anchor="middle">i</text>
<text class="nj-charts-tick" x="142" y="92">0x69</text>
<text class="nj-charts-tick" x="142" y="108">byte 1</text>
<rect class="fg-cell" x="180" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="212" y="60" text-anchor="middle">t</text>
<text class="nj-charts-tick" x="212" y="92">0x74</text>
<text class="nj-charts-tick" x="212" y="108">byte 2</text>
<rect class="fg-cell" x="250" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="282" y="60" text-anchor="middle">t</text>
<text class="nj-charts-tick" x="282" y="92">0x74</text>
<text class="nj-charts-tick" x="282" y="108">byte 3</text>
<rect class="fg-cell" x="320" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="352" y="60" text-anchor="middle">e</text>
<text class="nj-charts-tick" x="352" y="92">0x65</text>
<text class="nj-charts-tick" x="352" y="108">byte 4</text>
<rect class="fg-cell" x="390" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="422" y="60" text-anchor="middle">r</text>
<text class="nj-charts-tick" x="422" y="92">0x72</text>
<text class="nj-charts-tick" x="422" y="108">byte 5</text>
<rect class="fg-cell" x="460" y="34" width="64" height="40" rx="4"/>
<rect class="nj-charts-c2" fill-opacity=".25" x="460" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="492" y="60" text-anchor="middle">&quot;</text>
<text class="nj-charts-tick" x="492" y="92">0x22</text>
<text class="nj-charts-tick" x="492" y="108">byte 6</text>
<rect class="fg-cell" x="530" y="34" width="64" height="40" rx="4"/>
<text class="fg-code" x="562" y="60" text-anchor="middle">,</text>
<text class="nj-charts-tick" x="562" y="92">0x2C</text>
<text class="nj-charts-tick" x="562" y="108">byte 7</text>
<text class="fg-h" x="40" y="132">swar_string_special(): the high bit of each byte that needs handling</text>
<rect class="fg-cell" x="40" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="72" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="110" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="142" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="180" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="212" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="250" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="282" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="320" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="352" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="390" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="422" y="169" text-anchor="middle">0x00</text>
<rect class="fg-cell" x="460" y="146" width="64" height="34" rx="4"/>
<rect class="nj-charts-c2" fill-opacity=".25" x="460" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="492" y="169" text-anchor="middle">0x80</text>
<rect class="fg-cell" x="530" y="146" width="64" height="34" rx="4"/>
<text class="fg-code" x="562" y="169" text-anchor="middle">0x00</text>
<text class="fg-code" x="40" y="216">count_trailing_zeros(0x0080000000000000) = 55</text>
<text class="fg-code" x="40" y="242">55 / 8 = 6: copy bytes 0 to 5 in one go, then handle the quote</text>
<text class="fg-note fg-note--l" x="40" y="272">No branch per byte: a few subtractions, ANDs and ORs per word,</text>
<text class="fg-note fg-note--l" x="40" y="290">then one count of trailing zeros.</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

@@ -1,53 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-accept_twitter nj-blog-tl-accept_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-accept_twitter">accept() twitter.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-accept_twitter-d">accept() twitter.json: speedup over 3.12.0 at each of 360 commits, ending at 10x. Labeled steps, by theme: 4, 1, 4, 4, 2, 2, 1.</desc>
<text class="nj-charts-panel" x="8" y="18">accept() twitter.json</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="172.5" x2="330" y2="172.5"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="176.5">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="137" x2="330" y2="137"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="141">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="101.5" x2="330" y2="101.5"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="105.5">8&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">16&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.1 45.6,208.1 45.6,207.9 46.4,207.9 46.4,208.0 47.2,208.0 47.2,207.8 48.0,207.8 48.0,207.9 48.8,207.9 48.8,208.0 49.6,208.0 49.6,208.1 50.4,208.1 50.4,208.3 51.2,208.3 51.2,207.3 52.0,207.3 52.0,207.9 52.8,207.9 52.8,208.1 53.6,208.1 53.6,208.0 54.4,208.0 54.4,207.9 55.2,207.9 55.2,207.8 55.9,207.8 55.9,207.9 56.7,207.9 56.7,207.9 57.5,207.9 57.5,207.8 58.3,207.8 58.3,208.1 59.1,208.1 59.1,207.4 59.9,207.4 59.9,208.0 60.7,208.0 60.7,208.0 61.5,208.0 61.5,207.8 62.3,207.8 62.3,207.9 63.1,207.9 63.1,208.0 63.9,208.0 63.9,207.4 64.7,207.4 64.7,207.9 65.5,207.9 65.5,207.7 66.3,207.7 66.3,207.8 67.1,207.8 67.1,208.0 67.9,208.0 67.9,208.0 68.7,208.0 68.7,207.5 69.5,207.5 69.5,207.8 70.3,207.8 70.3,207.7 71.1,207.7 71.1,207.8 71.9,207.8 71.9,208.1 72.7,208.1 72.7,207.8 73.5,207.8 73.5,207.3 74.3,207.3 74.3,207.9 75.1,207.9 75.1,207.4 75.9,207.4 75.9,207.8 76.7,207.8 76.7,207.5 77.5,207.5 77.5,208.1 78.3,208.1 78.3,207.7 79.1,207.7 79.1,207.7 79.8,207.7 79.8,208.1 80.6,208.1 80.6,208.2 81.4,208.2 81.4,207.9 82.2,207.9 82.2,207.8 83.0,207.8 83.0,207.9 83.8,207.9 83.8,207.9 84.6,207.9 84.6,207.6 85.4,207.6 85.4,207.9 86.2,207.9 86.2,207.9 87.0,207.9 87.0,208.0 87.8,208.0 87.8,197.9 88.6,197.9 88.6,198.5 89.4,198.5 89.4,198.7 90.2,198.7 90.2,198.3 91.0,198.3 91.0,198.7 91.8,198.7 91.8,198.0 92.6,198.0 92.6,198.0 93.4,198.0 93.4,198.5 94.2,198.5 94.2,198.3 95.0,198.3 95.0,198.4 95.8,198.4 95.8,198.7 96.6,198.7 96.6,198.0 97.4,198.0 97.4,198.4 98.2,198.4 98.2,198.5 99.0,198.5 99.0,198.7 99.8,198.7 99.8,198.5 100.6,198.5 100.6,198.5 101.4,198.5 101.4,198.4 102.2,198.4 102.2,198.9 103.0,198.9 103.0,198.3 103.7,198.3 103.7,198.5 104.5,198.5 104.5,199.2 105.3,199.2 105.3,198.8 106.1,198.8 106.1,197.9 106.9,197.9 106.9,198.0 107.7,198.0 107.7,198.4 108.5,198.4 108.5,198.7 109.3,198.7 109.3,198.7 110.1,198.7 110.1,198.7 110.9,198.7 110.9,197.9 111.7,197.9 111.7,197.8 112.5,197.8 112.5,198.3 113.3,198.3 113.3,198.5 114.1,198.5 114.1,198.9 114.9,198.9 114.9,198.0 115.7,198.0 115.7,198.3 116.5,198.3 116.5,198.6 117.3,198.6 117.3,198.4 118.1,198.4 118.1,198.6 118.9,198.6 118.9,197.1 119.7,197.1 119.7,198.2 120.5,198.2 120.5,198.3 121.3,198.3 121.3,198.1 122.1,198.1 122.1,198.0 122.9,198.0 122.9,198.0 123.7,198.0 123.7,198.3 124.5,198.3 124.5,198.3 125.3,198.3 125.3,198.1 126.1,198.1 126.1,198.5 126.9,198.5 126.9,198.0 127.6,198.0 127.6,198.0 128.4,198.0 128.4,159.4 129.2,159.4 129.2,159.2 130.0,159.2 130.0,158.7 130.8,158.7 130.8,158.5 131.6,158.5 131.6,159.3 132.4,159.3 132.4,158.9 133.2,158.9 133.2,158.8 134.0,158.8 134.0,159.2 134.8,159.2 134.8,159.3 135.6,159.3 135.6,159.4 136.4,159.4 136.4,158.6 137.2,158.6 137.2,159.3 138.0,159.3 138.0,158.8 138.8,158.8 138.8,159.3 139.6,159.3 139.6,158.4 140.4,158.4 140.4,159.3 141.2,159.3 141.2,158.4 142.0,158.4 142.0,159.3 142.8,159.3 142.8,159.2 143.6,159.2 143.6,158.5 144.4,158.5 144.4,158.8 145.2,158.8 145.2,158.8 146.0,158.8 146.0,159.6 146.8,159.6 146.8,159.2 147.6,159.2 147.6,158.7 148.4,158.7 148.4,159.3 149.2,159.3 149.2,158.5 150.0,158.5 150.0,158.8 150.8,158.8 150.8,158.5 151.5,158.5 151.5,158.4 152.3,158.4 152.3,157.9 153.1,157.9 153.1,159.2 153.9,159.2 153.9,157.9 154.7,157.9 154.7,159.1 155.5,159.1 155.5,159.0 156.3,159.0 156.3,158.7 157.1,158.7 157.1,159.0 157.9,159.0 157.9,158.5 158.7,158.5 158.7,158.1 159.5,158.1 159.5,157.9 160.3,157.9 160.3,158.0 161.1,158.0 161.1,158.4 161.9,158.4 161.9,158.2 162.7,158.2 162.7,158.4 163.5,158.4 163.5,158.5 164.3,158.5 164.3,158.5 165.1,158.5 165.1,158.1 165.9,158.1 165.9,158.8 166.7,158.8 166.7,158.3 167.5,158.3 167.5,158.8 168.3,158.8 168.3,158.5 169.1,158.5 169.1,158.3 169.9,158.3 169.9,157.8 170.7,157.8 170.7,158.2 171.5,158.2 171.5,158.2 172.3,158.2 172.3,158.3 173.1,158.3 173.1,157.2 173.9,157.2 173.9,157.5 174.7,157.5 174.7,157.5 175.4,157.5 175.4,157.8 176.2,157.8 176.2,158.4 177.0,158.4 177.0,158.2 177.8,158.2 177.8,158.1 178.6,158.1 178.6,157.7 179.4,157.7 179.4,157.9 180.2,157.9 180.2,157.5 181.0,157.5 181.0,157.3 181.8,157.3 181.8,158.6 182.6,158.6 182.6,158.2 183.4,158.2 183.4,157.9 184.2,157.9 184.2,158.1 185.0,158.1 185.0,157.3 185.8,157.3 185.8,157.7 186.6,157.7 186.6,158.1 187.4,158.1 187.4,157.9 188.2,157.9 188.2,158.5 189.0,158.5 189.0,157.3 189.8,157.3 189.8,157.8 190.6,157.8 190.6,158.2 191.4,158.2 191.4,157.7 192.2,157.7 192.2,158.3 193.0,158.3 193.0,157.3 193.8,157.3 193.8,158.4 194.6,158.4 194.6,157.9 195.4,157.9 195.4,158.1 196.2,158.1 196.2,157.4 197.0,157.4 197.0,158.0 197.8,158.0 197.8,157.0 198.6,157.0 198.6,157.9 199.3,157.9 199.3,157.6 200.1,157.6 200.1,158.0 200.9,158.0 200.9,158.1 201.7,158.1 201.7,157.9 202.5,157.9 202.5,158.5 203.3,158.5 203.3,158.9 204.1,158.9 204.1,158.7 204.9,158.7 204.9,157.4 205.7,157.4 205.7,157.6 206.5,157.6 206.5,157.7 207.3,157.7 207.3,157.8 208.1,157.8 208.1,158.2 208.9,158.2 208.9,157.8 209.7,157.8 209.7,158.1 210.5,158.1 210.5,158.1 211.3,158.1 211.3,158.5 212.1,158.5 212.1,157.4 212.9,157.4 212.9,158.6Line truncated
<circle class="nj-charts-json-dot" cx="87.8" cy="197.9" r="3.5"><title>#5234: 1.22&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="87.8" y1="54.0" x2="87.8" y2="192.9"/>
<circle class="nj-theme-dot" cx="87.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="87.8" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="128.4" cy="159.4" r="3.5"><title>#5283: 2.6&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="128.4" y1="54.0" x2="128.4" y2="154.4"/>
<circle class="nj-theme-dot" cx="128.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="128.4" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="219.3" cy="153.4" r="3.5"><title>#5592: 2.9&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="219.3" y1="54.0" x2="219.3" y2="148.4"/>
<circle class="nj-theme-dot" cx="219.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="219.3" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="239.2" cy="141.0" r="3.5"><title>#5809: 3.7&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="240.0" cy="136.5" r="3.5"><title>#5810: 4.0&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="240.0" y1="36.0" x2="240.0" y2="131.5"/>
<circle class="nj-theme-dot" cx="231.0" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="231.0" y="32.0" text-anchor="middle">4</text>
<circle class="nj-theme-dot" cx="249.0" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="249.0" y="32.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="268.7" cy="126.4" r="3.5"><title>#5853: 4.9&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="268.7" y1="54.0" x2="268.7" y2="121.4"/>
<circle class="nj-theme-dot" cx="268.7" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="268.7" y="50.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="330.0" cy="89.0" r="3.5"><title>#6031: 10&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="330.0" y1="54.0" x2="330.0" y2="84.0"/>
<circle class="nj-theme-dot" cx="322.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="322.5" y="50.0" text-anchor="middle">1</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1,32 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-dump_canada nj-blog-tl-dump_canada-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-dump_canada">dump() canada.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-dump_canada-d">dump() canada.json: speedup over 3.12.0 at each of 360 commits, ending at 3.2x. Labeled steps, by theme: 6, 3.</desc>
<text class="nj-charts-panel" x="8" y="18">dump() canada.json</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="160.667" x2="330" y2="160.667"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="164.667">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="113.333" x2="330" y2="113.333"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="117.333">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">8&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,207.2 46.4,207.2 46.4,207.9 47.2,207.9 47.2,206.7 48.0,206.7 48.0,207.5 48.8,207.5 48.8,207.7 49.6,207.7 49.6,207.3 50.4,207.3 50.4,207.9 51.2,207.9 51.2,206.6 52.0,206.6 52.0,207.5 52.8,207.5 52.8,208.0 53.6,208.0 53.6,207.6 54.4,207.6 54.4,207.2 55.2,207.2 55.2,207.5 55.9,207.5 55.9,206.6 56.7,206.6 56.7,207.1 57.5,207.1 57.5,207.1 58.3,207.1 58.3,207.2 59.1,207.2 59.1,206.6 59.9,206.6 59.9,207.5 60.7,207.5 60.7,207.6 61.5,207.6 61.5,207.7 62.3,207.7 62.3,207.2 63.1,207.2 63.1,206.5 63.9,206.5 63.9,206.8 64.7,206.8 64.7,207.1 65.5,207.1 65.5,207.0 66.3,207.0 66.3,207.1 67.1,207.1 67.1,206.7 67.9,206.7 67.9,208.2 68.7,208.2 68.7,207.5 69.5,207.5 69.5,206.6 70.3,206.6 70.3,206.7 71.1,206.7 71.1,206.3 71.9,206.3 71.9,208.4 72.7,208.4 72.7,207.3 73.5,207.3 73.5,206.8 74.3,206.8 74.3,208.0 75.1,208.0 75.1,207.8 75.9,207.8 75.9,207.1 76.7,207.1 76.7,207.5 77.5,207.5 77.5,207.9 78.3,207.9 78.3,206.3 79.1,206.3 79.1,206.8 79.8,206.8 79.8,207.5 80.6,207.5 80.6,208.1 81.4,208.1 81.4,206.6 82.2,206.6 82.2,207.2 83.0,207.2 83.0,207.2 83.8,207.2 83.8,207.4 84.6,207.4 84.6,207.0 85.4,207.0 85.4,206.7 86.2,206.7 86.2,206.5 87.0,206.5 87.0,207.6 87.8,207.6 87.8,207.4 88.6,207.4 88.6,207.2 89.4,207.2 89.4,207.5 90.2,207.5 90.2,207.6 91.0,207.6 91.0,208.0 91.8,208.0 91.8,208.2 92.6,208.2 92.6,206.7 93.4,206.7 93.4,207.4 94.2,207.4 94.2,206.7 95.0,206.7 95.0,206.6 95.8,206.6 95.8,208.0 96.6,208.0 96.6,208.0 97.4,208.0 97.4,206.3 98.2,206.3 98.2,208.3 99.0,208.3 99.0,207.8 99.8,207.8 99.8,207.4 100.6,207.4 100.6,206.3 101.4,206.3 101.4,208.1 102.2,208.1 102.2,207.5 103.0,207.5 103.0,207.4 103.7,207.4 103.7,207.5 104.5,207.5 104.5,207.7 105.3,207.7 105.3,208.0 106.1,208.0 106.1,207.0 106.9,207.0 106.9,207.5 107.7,207.5 107.7,207.2 108.5,207.2 108.5,207.7 109.3,207.7 109.3,207.3 110.1,207.3 110.1,208.0 110.9,208.0 110.9,206.7 111.7,206.7 111.7,206.6 112.5,206.6 112.5,207.2 113.3,207.2 113.3,208.1 114.1,208.1 114.1,208.1 114.9,208.1 114.9,206.7 115.7,206.7 115.7,207.8 116.5,207.8 116.5,207.6 117.3,207.6 117.3,207.4 118.1,207.4 118.1,207.1 118.9,207.1 118.9,207.5 119.7,207.5 119.7,208.8 120.5,208.8 120.5,209.2 121.3,209.2 121.3,208.4 122.1,208.4 122.1,208.3 122.9,208.3 122.9,208.0 123.7,208.0 123.7,209.0 124.5,209.0 124.5,208.5 125.3,208.5 125.3,209.1 126.1,209.1 126.1,209.2 126.9,209.2 126.9,208.6 127.6,208.6 127.6,207.7 128.4,207.7 128.4,207.7 129.2,207.7 129.2,207.5 130.0,207.5 130.0,202.2 130.8,202.2 130.8,202.3 131.6,202.3 131.6,201.7 132.4,201.7 132.4,202.3 133.2,202.3 133.2,201.9 134.0,201.9 134.0,201.2 134.8,201.2 134.8,202.1 135.6,202.1 135.6,202.6 136.4,202.6 136.4,201.5 137.2,201.5 137.2,202.3 138.0,202.3 138.0,202.3 138.8,202.3 138.8,201.7 139.6,201.7 139.6,201.3 140.4,201.3 140.4,202.5 141.2,202.5 141.2,201.1 142.0,201.1 142.0,202.9 142.8,202.9 142.8,202.2 143.6,202.2 143.6,201.7 144.4,201.7 144.4,201.7 145.2,201.7 145.2,201.6 146.0,201.6 146.0,203.0 146.8,203.0 146.8,202.7 147.6,202.7 147.6,202.4 148.4,202.4 148.4,202.8 149.2,202.8 149.2,202.1 150.0,202.1 150.0,203.1 150.8,203.1 150.8,202.3 151.5,202.3 151.5,202.3 152.3,202.3 152.3,201.8 153.1,201.8 153.1,203.1 153.9,203.1 153.9,201.8 154.7,201.8 154.7,202.6 155.5,202.6 155.5,202.6 156.3,202.6 156.3,202.9 157.1,202.9 157.1,202.3 157.9,202.3 157.9,202.3 158.7,202.3 158.7,201.6 159.5,201.6 159.5,201.5 160.3,201.5 160.3,202.4 161.1,202.4 161.1,201.7 161.9,201.7 161.9,201.2 162.7,201.2 162.7,202.2 163.5,202.2 163.5,201.6 164.3,201.6 164.3,201.6 165.1,201.6 165.1,201.8 165.9,201.8 165.9,202.1 166.7,202.1 166.7,201.7 167.5,201.7 167.5,201.4 168.3,201.4 168.3,202.2 169.1,202.2 169.1,202.7 169.9,202.7 169.9,202.4 170.7,202.4 170.7,201.7 171.5,201.7 171.5,201.7 172.3,201.7 172.3,202.3 173.1,202.3 173.1,201.6 173.9,201.6 173.9,201.7 174.7,201.7 174.7,202.2 175.4,202.2 175.4,202.2 176.2,202.2 176.2,202.4 177.0,202.4 177.0,201.7 177.8,201.7 177.8,202.1 178.6,202.1 178.6,201.6 179.4,201.6 179.4,202.2 180.2,202.2 180.2,201.9 181.0,201.9 181.0,201.9 181.8,201.9 181.8,202.5 182.6,202.5 182.6,201.6 183.4,201.6 183.4,202.1 184.2,202.1 184.2,202.3 185.0,202.3 185.0,201.8 185.8,201.8 185.8,201.5 186.6,201.5 186.6,202.3 187.4,202.3 187.4,202.2 188.2,202.2 188.2,202.9 189.0,202.9 189.0,201.3 189.8,201.3 189.8,202.2 190.6,202.2 190.6,203.6 191.4,203.6 191.4,201.9 192.2,201.9 192.2,202.4 193.0,202.4 193.0,201.7 193.8,201.7 193.8,202.7 194.6,202.7 194.6,202.3 195.4,202.3 195.4,202.5 196.2,202.5 196.2,202.1 197.0,202.1 197.0,203.4 197.8,203.4 197.8,202.1 198.6,202.1 198.6,202.3 199.3,202.3 199.3,201.9 200.1,201.9 200.1,202.3 200.9,202.3 200.9,201.7 201.7,201.7 201.7,202.4 202.5,202.4 202.5,202.3 203.3,202.3 203.3,202.9 204.1,202.9 204.1,202.9 204.9,202.9 204.9,202.2 205.7,202.2 205.7,202.4 206.5,202.4 206.5,202.2 207.3,202.2 207.3,202.7 208.1,202.7 208.1,202.5 208.9,202.5 208.9,202.5 209.7,202.5 209.7,201.5 210.5,201.5 210.5,203.1 211.3,203.1 211.3,203.2 212.1,203.2 212.1,201.5 212.9,201.5 212.9,203.3Line truncated
<circle class="nj-charts-json-dot" cx="130.0" cy="202.2" r="3.5"><title>#5285: 1.09&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="130.0" y1="54.0" x2="130.0" y2="197.2"/>
<circle class="nj-theme-dot" cx="130.0" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="130.0" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="242.4" cy="130.7" r="3.5"><title>#5634: 3.1&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="242.4" y1="54.0" x2="242.4" y2="125.7"/>
<circle class="nj-theme-dot" cx="242.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="242.4" y="50.0" text-anchor="middle">3</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,39 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-dump_twitter nj-blog-tl-dump_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-dump_twitter">dump() twitter.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-dump_twitter-d">dump() twitter.json: speedup over 3.12.0 at each of 360 commits, ending at 6.8x. Labeled steps, by theme: 6, 2, 2, 2.</desc>
<text class="nj-charts-panel" x="8" y="18">dump() twitter.json</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="172.5" x2="330" y2="172.5"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="176.5">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="137" x2="330" y2="137"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="141">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="101.5" x2="330" y2="101.5"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="105.5">8&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">16&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,207.2 46.4,207.2 46.4,207.9 47.2,207.9 47.2,206.8 48.0,206.8 48.0,208.0 48.8,208.0 48.8,207.4 49.6,207.4 49.6,207.3 50.4,207.3 50.4,208.0 51.2,208.0 51.2,206.8 52.0,206.8 52.0,207.2 52.8,207.2 52.8,208.0 53.6,208.0 53.6,207.2 54.4,207.2 54.4,207.5 55.2,207.5 55.2,206.8 55.9,206.8 55.9,206.9 56.7,206.9 56.7,207.5 57.5,207.5 57.5,207.3 58.3,207.3 58.3,207.8 59.1,207.8 59.1,206.8 59.9,206.8 59.9,207.8 60.7,207.8 60.7,207.4 61.5,207.4 61.5,208.0 62.3,208.0 62.3,207.4 63.1,207.4 63.1,207.3 63.9,207.3 63.9,206.9 64.7,206.9 64.7,207.3 65.5,207.3 65.5,207.4 66.3,207.4 66.3,207.6 67.1,207.6 67.1,207.5 67.9,207.5 67.9,207.6 68.7,207.6 68.7,207.4 69.5,207.4 69.5,207.2 70.3,207.2 70.3,207.1 71.1,207.1 71.1,207.3 71.9,207.3 71.9,207.7 72.7,207.7 72.7,207.8 73.5,207.8 73.5,206.9 74.3,206.9 74.3,207.6 75.1,207.6 75.1,207.0 75.9,207.0 75.9,207.0 76.7,207.0 76.7,207.3 77.5,207.3 77.5,207.6 78.3,207.6 78.3,206.8 79.1,206.8 79.1,207.7 79.8,207.7 79.8,207.4 80.6,207.4 80.6,207.5 81.4,207.5 81.4,207.1 82.2,207.1 82.2,207.3 83.0,207.3 83.0,207.5 83.8,207.5 83.8,207.3 84.6,207.3 84.6,207.3 85.4,207.3 85.4,206.9 86.2,206.9 86.2,207.4 87.0,207.4 87.0,207.9 87.8,207.9 87.8,207.3 88.6,207.3 88.6,206.8 89.4,206.8 89.4,207.6 90.2,207.6 90.2,207.7 91.0,207.7 91.0,208.6 91.8,208.6 91.8,208.5 92.6,208.5 92.6,208.6 93.4,208.6 93.4,209.2 94.2,209.2 94.2,208.5 95.0,208.5 95.0,208.2 95.8,208.2 95.8,209.3 96.6,209.3 96.6,208.4 97.4,208.4 97.4,208.4 98.2,208.4 98.2,209.0 99.0,209.0 99.0,209.0 99.8,209.0 99.8,208.7 100.6,208.7 100.6,208.9 101.4,208.9 101.4,208.7 102.2,208.7 102.2,209.0 103.0,209.0 103.0,208.8 103.7,208.8 103.7,208.7 104.5,208.7 104.5,209.3 105.3,209.3 105.3,208.6 106.1,208.6 106.1,208.5 106.9,208.5 106.9,208.4 107.7,208.4 107.7,208.0 108.5,208.0 108.5,208.9 109.3,208.9 109.3,208.6 110.1,208.6 110.1,208.9 110.9,208.9 110.9,208.1 111.7,208.1 111.7,208.0 112.5,208.0 112.5,208.6 113.3,208.6 113.3,208.5 114.1,208.5 114.1,209.1 114.9,209.1 114.9,208.0 115.7,208.0 115.7,209.1 116.5,209.1 116.5,208.9 117.3,208.9 117.3,208.5 118.1,208.5 118.1,209.1 118.9,209.1 118.9,209.0 119.7,209.0 119.7,208.8 120.5,208.8 120.5,208.6 121.3,208.6 121.3,208.6 122.1,208.6 122.1,208.2 122.9,208.2 122.9,209.0 123.7,209.0 123.7,209.2 124.5,209.2 124.5,209.1 125.3,209.1 125.3,209.2 126.1,209.2 126.1,209.2 126.9,209.2 126.9,208.5 127.6,208.5 127.6,208.7 128.4,208.7 128.4,209.5 129.2,209.5 129.2,208.4 130.0,208.4 130.0,147.4 130.8,147.4 130.8,148.3 131.6,148.3 131.6,148.4 132.4,148.4 132.4,147.5 133.2,147.5 133.2,147.5 134.0,147.5 134.0,147.7 134.8,147.7 134.8,148.2 135.6,148.2 135.6,148.2 136.4,148.2 136.4,147.3 137.2,147.3 137.2,148.1 138.0,148.1 138.0,147.2 138.8,147.2 138.8,147.5 139.6,147.5 139.6,147.3 140.4,147.3 140.4,148.4 141.2,148.4 141.2,147.4 142.0,147.4 142.0,148.3 142.8,148.3 142.8,148.5 143.6,148.5 143.6,147.7 144.4,147.7 144.4,147.8 145.2,147.8 145.2,148.0 146.0,148.0 146.0,148.5 146.8,148.5 146.8,148.0 147.6,148.0 147.6,148.1 148.4,148.1 148.4,148.2 149.2,148.2 149.2,148.3 150.0,148.3 150.0,149.0 150.8,149.0 150.8,148.7 151.5,148.7 151.5,148.2 152.3,148.2 152.3,148.1 153.1,148.1 153.1,148.9 153.9,148.9 153.9,147.7 154.7,147.7 154.7,149.2 155.5,149.2 155.5,149.1 156.3,149.1 156.3,148.8 157.1,148.8 157.1,148.1 157.9,148.1 157.9,148.7 158.7,148.7 158.7,147.7 159.5,147.7 159.5,147.9 160.3,147.9 160.3,147.7 161.1,147.7 161.1,148.3 161.9,148.3 161.9,148.0 162.7,148.0 162.7,148.2 163.5,148.2 163.5,148.4 164.3,148.4 164.3,148.3 165.1,148.3 165.1,148.1 165.9,148.1 165.9,149.0 166.7,149.0 166.7,147.8 167.5,147.8 167.5,148.8 168.3,148.8 168.3,148.3 169.1,148.3 169.1,148.0 169.9,148.0 169.9,147.8 170.7,147.8 170.7,148.0 171.5,148.0 171.5,147.7 172.3,147.7 172.3,148.2 173.1,148.2 173.1,147.1 173.9,147.1 173.9,147.9 174.7,147.9 174.7,147.9 175.4,147.9 175.4,147.9 176.2,147.9 176.2,147.7 177.0,147.7 177.0,148.0 177.8,148.0 177.8,147.4 178.6,147.4 178.6,147.5 179.4,147.5 179.4,147.5 180.2,147.5 180.2,147.0 181.0,147.0 181.0,147.0 181.8,147.0 181.8,148.2 182.6,148.2 182.6,147.7 183.4,147.7 183.4,148.0 184.2,148.0 184.2,148.2 185.0,148.2 185.0,147.7 185.8,147.7 185.8,147.8 186.6,147.8 186.6,148.2 187.4,148.2 187.4,148.3 188.2,148.3 188.2,148.5 189.0,148.5 189.0,148.1 189.8,148.1 189.8,147.9 190.6,147.9 190.6,148.2 191.4,148.2 191.4,147.5 192.2,147.5 192.2,148.1 193.0,148.1 193.0,147.6 193.8,147.6 193.8,148.4 194.6,148.4 194.6,148.2 195.4,148.2 195.4,148.3 196.2,148.3 196.2,148.7 197.0,148.7 197.0,149.4 197.8,149.4 197.8,148.7 198.6,148.7 198.6,149.5 199.3,149.5 199.3,148.2 200.1,148.2 200.1,148.5 200.9,148.5 200.9,149.1 201.7,149.1 201.7,148.8 202.5,148.8 202.5,149.2 203.3,149.2 203.3,149.3 204.1,149.3 204.1,149.1 204.9,149.1 204.9,148.6 205.7,148.6 205.7,148.9 206.5,148.9 206.5,148.5 207.3,148.5 207.3,148.9 208.1,148.9 208.1,149.0 208.9,149.0 208.9,149.0 209.7,149.0 209.7,148.5 210.5,148.5 210.5,149.1 211.3,149.1 211.3,149.2 212.1,149.2 212.1,148.3 212.9,148.3 212.9,149.4Line truncated
<circle class="nj-charts-json-dot" cx="130.0" cy="147.4" r="3.5"><title>#5285: 3.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="130.0" y1="54.0" x2="130.0" y2="142.4"/>
<circle class="nj-theme-dot" cx="130.0" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="130.0" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="241.6" cy="139.0" r="3.5"><title>#5738: 3.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="241.6" y1="54.0" x2="241.6" y2="134.0"/>
<circle class="nj-theme-dot" cx="241.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="241.6" y="50.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="271.0" cy="131.0" r="3.5"><title>#5878: 4.5&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="276.6" cy="109.6" r="3.5"><title>#5883: 6.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="276.6" y1="54.0" x2="276.6" y2="104.6"/>
<circle class="nj-theme-dot" cx="276.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="276.6" y="50.0" text-anchor="middle">2</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,42 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-from_cbor_twitter nj-blog-tl-from_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-from_cbor_twitter">from_cbor() twitter: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-from_cbor_twitter-d">from_cbor() twitter: speedup over 3.12.0 at each of 360 commits, ending at 2.8x. Labeled steps, by theme: 1, 4, U, U, 4.</desc>
<text class="nj-charts-panel" x="8" y="18">from_cbor() twitter</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="137" x2="330" y2="137"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="141">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">4&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,209.1 45.6,209.1 45.6,208.2 46.4,208.2 46.4,208.6 47.2,208.6 47.2,208.0 48.0,208.0 48.0,208.4 48.8,208.4 48.8,208.6 49.6,208.6 49.6,208.3 50.4,208.3 50.4,209.1 51.2,209.1 51.2,207.8 52.0,207.8 52.0,208.5 52.8,208.5 52.8,208.6 53.6,208.6 53.6,208.6 54.4,208.6 54.4,207.7 55.2,207.7 55.2,207.1 55.9,207.1 55.9,207.3 56.7,207.3 56.7,206.9 57.5,206.9 57.5,207.1 58.3,207.1 58.3,207.0 59.1,207.0 59.1,207.1 59.9,207.1 59.9,207.1 60.7,207.1 60.7,207.5 61.5,207.5 61.5,207.5 62.3,207.5 62.3,206.9 63.1,206.9 63.1,207.0 63.9,207.0 63.9,206.2 64.7,206.2 64.7,207.1 65.5,207.1 65.5,208.5 66.3,208.5 66.3,208.0 67.1,208.0 67.1,207.8 67.9,207.8 67.9,208.5 68.7,208.5 68.7,207.8 69.5,207.8 69.5,207.0 70.3,207.0 70.3,208.1 71.1,208.1 71.1,208.2 71.9,208.2 71.9,208.6 72.7,208.6 72.7,208.1 73.5,208.1 73.5,207.2 74.3,207.2 74.3,208.3 75.1,208.3 75.1,207.4 75.9,207.4 75.9,207.9 76.7,207.9 76.7,207.7 77.5,207.7 77.5,208.6 78.3,208.6 78.3,207.3 79.1,207.3 79.1,207.9 79.8,207.9 79.8,208.4 80.6,208.4 80.6,208.5 81.4,208.5 81.4,208.0 82.2,208.0 82.2,207.1 83.0,207.1 83.0,208.1 83.8,208.1 83.8,208.1 84.6,208.1 84.6,207.8 85.4,207.8 85.4,207.9 86.2,207.9 86.2,207.9 87.0,207.9 87.0,208.7 87.8,208.7 87.8,208.1 88.6,208.1 88.6,168.9 89.4,168.9 89.4,170.3 90.2,170.3 90.2,169.9 91.0,169.9 91.0,169.0 91.8,169.0 91.8,169.6 92.6,169.6 92.6,169.1 93.4,169.1 93.4,170.1 94.2,170.1 94.2,168.8 95.0,168.8 95.0,167.9 95.8,167.9 95.8,170.4 96.6,170.4 96.6,169.5 97.4,169.5 97.4,169.7 98.2,169.7 98.2,172.9 99.0,172.9 99.0,170.5 99.8,170.5 99.8,170.4 100.6,170.4 100.6,170.1 101.4,170.1 101.4,170.2 102.2,170.2 102.2,170.7 103.0,170.7 103.0,170.5 103.7,170.5 103.7,170.4 104.5,170.4 104.5,171.1 105.3,171.1 105.3,170.2 106.1,170.2 106.1,168.6 106.9,168.6 106.9,168.9 107.7,168.9 107.7,168.8 108.5,168.8 108.5,170.5 109.3,170.5 109.3,169.2 110.1,169.2 110.1,169.8 110.9,169.8 110.9,168.2 111.7,168.2 111.7,168.3 112.5,168.3 112.5,169.9 113.3,169.9 113.3,170.3 114.1,170.3 114.1,170.5 114.9,170.5 114.9,169.2 115.7,169.2 115.7,170.5 116.5,170.5 116.5,170.1 117.3,170.1 117.3,170.0 118.1,170.0 118.1,170.0 118.9,170.0 118.9,169.7 119.7,169.7 119.7,169.9 120.5,169.9 120.5,169.2 121.3,169.2 121.3,169.6 122.1,169.6 122.1,170.0 122.9,170.0 122.9,170.0 123.7,170.0 123.7,170.5 124.5,170.5 124.5,170.8 125.3,170.8 125.3,170.5 126.1,170.5 126.1,170.8 126.9,170.8 126.9,169.2 127.6,169.2 127.6,128.6 128.4,128.6 128.4,121.0 129.2,121.0 129.2,120.5 130.0,120.5 130.0,120.8 130.8,120.8 130.8,120.9 131.6,120.9 131.6,120.2 132.4,120.2 132.4,116.5 133.2,116.5 133.2,117.5 134.0,117.5 134.0,117.4 134.8,117.4 134.8,118.0 135.6,118.0 135.6,118.3 136.4,118.3 136.4,118.0 137.2,118.0 137.2,120.1 138.0,120.1 138.0,118.9 138.8,118.9 138.8,119.6 139.6,119.6 139.6,119.0 140.4,119.0 140.4,120.9 141.2,120.9 141.2,118.6 142.0,118.6 142.0,121.1 142.8,121.1 142.8,120.1 143.6,120.1 143.6,118.4 144.4,118.4 144.4,119.3 145.2,119.3 145.2,119.0 146.0,119.0 146.0,120.2 146.8,120.2 146.8,119.0 147.6,119.0 147.6,119.4 148.4,119.4 148.4,119.8 149.2,119.8 149.2,120.4 150.0,120.4 150.0,120.6 150.8,120.6 150.8,119.6 151.5,119.6 151.5,118.8 152.3,118.8 152.3,118.4 153.1,118.4 153.1,120.2 153.9,120.2 153.9,119.3 154.7,119.3 154.7,119.9 155.5,119.9 155.5,119.6 156.3,119.6 156.3,119.7 157.1,119.7 157.1,119.2 157.9,119.2 157.9,119.5 158.7,119.5 158.7,118.0 159.5,118.0 159.5,150.3 160.3,150.3 160.3,150.5 161.1,150.5 161.1,150.6 161.9,150.6 161.9,151.3 162.7,151.3 162.7,151.4 163.5,151.4 163.5,150.7 164.3,150.7 164.3,152.1 165.1,152.1 165.1,151.8 165.9,151.8 165.9,152.4 166.7,152.4 166.7,150.6 167.5,150.6 167.5,152.8 168.3,152.8 168.3,154.2 169.1,154.2 169.1,152.8 169.9,152.8 169.9,152.9 170.7,152.9 170.7,153.6 171.5,153.6 171.5,151.7 172.3,151.7 172.3,153.8 173.1,153.8 173.1,151.6 173.9,151.6 173.9,152.6 174.7,152.6 174.7,153.5 175.4,153.5 175.4,151.8 176.2,151.8 176.2,152.7 177.0,152.7 177.0,153.6 177.8,153.6 177.8,152.7 178.6,152.7 178.6,152.5 179.4,152.5 179.4,152.7 180.2,152.7 180.2,151.6 181.0,151.6 181.0,153.2 181.8,153.2 181.8,154.6 182.6,154.6 182.6,152.1 183.4,152.1 183.4,152.9 184.2,152.9 184.2,153.9 185.0,153.9 185.0,153.0 185.8,153.0 185.8,152.6 186.6,152.6 186.6,154.0 187.4,154.0 187.4,154.0 188.2,154.0 188.2,154.3 189.0,154.3 189.0,152.5 189.8,152.5 189.8,154.4 190.6,154.4 190.6,154.2 191.4,154.2 191.4,151.8 192.2,151.8 192.2,154.0 193.0,154.0 193.0,153.0 193.8,153.0 193.8,152.2 194.6,152.2 194.6,153.7 195.4,153.7 195.4,153.8 196.2,153.8 196.2,153.9 197.0,153.9 197.0,155.5 197.8,155.5 197.8,153.4 198.6,153.4 198.6,155.4 199.3,155.4 199.3,152.8 200.1,152.8 200.1,154.0 200.9,154.0 200.9,152.3 201.7,152.3 201.7,153.2 202.5,153.2 202.5,153.5 203.3,153.5 203.3,153.6 204.1,153.6 204.1,154.6 204.9,154.6 204.9,152.7 205.7,152.7 205.7,155.4 206.5,155.4 206.5,152.5 207.3,152.5 207.3,153.3 208.1,153.3 208.1,153.3 208.9,153.3 208.9,154.5 209.7,154.5 209.7,152.6 210.5,152.6 210.5,153.0 211.3,153.0 211.3,154.3 212.1,154.3 212.1,122.0 212.9,122.0 212.9,123.3Line truncated
<circle class="nj-charts-json-dot" cx="88.6" cy="168.9" r="3.5"><title>#5233: 1.47&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="88.6" y1="54.0" x2="88.6" y2="163.9"/>
<circle class="nj-theme-dot" cx="88.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="88.6" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="127.6" cy="128.6" r="3.5"><title>#5501: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="127.6" y1="54.0" x2="127.6" y2="123.6"/>
<circle class="nj-theme-dot" cx="127.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="127.6" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="159.5" cy="150.3" r="3.5"><title>#5185: 1.76&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="159.5" y1="54.0" x2="159.5" y2="145.3"/>
<circle class="nj-theme-dot nj-theme-dot--other" cx="159.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="159.5" y="50.0" text-anchor="middle">U</text>
<circle class="nj-charts-json-dot" cx="212.1" cy="122.0" r="3.5"><title>#5746: 2.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="212.1" y1="54.0" x2="212.1" y2="117.0"/>
<circle class="nj-theme-dot nj-theme-dot--other" cx="212.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="212.1" y="50.0" text-anchor="middle">U</text>
<circle class="nj-charts-json-dot" cx="328.4" cy="101.8" r="3.5"><title>#6028: 2.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="328.4" y1="54.0" x2="328.4" y2="96.8"/>
<circle class="nj-theme-dot" cx="322.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="322.5" y="50.0" text-anchor="middle">4</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1,52 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_canada nj-blog-tl-parse_canada-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_canada">parse() canada.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_canada-d">parse() canada.json: speedup over 3.12.0 at each of 360 commits, ending at 3.3x. Labeled steps, by theme: 4, 1, 3, 3, 3, 4, 1.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() canada.json</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="160.667" x2="330" y2="160.667"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="164.667">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="113.333" x2="330" y2="113.333"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="117.333">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">8&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.1 45.6,208.1 45.6,208.1 46.4,208.1 46.4,207.8 47.2,207.8 47.2,207.5 48.0,207.5 48.0,208.0 48.8,208.0 48.8,208.1 49.6,208.1 49.6,207.8 50.4,207.8 50.4,208.3 51.2,208.3 51.2,207.5 52.0,207.5 52.0,208.0 52.8,208.0 52.8,208.8 53.6,208.8 53.6,208.3 54.4,208.3 54.4,208.1 55.2,208.1 55.2,207.8 55.9,207.8 55.9,209.2 56.7,209.2 56.7,208.4 57.5,208.4 57.5,208.1 58.3,208.1 58.3,208.1 59.1,208.1 59.1,207.3 59.9,207.3 59.9,207.8 60.7,207.8 60.7,207.7 61.5,207.7 61.5,208.1 62.3,208.1 62.3,208.3 63.1,208.3 63.1,207.8 63.9,207.8 63.9,207.6 64.7,207.6 64.7,208.2 65.5,208.2 65.5,207.5 66.3,207.5 66.3,207.8 67.1,207.8 67.1,207.9 67.9,207.9 67.9,207.9 68.7,207.9 68.7,207.6 69.5,207.6 69.5,207.7 70.3,207.7 70.3,208.0 71.1,208.0 71.1,208.1 71.9,208.1 71.9,207.9 72.7,207.9 72.7,207.9 73.5,207.9 73.5,207.4 74.3,207.4 74.3,207.7 75.1,207.7 75.1,207.9 75.9,207.9 75.9,207.5 76.7,207.5 76.7,207.8 77.5,207.8 77.5,208.4 78.3,208.4 78.3,207.0 79.1,207.0 79.1,208.0 79.8,208.0 79.8,208.5 80.6,208.5 80.6,208.0 81.4,208.0 81.4,207.8 82.2,207.8 82.2,208.3 83.0,208.3 83.0,208.0 83.8,208.0 83.8,207.7 84.6,207.7 84.6,207.9 85.4,207.9 85.4,207.6 86.2,207.6 86.2,207.7 87.0,207.7 87.0,208.3 87.8,208.3 87.8,201.0 88.6,201.0 88.6,201.3 89.4,201.3 89.4,200.6 90.2,200.6 90.2,200.7 91.0,200.7 91.0,201.2 91.8,201.2 91.8,200.0 92.6,200.0 92.6,200.8 93.4,200.8 93.4,201.4 94.2,201.4 94.2,200.9 95.0,200.9 95.0,200.6 95.8,200.6 95.8,201.0 96.6,201.0 96.6,200.8 97.4,200.8 97.4,201.1 98.2,201.1 98.2,201.1 99.0,201.1 99.0,201.1 99.8,201.1 99.8,200.6 100.6,200.6 100.6,201.3 101.4,201.3 101.4,201.3 102.2,201.3 102.2,201.0 103.0,201.0 103.0,201.0 103.7,201.0 103.7,201.0 104.5,201.0 104.5,201.4 105.3,201.4 105.3,201.3 106.1,201.3 106.1,199.5 106.9,199.5 106.9,200.4 107.7,200.4 107.7,201.2 108.5,201.2 108.5,200.7 109.3,200.7 109.3,200.2 110.1,200.2 110.1,200.5 110.9,200.5 110.9,200.4 111.7,200.4 111.7,200.4 112.5,200.4 112.5,201.1 113.3,201.1 113.3,201.0 114.1,201.0 114.1,201.4 114.9,201.4 114.9,199.9 115.7,199.9 115.7,201.0 116.5,201.0 116.5,201.1 117.3,201.1 117.3,200.5 118.1,200.5 118.1,200.7 118.9,200.7 118.9,201.3 119.7,201.3 119.7,200.6 120.5,200.6 120.5,200.8 121.3,200.8 121.3,200.4 122.1,200.4 122.1,200.7 122.9,200.7 122.9,200.8 123.7,200.8 123.7,201.0 124.5,201.0 124.5,201.2 125.3,201.2 125.3,200.8 126.1,200.8 126.1,201.1 126.9,201.1 126.9,200.9 127.6,200.9 127.6,200.7 128.4,200.7 128.4,181.8 129.2,181.8 129.2,182.4 130.0,182.4 130.0,182.8 130.8,182.8 130.8,181.9 131.6,181.9 131.6,181.6 132.4,181.6 132.4,182.6 133.2,182.6 133.2,181.8 134.0,181.8 134.0,181.5 134.8,181.5 134.8,182.5 135.6,182.5 135.6,183.2 136.4,183.2 136.4,181.4 137.2,181.4 137.2,182.8 138.0,182.8 138.0,182.1 138.8,182.1 138.8,182.7 139.6,182.7 139.6,181.6 140.4,181.6 140.4,182.5 141.2,182.5 141.2,182.7 142.0,182.7 142.0,182.5 142.8,182.5 142.8,182.1 143.6,182.1 143.6,180.8 144.4,180.8 144.4,182.5 145.2,182.5 145.2,181.7 146.0,181.7 146.0,182.9 146.8,182.9 146.8,182.5 147.6,182.5 147.6,181.8 148.4,181.8 148.4,182.2 149.2,182.2 149.2,184.2 150.0,184.2 150.0,183.5 150.8,183.5 150.8,182.1 151.5,182.1 151.5,181.2 152.3,181.2 152.3,182.2 153.1,182.2 153.1,182.1 153.9,182.1 153.9,181.7 154.7,181.7 154.7,181.8 155.5,181.8 155.5,181.7 156.3,181.7 156.3,182.0 157.1,182.0 157.1,181.7 157.9,181.7 157.9,183.2 158.7,183.2 158.7,182.6 159.5,182.6 159.5,181.4 160.3,181.4 160.3,181.9 161.1,181.9 161.1,181.7 161.9,181.7 161.9,181.6 162.7,181.6 162.7,182.6 163.5,182.6 163.5,182.1 164.3,182.1 164.3,181.7 165.1,181.7 165.1,181.7 165.9,181.7 165.9,182.2 166.7,182.2 166.7,182.0 167.5,182.0 167.5,182.8 168.3,182.8 168.3,188.0 169.1,188.0 169.1,187.6 169.9,187.6 169.9,181.2 170.7,181.2 170.7,181.7 171.5,181.7 171.5,181.8 172.3,181.8 172.3,181.6 173.1,181.6 173.1,181.9 173.9,181.9 173.9,181.3 174.7,181.3 174.7,181.5 175.4,181.5 175.4,181.1 176.2,181.1 176.2,181.0 177.0,181.0 177.0,181.4 177.8,181.4 177.8,181.5 178.6,181.5 178.6,181.4 179.4,181.4 179.4,181.4 180.2,181.4 180.2,181.0 181.0,181.0 181.0,180.4 181.8,180.4 181.8,182.1 182.6,182.1 182.6,181.7 183.4,181.7 183.4,181.6 184.2,181.6 184.2,181.4 185.0,181.4 185.0,180.9 185.8,180.9 185.8,181.3 186.6,181.3 186.6,181.5 187.4,181.5 187.4,181.7 188.2,181.7 188.2,182.0 189.0,182.0 189.0,180.4 189.8,180.4 189.8,182.3 190.6,182.3 190.6,182.2 191.4,182.2 191.4,180.9 192.2,180.9 192.2,181.6 193.0,181.6 193.0,180.8 193.8,180.8 193.8,182.2 194.6,182.2 194.6,181.9 195.4,181.9 195.4,180.9 196.2,180.9 196.2,181.6 197.0,181.6 197.0,181.6 197.8,181.6 197.8,180.6 198.6,180.6 198.6,181.8 199.3,181.8 199.3,179.8 200.1,179.8 200.1,180.7 200.9,180.7 200.9,180.4 201.7,180.4 201.7,181.0 202.5,181.0 202.5,181.1 203.3,181.1 203.3,180.8 204.1,180.8 204.1,180.9 204.9,180.9 204.9,180.4 205.7,180.4 205.7,180.1 206.5,180.1 206.5,181.6 207.3,181.6 207.3,180.8 208.1,180.8 208.1,180.5 208.9,180.5 208.9,180.3 209.7,180.3 209.7,180.0 210.5,180.0 210.5,180.9 211.3,180.9 211.3,180.8 212.1,180.8 212.1,180.9 212.9,180.9 212.9,181.5Line truncated
<circle class="nj-charts-json-dot" cx="87.8" cy="201.0" r="3.5"><title>#5234: 1.11&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="87.8" y1="54.0" x2="87.8" y2="196.0"/>
<circle class="nj-theme-dot" cx="87.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="87.8" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="128.4" cy="181.8" r="3.5"><title>#5283: 1.47&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="128.4" y1="54.0" x2="128.4" y2="176.8"/>
<circle class="nj-theme-dot" cx="128.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="128.4" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="169.9" cy="181.2" r="3.5"><title>#5617: 1.48&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="169.9" y1="54.0" x2="169.9" y2="176.2"/>
<circle class="nj-theme-dot" cx="169.9" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="169.9" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="241.6" cy="162.6" r="3.5"><title>#5738: 1.95&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="241.6" y1="54.0" x2="241.6" y2="157.6"/>
<circle class="nj-theme-dot" cx="241.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="241.6" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="267.1" cy="154.3" r="3.5"><title>#5851: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="267.1" y1="54.0" x2="267.1" y2="149.3"/>
<circle class="nj-theme-dot" cx="267.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="267.1" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="280.6" cy="137.5" r="3.5"><title>#5882: 2.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="280.6" y1="36.0" x2="280.6" y2="132.5"/>
<circle class="nj-theme-dot" cx="280.6" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="280.6" y="32.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="330.0" cy="126.8" r="3.5"><title>#6031: 3.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="330.0" y1="54.0" x2="330.0" y2="121.8"/>
<circle class="nj-theme-dot" cx="322.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="322.5" y="50.0" text-anchor="middle">1</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1,51 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_citm nj-blog-tl-parse_citm-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_citm">parse() citm_catalog.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_citm-d">parse() citm_catalog.json: speedup over 3.12.0 at each of 360 commits, ending at 3.8x. Labeled steps, by theme: 4, 1, 4, 4, 2, 4, 1.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() citm_catalog.json</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="160.667" x2="330" y2="160.667"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="164.667">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="113.333" x2="330" y2="113.333"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="117.333">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">8&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.2 45.6,208.2 45.6,207.8 46.4,207.8 46.4,207.5 47.2,207.5 47.2,206.5 48.0,206.5 48.0,208.3 48.8,208.3 48.8,207.3 49.6,207.3 49.6,206.8 50.4,206.8 50.4,207.8 51.2,207.8 51.2,206.8 52.0,206.8 52.0,207.3 52.8,207.3 52.8,207.6 53.6,207.6 53.6,207.8 54.4,207.8 54.4,207.0 55.2,207.0 55.2,207.3 55.9,207.3 55.9,207.2 56.7,207.2 56.7,207.4 57.5,207.4 57.5,207.5 58.3,207.5 58.3,207.4 59.1,207.4 59.1,206.6 59.9,206.6 59.9,207.6 60.7,207.6 60.7,207.6 61.5,207.6 61.5,207.2 62.3,207.2 62.3,207.0 63.1,207.0 63.1,207.6 63.9,207.6 63.9,206.7 64.7,206.7 64.7,207.4 65.5,207.4 65.5,206.8 66.3,206.8 66.3,207.3 67.1,207.3 67.1,207.7 67.9,207.7 67.9,207.9 68.7,207.9 68.7,207.2 69.5,207.2 69.5,206.4 70.3,206.4 70.3,207.6 71.1,207.6 71.1,206.4 71.9,206.4 71.9,208.0 72.7,208.0 72.7,207.4 73.5,207.4 73.5,206.5 74.3,206.5 74.3,207.5 75.1,207.5 75.1,207.2 75.9,207.2 75.9,206.9 76.7,206.9 76.7,207.6 77.5,207.6 77.5,207.6 78.3,207.6 78.3,207.0 79.1,207.0 79.1,206.9 79.8,206.9 79.8,208.0 80.6,208.0 80.6,207.6 81.4,207.6 81.4,206.6 82.2,206.6 82.2,206.8 83.0,206.8 83.0,207.3 83.8,207.3 83.8,206.9 84.6,206.9 84.6,207.6 85.4,207.6 85.4,207.1 86.2,207.1 86.2,207.6 87.0,207.6 87.0,207.9 87.8,207.9 87.8,178.2 88.6,178.2 88.6,177.5 89.4,177.5 89.4,177.7 90.2,177.7 90.2,177.6 91.0,177.6 91.0,177.7 91.8,177.7 91.8,177.1 92.6,177.1 92.6,176.8 93.4,176.8 93.4,177.7 94.2,177.7 94.2,177.6 95.0,177.6 95.0,176.8 95.8,176.8 95.8,177.8 96.6,177.8 96.6,177.0 97.4,177.0 97.4,176.8 98.2,176.8 98.2,178.0 99.0,178.0 99.0,178.1 99.8,178.1 99.8,177.6 100.6,177.6 100.6,177.6 101.4,177.6 101.4,177.4 102.2,177.4 102.2,177.6 103.0,177.6 103.0,177.8 103.7,177.8 103.7,177.5 104.5,177.5 104.5,177.9 105.3,177.9 105.3,177.7 106.1,177.7 106.1,175.9 106.9,175.9 106.9,177.5 107.7,177.5 107.7,177.6 108.5,177.6 108.5,177.6 109.3,177.6 109.3,176.9 110.1,176.9 110.1,177.5 110.9,177.5 110.9,177.4 111.7,177.4 111.7,177.4 112.5,177.4 112.5,176.9 113.3,176.9 113.3,177.9 114.1,177.9 114.1,177.3 114.9,177.3 114.9,176.6 115.7,176.6 115.7,177.4 116.5,177.4 116.5,177.5 117.3,177.5 117.3,177.5 118.1,177.5 118.1,177.4 118.9,177.4 118.9,177.0 119.7,177.0 119.7,177.7 120.5,177.7 120.5,176.2 121.3,176.2 121.3,176.9 122.1,176.9 122.1,177.5 122.9,177.5 122.9,177.8 123.7,177.8 123.7,177.8 124.5,177.8 124.5,177.9 125.3,177.9 125.3,177.3 126.1,177.3 126.1,177.5 126.9,177.5 126.9,177.4 127.6,177.4 127.6,177.1 128.4,177.1 128.4,162.5 129.2,162.5 129.2,162.2 130.0,162.2 130.0,161.8 130.8,161.8 130.8,162.2 131.6,162.2 131.6,161.2 132.4,161.2 132.4,160.7 133.2,160.7 133.2,159.4 134.0,159.4 134.0,160.3 134.8,160.3 134.8,160.4 135.6,160.4 135.6,160.6 136.4,160.6 136.4,159.5 137.2,159.5 137.2,160.4 138.0,160.4 138.0,159.6 138.8,159.6 138.8,160.0 139.6,160.0 139.6,159.9 140.4,159.9 140.4,160.2 141.2,160.2 141.2,159.6 142.0,159.6 142.0,160.8 142.8,160.8 142.8,160.1 143.6,160.1 143.6,159.1 144.4,159.1 144.4,159.7 145.2,159.7 145.2,159.9 146.0,159.9 146.0,160.5 146.8,160.5 146.8,160.2 147.6,160.2 147.6,159.9 148.4,159.9 148.4,160.5 149.2,160.5 149.2,160.5 150.0,160.5 150.0,160.6 150.8,160.6 150.8,159.7 151.5,159.7 151.5,159.5 152.3,159.5 152.3,160.0 153.1,160.0 153.1,160.2 153.9,160.2 153.9,160.0 154.7,160.0 154.7,160.6 155.5,160.6 155.5,159.9 156.3,159.9 156.3,160.2 157.1,160.2 157.1,160.1 157.9,160.1 157.9,160.8 158.7,160.8 158.7,159.2 159.5,159.2 159.5,159.6 160.3,159.6 160.3,159.2 161.1,159.2 161.1,160.0 161.9,160.0 161.9,159.4 162.7,159.4 162.7,159.6 163.5,159.6 163.5,159.5 164.3,159.5 164.3,160.1 165.1,160.1 165.1,159.0 165.9,159.0 165.9,159.4 166.7,159.4 166.7,160.2 167.5,160.2 167.5,161.4 168.3,161.4 168.3,161.7 169.1,161.7 169.1,161.6 169.9,161.6 169.9,160.3 170.7,160.3 170.7,161.1 171.5,161.1 171.5,161.2 172.3,161.2 172.3,161.7 173.1,161.7 173.1,161.2 173.9,161.2 173.9,160.4 174.7,160.4 174.7,161.6 175.4,161.6 175.4,160.6 176.2,160.6 176.2,161.4 177.0,161.4 177.0,161.3 177.8,161.3 177.8,161.3 178.6,161.3 178.6,161.7 179.4,161.7 179.4,161.2 180.2,161.2 180.2,160.1 181.0,160.1 181.0,160.9 181.8,160.9 181.8,161.5 182.6,161.5 182.6,160.6 183.4,160.6 183.4,161.9 184.2,161.9 184.2,161.4 185.0,161.4 185.0,160.1 185.8,160.1 185.8,160.6 186.6,160.6 186.6,162.0 187.4,162.0 187.4,161.5 188.2,161.5 188.2,162.0 189.0,162.0 189.0,161.3 189.8,161.3 189.8,162.3 190.6,162.3 190.6,162.1 191.4,162.1 191.4,160.8 192.2,160.8 192.2,161.5 193.0,161.5 193.0,161.4 193.8,161.4 193.8,162.2 194.6,162.2 194.6,161.4 195.4,161.4 195.4,161.4 196.2,161.4 196.2,161.8 197.0,161.8 197.0,160.7 197.8,160.7 197.8,160.5 198.6,160.5 198.6,160.5 199.3,160.5 199.3,159.3 200.1,159.3 200.1,159.4 200.9,159.4 200.9,160.4 201.7,160.4 201.7,160.1 202.5,160.1 202.5,160.4 203.3,160.4 203.3,160.4 204.1,160.4 204.1,160.8 204.9,160.8 204.9,159.8 205.7,159.8 205.7,159.4 206.5,159.4 206.5,160.5 207.3,160.5 207.3,160.1 208.1,160.1 208.1,160.7 208.9,160.7 208.9,160.6 209.7,160.6 209.7,159.5 210.5,159.5 210.5,161.1 211.3,161.1 211.3,161.3 212.1,161.3 212.1,161.0 212.9,161.0 212.9,160.8Line truncated
<circle class="nj-charts-json-dot" cx="87.8" cy="178.2" r="3.5"><title>#5234: 1.55&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="87.8" y1="54.0" x2="87.8" y2="173.2"/>
<circle class="nj-theme-dot" cx="87.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="87.8" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="128.4" cy="162.5" r="3.5"><title>#5283: 1.95&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="128.4" y1="54.0" x2="128.4" y2="157.5"/>
<circle class="nj-theme-dot" cx="128.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="128.4" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="219.3" cy="155.4" r="3.5"><title>#5592: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="219.3" y1="54.0" x2="219.3" y2="150.4"/>
<circle class="nj-theme-dot" cx="219.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="219.3" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="239.2" cy="147.1" r="3.5"><title>#5809: 2.4&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="240.0" cy="138.2" r="3.5"><title>#5810: 2.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="240.0" y1="36.0" x2="240.0" y2="133.2"/>
<circle class="nj-theme-dot" cx="231.0" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="231.0" y="32.0" text-anchor="middle">4</text>
<circle class="nj-theme-dot" cx="249.0" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="249.0" y="32.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="280.6" cy="125.7" r="3.5"><title>#5882: 3.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="280.6" y1="54.0" x2="280.6" y2="120.7"/>
<circle class="nj-theme-dot" cx="280.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="280.6" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="330.0" cy="116.6" r="3.5"><title>#6031: 3.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="330.0" y1="54.0" x2="330.0" y2="111.6"/>
<circle class="nj-theme-dot" cx="322.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="322.5" y="50.0" text-anchor="middle">1</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1,30 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_twitter_ifstream nj-blog-tl-parse_twitter_ifstream-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_twitter_ifstream">parse() twitter.json, std::ifstream: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_twitter_ifstream-d">parse() twitter.json, std::ifstream: speedup over 3.12.0 at each of 360 commits, ending at 2.2x. Labeled steps, by theme: 1, 1.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() twitter.json, std::ifstream</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="137" x2="330" y2="137"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="141">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">4&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,209.3 45.6,209.3 45.6,206.6 46.4,206.6 46.4,208.3 47.2,208.3 47.2,205.9 48.0,205.9 48.0,209.3 48.8,209.3 48.8,208.3 49.6,208.3 49.6,207.9 50.4,207.9 50.4,209.4 51.2,209.4 51.2,205.8 52.0,205.8 52.0,206.7 52.8,206.7 52.8,209.2 53.6,209.2 53.6,208.1 54.4,208.1 54.4,206.9 55.2,206.9 55.2,207.5 55.9,207.5 55.9,207.5 56.7,207.5 56.7,207.6 57.5,207.6 57.5,206.9 58.3,206.9 58.3,206.9 59.1,206.9 59.1,208.4 59.9,208.4 59.9,208.6 60.7,208.6 60.7,209.1 61.5,209.1 61.5,207.7 62.3,207.7 62.3,207.0 63.1,207.0 63.1,206.7 63.9,206.7 63.9,206.1 64.7,206.1 64.7,207.5 65.5,207.5 65.5,206.4 66.3,206.4 66.3,206.7 67.1,206.7 67.1,206.8 67.9,206.8 67.9,209.3 68.7,209.3 68.7,206.7 69.5,206.7 69.5,206.8 70.3,206.8 70.3,206.6 71.1,206.6 71.1,206.8 71.9,206.8 71.9,209.2 72.7,209.2 72.7,207.6 73.5,207.6 73.5,205.9 74.3,205.9 74.3,209.1 75.1,209.1 75.1,206.6 75.9,206.6 75.9,207.4 76.7,207.4 76.7,207.0 77.5,207.0 77.5,209.1 78.3,209.1 78.3,205.8 79.1,205.8 79.1,206.9 79.8,206.9 79.8,208.0 80.6,208.0 80.6,208.5 81.4,208.5 81.4,206.6 82.2,206.6 82.2,206.0 83.0,206.0 83.0,207.9 83.8,207.9 83.8,206.6 84.6,206.6 84.6,206.5 85.4,206.5 85.4,206.6 86.2,206.6 86.2,207.2 87.0,207.2 87.0,208.0 87.8,208.0 87.8,208.1 88.6,208.1 88.6,206.7 89.4,206.7 89.4,207.8 90.2,207.8 90.2,206.7 91.0,206.7 91.0,208.1 91.8,208.1 91.8,205.9 92.6,205.9 92.6,206.8 93.4,206.8 93.4,208.0 94.2,208.0 94.2,207.3 95.0,207.3 95.0,206.7 95.8,206.7 95.8,209.3 96.6,209.3 96.6,206.5 97.4,206.5 97.4,207.2 98.2,207.2 98.2,208.2 99.0,208.2 99.0,209.3 99.8,209.3 99.8,207.8 100.6,207.8 100.6,206.9 101.4,206.9 101.4,206.7 102.2,206.7 102.2,209.0 103.0,209.0 103.0,208.0 103.7,208.0 103.7,208.1 104.5,208.1 104.5,209.1 105.3,209.1 105.3,208.1 106.1,208.1 106.1,205.6 106.9,205.6 106.9,207.0 107.7,207.0 107.7,206.7 108.5,206.7 108.5,207.9 109.3,207.9 109.3,206.7 110.1,206.7 110.1,206.9 110.9,206.9 110.9,206.8 111.7,206.8 111.7,206.4 112.5,206.4 112.5,207.1 113.3,207.1 113.3,208.6 114.1,208.6 114.1,208.7 114.9,208.7 114.9,206.6 115.7,206.6 115.7,209.3 116.5,209.3 116.5,208.0 117.3,208.0 117.3,206.7 118.1,206.7 118.1,207.7 118.9,207.7 118.9,206.9 119.7,206.9 119.7,208.8 120.5,208.8 120.5,208.7 121.3,208.7 121.3,207.7 122.1,207.7 122.1,208.8 122.9,208.8 122.9,207.8 123.7,207.8 123.7,210.3 124.5,210.3 124.5,208.9 125.3,208.9 125.3,208.9 126.1,208.9 126.1,209.0 126.9,209.0 126.9,208.0 127.6,208.0 127.6,207.7 128.4,207.7 128.4,208.3 129.2,208.3 129.2,207.0 130.0,207.0 130.0,207.2 130.8,207.2 130.8,207.5 131.6,207.5 131.6,208.0 132.4,208.0 132.4,207.6 133.2,207.6 133.2,207.9 134.0,207.9 134.0,207.6 134.8,207.6 134.8,208.5 135.6,208.5 135.6,209.2 136.4,209.2 136.4,206.3 137.2,206.3 137.2,208.7 138.0,208.7 138.0,207.6 138.8,207.6 138.8,207.4 139.6,207.4 139.6,207.5 140.4,207.5 140.4,209.0 141.2,209.0 141.2,206.9 142.0,206.9 142.0,209.3 142.8,209.3 142.8,209.9 143.6,209.9 143.6,207.0 144.4,207.0 144.4,207.3 145.2,207.3 145.2,208.1 146.0,208.1 146.0,209.8 146.8,209.8 146.8,208.1 147.6,208.1 147.6,208.1 148.4,208.1 148.4,208.5 149.2,208.5 149.2,208.2 150.0,208.2 150.0,210.4 150.8,210.4 150.8,207.7 151.5,207.7 151.5,207.2 152.3,207.2 152.3,206.7 153.1,206.7 153.1,209.9 153.9,209.9 153.9,206.6 154.7,206.6 154.7,209.9 155.5,209.9 155.5,208.8 156.3,208.8 156.3,208.8 157.1,208.8 157.1,209.5 157.9,209.5 157.9,208.9 158.7,208.9 158.7,206.4 159.5,206.4 159.5,207.2 160.3,207.2 160.3,207.0 161.1,207.0 161.1,207.2 161.9,207.2 161.9,206.6 162.7,206.6 162.7,207.2 163.5,207.2 163.5,208.0 164.3,208.0 164.3,207.6 165.1,207.6 165.1,207.9 165.9,207.9 165.9,207.5 166.7,207.5 166.7,205.6 167.5,205.6 167.5,208.0 168.3,208.0 168.3,209.7 169.1,209.7 169.1,207.9 169.9,207.9 169.9,207.6 170.7,207.6 170.7,208.5 171.5,208.5 171.5,207.9 172.3,207.9 172.3,210.4 173.1,210.4 173.1,206.7 173.9,206.7 173.9,207.7 174.7,207.7 174.7,209.2 175.4,209.2 175.4,206.8 176.2,206.8 176.2,209.3 177.0,209.3 177.0,208.0 177.8,208.0 177.8,208.0 178.6,208.0 178.6,207.9 179.4,207.9 179.4,208.2 180.2,208.2 180.2,207.9 181.0,207.9 181.0,207.0 181.8,207.0 181.8,208.8 182.6,208.8 182.6,208.0 183.4,208.0 183.4,208.0 184.2,208.0 184.2,209.2 185.0,209.2 185.0,206.7 185.8,206.7 185.8,206.7 186.6,206.7 186.6,208.5 187.4,208.5 187.4,208.9 188.2,208.9 188.2,210.1 189.0,210.1 189.0,206.4 189.8,206.4 189.8,209.4 190.6,209.4 190.6,210.1 191.4,210.1 191.4,207.6 192.2,207.6 192.2,209.5 193.0,209.5 193.0,208.7 193.8,208.7 193.8,211.1 194.6,211.1 194.6,210.1 195.4,210.1 195.4,211.7 196.2,211.7 196.2,208.8 197.0,208.8 197.0,209.2 197.8,209.2 197.8,207.7 198.6,207.7 198.6,208.1 199.3,208.1 199.3,206.4 200.1,206.4 200.1,206.7 200.9,206.7 200.9,207.3 201.7,207.3 201.7,207.8 202.5,207.8 202.5,208.7 203.3,208.7 203.3,210.1 204.1,210.1 204.1,210.0 204.9,210.0 204.9,206.9 205.7,206.9 205.7,209.0 206.5,209.0 206.5,208.7 207.3,208.7 207.3,209.1 208.1,209.1 208.1,208.6 208.9,208.6 208.9,208.9 209.7,208.9 209.7,207.3 210.5,207.3 210.5,208.9 211.3,208.9 211.3,209.2 212.1,209.2 212.1,207.3 212.9,207.3 212.9,210.5Line truncated
<circle class="nj-charts-json-dot" cx="258.3" cy="138.8" r="3.5"><title>#5828: 1.97&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="258.3" y1="54.0" x2="258.3" y2="133.8"/>
<circle class="nj-theme-dot" cx="258.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="258.3" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="275.0" cy="127.0" r="3.5"><title>#5884: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="275.0" y1="36.0" x2="275.0" y2="122.0"/>
<circle class="nj-theme-dot" cx="275.0" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="275.0" y="32.0" text-anchor="middle">1</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,36 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-to_cbor_twitter nj-blog-tl-to_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-to_cbor_twitter">to_cbor() twitter: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-to_cbor_twitter-d">to_cbor() twitter: speedup over 3.12.0 at each of 360 commits, ending at 5.1x. Labeled steps, by theme: 4, 6, 6.</desc>
<text class="nj-charts-panel" x="8" y="18">to_cbor() twitter</text>
<line class="nj-charts-grid" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="212">1&#215;</text>
<line class="nj-charts-grid" x1="44" y1="160.667" x2="330" y2="160.667"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="164.667">2&#215;</text>
<line class="nj-charts-grid" x1="44" y1="113.333" x2="330" y2="113.333"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="117.333">4&#215;</text>
<line class="nj-charts-grid" x1="44" y1="66" x2="330" y2="66"/>
<text class="nj-charts-tick nj-charts-tick--r" x="38" y="70">8&#215;</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="44" y2="212"/>
<text class="nj-charts-tick" x="44" y="225">3.12.0</text>
<line class="nj-charts-axis" x1="116.496" y1="208" x2="116.496" y2="212"/>
<text class="nj-charts-tick" x="116.496" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="195.365" y1="208" x2="195.365" y2="212"/>
<text class="nj-charts-tick" x="195.365" y="225">Oct</text>
<line class="nj-charts-axis" x1="302.117" y1="208" x2="302.117" y2="212"/>
<text class="nj-charts-tick" x="302.117" y="225">Nov</text>
<polyline class="nj-charts-json" points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,204.9 46.4,204.9 46.4,205.2 47.2,205.2 47.2,204.7 48.0,204.7 48.0,205.2 48.8,205.2 48.8,205.0 49.6,205.0 49.6,204.9 50.4,204.9 50.4,205.0 51.2,205.0 51.2,205.0 52.0,205.0 52.0,205.1 52.8,205.1 52.8,205.4 53.6,205.4 53.6,205.0 54.4,205.0 54.4,205.2 55.2,205.2 55.2,211.6 55.9,211.6 55.9,206.8 56.7,206.8 56.7,204.2 57.5,204.2 57.5,207.6 58.3,207.6 58.3,204.1 59.1,204.1 59.1,203.8 59.9,203.8 59.9,204.2 60.7,204.2 60.7,205.1 61.5,205.1 61.5,204.4 62.3,204.4 62.3,204.3 63.1,204.3 63.1,204.0 63.9,204.0 63.9,202.7 64.7,202.7 64.7,204.2 65.5,204.2 65.5,204.2 66.3,204.2 66.3,204.2 67.1,204.2 67.1,204.4 67.9,204.4 67.9,206.2 68.7,206.2 68.7,204.3 69.5,204.3 69.5,204.1 70.3,204.1 70.3,204.3 71.1,204.3 71.1,204.3 71.9,204.3 71.9,204.3 72.7,204.3 72.7,204.3 73.5,204.3 73.5,204.4 74.3,204.4 74.3,204.8 75.1,204.8 75.1,208.4 75.9,208.4 75.9,203.5 76.7,203.5 76.7,206.2 77.5,206.2 77.5,204.4 78.3,204.4 78.3,203.2 79.1,203.2 79.1,204.1 79.8,204.1 79.8,204.2 80.6,204.2 80.6,203.7 81.4,203.7 81.4,204.2 82.2,204.2 82.2,203.2 83.0,203.2 83.0,204.2 83.8,204.2 83.8,204.4 84.6,204.4 84.6,203.8 85.4,203.8 85.4,204.4 86.2,204.4 86.2,204.7 87.0,204.7 87.0,204.6 87.8,204.6 87.8,208.7 88.6,208.7 88.6,205.2 89.4,205.2 89.4,205.5 90.2,205.5 90.2,205.2 91.0,205.2 91.0,205.3 91.8,205.3 91.8,206.8 92.6,206.8 92.6,204.6 93.4,204.6 93.4,205.5 94.2,205.5 94.2,205.1 95.0,205.1 95.0,204.7 95.8,204.7 95.8,205.7 96.6,205.7 96.6,205.0 97.4,205.0 97.4,204.9 98.2,204.9 98.2,206.5 99.0,206.5 99.0,205.6 99.8,205.6 99.8,205.0 100.6,205.0 100.6,209.2 101.4,209.2 101.4,205.9 102.2,205.9 102.2,206.5 103.0,206.5 103.0,205.5 103.7,205.5 103.7,205.3 104.5,205.3 104.5,205.3 105.3,205.3 105.3,205.1 106.1,205.1 106.1,204.4 106.9,204.4 106.9,204.6 107.7,204.6 107.7,204.8 108.5,204.8 108.5,204.2 109.3,204.2 109.3,203.8 110.1,203.8 110.1,204.4 110.9,204.4 110.9,202.8 111.7,202.8 111.7,203.5 112.5,203.5 112.5,204.0 113.3,204.0 113.3,204.3 114.1,204.3 114.1,202.9 114.9,202.9 114.9,203.3 115.7,203.3 115.7,204.4 116.5,204.4 116.5,204.5 117.3,204.5 117.3,204.1 118.1,204.1 118.1,208.3 118.9,208.3 118.9,203.8 119.7,203.8 119.7,207.0 120.5,207.0 120.5,205.9 121.3,205.9 121.3,205.4 122.1,205.4 122.1,205.3 122.9,205.3 122.9,205.8 123.7,205.8 123.7,205.4 124.5,205.4 124.5,205.6 125.3,205.6 125.3,206.3 126.1,206.3 126.1,205.5 126.9,205.5 126.9,204.8 127.6,204.8 127.6,204.6 128.4,204.6 128.4,206.1 129.2,206.1 129.2,204.6 130.0,204.6 130.0,204.1 130.8,204.1 130.8,204.3 131.6,204.3 131.6,205.6 132.4,205.6 132.4,203.9 133.2,203.9 133.2,204.0 134.0,204.0 134.0,203.9 134.8,203.9 134.8,204.6 135.6,204.6 135.6,204.1 136.4,204.1 136.4,203.9 137.2,203.9 137.2,204.8 138.0,204.8 138.0,203.2 138.8,203.2 138.8,203.3 139.6,203.3 139.6,204.7 140.4,204.7 140.4,208.3 141.2,208.3 141.2,204.3 142.0,204.3 142.0,207.4 142.8,207.4 142.8,204.4 143.6,204.4 143.6,208.2 144.4,208.2 144.4,205.0 145.2,205.0 145.2,204.9 146.0,204.9 146.0,208.8 146.8,208.8 146.8,207.9 147.6,207.9 147.6,206.2 148.4,206.2 148.4,204.2 149.2,204.2 149.2,204.1 150.0,204.1 150.0,204.2 150.8,204.2 150.8,202.2 151.5,202.2 151.5,205.6 152.3,205.6 152.3,203.0 153.1,203.0 153.1,203.4 153.9,203.4 153.9,202.7 154.7,202.7 154.7,203.6 155.5,203.6 155.5,203.3 156.3,203.3 156.3,203.2 157.1,203.2 157.1,204.9 157.9,204.9 157.9,202.9 158.7,202.9 158.7,202.2 159.5,202.2 159.5,202.5 160.3,202.5 160.3,202.9 161.1,202.9 161.1,202.9 161.9,202.9 161.9,202.3 162.7,202.3 162.7,202.9 163.5,202.9 163.5,203.7 164.3,203.7 164.3,204.1 165.1,204.1 165.1,203.9 165.9,203.9 165.9,203.7 166.7,203.7 166.7,203.3 167.5,203.3 167.5,203.8 168.3,203.8 168.3,205.0 169.1,205.0 169.1,208.0 169.9,208.0 169.9,205.1 170.7,205.1 170.7,206.5 171.5,206.5 171.5,205.4 172.3,205.4 172.3,205.4 173.1,205.4 173.1,207.0 173.9,207.0 173.9,204.9 174.7,204.9 174.7,205.4 175.4,205.4 175.4,203.6 176.2,203.6 176.2,205.7 177.0,205.7 177.0,204.5 177.8,204.5 177.8,205.0 178.6,205.0 178.6,205.2 179.4,205.2 179.4,204.9 180.2,204.9 180.2,204.5 181.0,204.5 181.0,204.9 181.8,204.9 181.8,205.3 182.6,205.3 182.6,203.9 183.4,203.9 183.4,204.8 184.2,204.8 184.2,204.8 185.0,204.8 185.0,203.6 185.8,203.6 185.8,203.4 186.6,203.4 186.6,203.8 187.4,203.8 187.4,205.1 188.2,205.1 188.2,205.5 189.0,205.5 189.0,204.0 189.8,204.0 189.8,204.9 190.6,204.9 190.6,205.0 191.4,205.0 191.4,206.4 192.2,206.4 192.2,205.1 193.0,205.1 193.0,204.5 193.8,204.5 193.8,204.8 194.6,204.8 194.6,205.2 195.4,205.2 195.4,205.0 196.2,205.0 196.2,204.6 197.0,204.6 197.0,203.9 197.8,203.9 197.8,203.5 198.6,203.5 198.6,203.6 199.3,203.6 199.3,204.2 200.1,204.2 200.1,205.9 200.9,205.9 200.9,205.2 201.7,205.2 201.7,204.8 202.5,204.8 202.5,207.3 203.3,207.3 203.3,205.2 204.1,205.2 204.1,208.6 204.9,208.6 204.9,204.3 205.7,204.3 205.7,203.9 206.5,203.9 206.5,203.2 207.3,203.2 207.3,203.9 208.1,203.9 208.1,205.9 208.9,205.9 208.9,204.8 209.7,204.8 209.7,204.7 210.5,204.7 210.5,203.6 211.3,203.6 211.3,203.7 212.1,203.7 212.1,208.2 212.9,208.2 212.9,208.4Line truncated
<circle class="nj-charts-json-dot" cx="231.2" cy="153.7" r="3.5"><title>#5328: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="231.2" y1="54.0" x2="231.2" y2="148.7"/>
<circle class="nj-theme-dot" cx="231.2" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="231.2" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="265.5" cy="123.4" r="3.5"><title>#5824: 3.5&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="265.5" y1="54.0" x2="265.5" y2="118.4"/>
<circle class="nj-theme-dot" cx="265.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="265.5" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="277.4" cy="96.9" r="3.5"><title>#5885: 5.1&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="277.4" y1="36.0" x2="277.4" y2="91.9"/>
<circle class="nj-theme-dot" cx="277.4" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="277.4" y="32.0" text-anchor="middle">6</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,379 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewBox="0 0 784 510" role="img" aria-labelledby="nj-blog-uc-mac nj-blog-uc-mac-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-uc-mac">Use cases: time of each library relative to the fastest, Apple M1 Max</title>
<desc id="nj-blog-uc-mac-d">Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.00; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.85 doing less, N); nlohmann/json json_document minify: 1.00 (0.84 doing less, N); nlohmann/json json_document write: 1.00 (0.69 doing less, N); yyjson validate: 1.41; yyjson sum: 1.14; yyjson select: 1.30; yyjson edit: 1.48; yyjson minify: 1.26 (1.18 doing less, N); yyjson write: 1.23; simdjson validate: 1.52; simdjson sum: 1.21; simdjson select: 1.34 (0.76 doing less, P); simdjson edit: n/a; simdjson minify: 1.73 (0.18 doing less, P); simdjson write: 2.41; sonic-rs (Rust) validate: 1.91; sonic-rs (Rust) sum: 1.54; sonic-rs (Rust) select: 1.85; sonic-rs (Rust) edit: 2.10; sonic-rs (Rust) minify: 1.93; sonic-rs (Rust) write: 2.34; sonic-cpp validate: no fully validating way (2.50 doing less, U); sonic-cpp sum: no fully validating way (1.86 doing less, U); sonic-cpp select: no fully validating way (2.34 doing less, U); sonic-cpp edit: no fully validating way (1.70 doing less, U); sonic-cpp minify: no fully validating way (2.03 doing less, U); sonic-cpp write: 1.61; simd-json (Rust) validate: 2.05; simd-json (Rust) sum: 1.63; simd-json (Rust) select: 2.39; simd-json (Rust) edit: 2.85; simd-json (Rust) minify: 3.40; simd-json (Rust) write: 3.05; nlohmann/json json validate: 1.38; nlohmann/json json sum: 1.34; nlohmann/json json select: 6.09; nlohmann/json json edit: 3.22; nlohmann/json json minify: 4.39; nlohmann/json json write: 2.03; Glaze validate: 2.03; Glaze sum: 3.88; Glaze select: 1.81 (0.81 doing less, P); Glaze edit: 4.44; Glaze minify: 5.23 (1.05 doing less, P); Glaze write: 2.19; Boost.J&#8203;SON validate: 2.54; Boost.J&#8203;SON sum: 2.02; Boost.J&#8203;SON select: 3.31; Boost.J&#8203;SON edit: 3.23; Boost.J&#8203;SON minify: 3.89; Boost.J&#8203;SON write: 3.67; serde_json (Rust) validate: 2.44 (2.21 doing less, U); serde_json (Rust) sum: 2.60; serde_json (Rust) select: 2.41 (2.26 doing less, U); serde_json (Rust) edit: 5.02; serde_json (Rust) minify: 5.85; serde_json (Rust) write: 2.90; RapidJSON validate: 4.67 (3.09 doing less, U); RapidJSON sum: 4.18 (2.89 doing less, U); RapidJSON select: 6.02 (3.93 doing less, U); RapidJSON edit: 4.85 (3.83 doing less, U); RapidJSON minify: 4.85 (3.66 doing less, U N); RapidJSON write: 5.74.</desc>
<text class="nj-charts-tick" x="270" y="34">validate</text>
<text class="nj-charts-tick" x="362" y="34">sum</text>
<text class="nj-charts-tick" x="454" y="34">select</text>
<text class="nj-charts-tick" x="546" y="34">edit</text>
<text class="nj-charts-tick" x="638" y="34">minify</text>
<text class="nj-charts-tick" x="730" y="34">write</text>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="66" text-anchor="end">nlohmann/json json_document</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · validate&#10;1.00× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 172 µs&#10;citm_catalog.json: 313 µs&#10;canada.json: 905 µs&#10;jeopardy.json: 20,926 µs">
<rect class="nj-heat-0" x="225" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · sum&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 219 µs&#10;citm_catalog.json: 493 µs&#10;canada.json: 1,803 µs&#10;jeopardy.json: 28,898 µs">
<rect class="nj-heat-0" x="317" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · select&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 183 µs&#10;citm_catalog.json: 363 µs&#10;canada.json: 944 µs&#10;jeopardy.json: 24,801 µs">
<rect class="nj-heat-0" x="409" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit&#10;1.00× the time of the fastest library (fully validating)&#10;way: editable&#10;twitter.json: 288 µs&#10;citm_catalog.json: 559 µs&#10;canada.json: 2,737 µs&#10;jeopardy.json: 58,019 µs">
<rect class="nj-heat-0" x="501" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit, checking less&#10;0.85× the time of the fastest fully validating library&#10;way: editable (source numbers)&#10;twitter.json: 281 µs (validates fully)&#10;citm_catalog.json: 557 µs (validates fully)&#10;canada.json: 1,504 µs (validates fully)&#10;jeopardy.json: 57,885 µs (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="547" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="60" text-anchor="middle">0.85</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 261 µs&#10;citm_catalog.json: 496 µs&#10;canada.json: 2,570 µs&#10;jeopardy.json: 37,624 µs">
<rect class="nj-heat-0" x="593" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify, checking less&#10;0.84× the time of the fastest fully validating library&#10;twitter.json: 252 µs · parse + dump (source numbers) (validates fully)&#10;citm_catalog.json: 494 µs · parse + dump (source numbers) (validates fully)&#10;canada.json: 1,343 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 37,624 µs · parse + dump (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.84</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write&#10;1.00× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 76.2 µs&#10;citm_catalog.json: 139 µs&#10;canada.json: 1,625 µs&#10;jeopardy.json: 14,861 µs">
<rect class="nj-heat-0" x="685" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="707.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write, checking less&#10;0.69× the time of the fastest fully validating library&#10;way: dump (source numbers)&#10;twitter.json: 72.8 µs (validates fully)&#10;citm_catalog.json: 136 µs (validates fully)&#10;canada.json: 398 µs (validates fully)&#10;jeopardy.json: 14,758 µs (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="731" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="752.5" y="60" text-anchor="middle">0.69</text>
<text class="nj-charts-cell nj-charts-cell--small" x="752.5" y="73" text-anchor="middle">N</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="102" text-anchor="end">yyjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · validate&#10;1.41× the time of the fastest library (fully validating)&#10;twitter.json: 183 µs · insitu (copy)&#10;citm_catalog.json: 476 µs · read&#10;canada.json: 1,487 µs · insitu (copy)&#10;jeopardy.json: 30,922 µs · read&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="225" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="102" text-anchor="middle">1.41</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.14× the time of the fastest library (fully validating)&#10;twitter.json: 231 µs · insitu (copy)&#10;citm_catalog.json: 571 µs · read&#10;canada.json: 1,875 µs · read&#10;jeopardy.json: 37,817 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-0" x="317" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="102" text-anchor="middle">1.14</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.30× the time of the fastest library (fully validating)&#10;twitter.json: 191 µs · insitu (copy)&#10;citm_catalog.json: 480 µs · read&#10;canada.json: 1,489 µs · insitu (copy)&#10;jeopardy.json: 32,777 µs · read (raw numbers)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="409" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="102" text-anchor="middle">1.30</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.48× the time of the fastest library (fully validating)&#10;twitter.json: 440 µs · insitu (copy) + mut copy&#10;citm_catalog.json: 904 µs · mut copy&#10;canada.json: 3,692 µs · mut copy&#10;jeopardy.json: 84,466 µs · insitu (copy) + mut copy&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="501" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="102" text-anchor="middle">1.48</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.26× the time of the fastest library (fully validating)&#10;twitter.json: 298 µs · insitu (copy) + write&#10;citm_catalog.json: 642 µs · read + write&#10;canada.json: 3,222 µs · insitu (copy) + write&#10;jeopardy.json: 51,001 µs · read + write&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="593" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="102" text-anchor="middle">1.26</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;1.18× the time of the fastest fully validating library&#10;twitter.json: 298 µs · insitu (copy) + write (validates fully)&#10;citm_catalog.json: 642 µs · read + write (validates fully)&#10;canada.json: 2,523 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 51,001 µs · read + write (validates fully)&#10;copies each number&#x27;s text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="639" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="96" text-anchor="middle">1.18</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="109" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · write&#10;1.23× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 101 µs&#10;citm_catalog.json: 167 µs&#10;canada.json: 1,719 µs&#10;jeopardy.json: 19,937 µs">
<rect class="nj-heat-1" x="685" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="102" text-anchor="middle">1.23</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="138" text-anchor="end">simdjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · validate&#10;1.52× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 215 µs&#10;citm_catalog.json: 460 µs&#10;canada.json: 1,890 µs&#10;jeopardy.json: 28,890 µs">
<rect class="nj-heat-2" x="225" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="138" text-anchor="middle">1.52</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · sum&#10;1.21× the time of the fastest library (fully validating)&#10;twitter.json: 249 µs · D&#8203;OM&#10;citm_catalog.json: 572 µs · On-Demand&#10;canada.json: 2,398 µs · On-Demand&#10;jeopardy.json: 34,994 µs · D&#8203;OM">
<rect class="nj-heat-1" x="317" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="138" text-anchor="middle">1.21</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select&#10;1.34× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 192 µs&#10;citm_catalog.json: 454 µs&#10;canada.json: 1,893 µs&#10;jeopardy.json: 30,714 µs">
<rect class="nj-heat-1" x="409" y="117" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="138" text-anchor="middle">1.34</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.76× the time of the fastest fully validating library&#10;twitter.json: 128 µs · On-Demand structs&#10;citm_catalog.json: 356 µs · On-Demand&#10;canada.json: 571 µs · On-Demand&#10;jeopardy.json: 19,633 µs · On-Demand&#10;reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets">
<rect class="nj-heat-0" x="455" y="117" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="132" text-anchor="middle">0.76</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="145" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · edit&#10;simdjson&#x27;s documents are read-only: it has no A&#8203;PI to change a value and write the result">
<rect class="nj-heat-na" x="501" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-tick" x="546" y="138">n/a</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify&#10;1.73× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 425 µs&#10;citm_catalog.json: 850 µs&#10;canada.json: 5,094 µs&#10;jeopardy.json: 61,202 µs">
<rect class="nj-heat-2" x="593" y="117" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="138" text-anchor="middle">1.73</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify, checking less&#10;0.18× the time of the fastest fully validating library&#10;way: minify&#10;twitter.json: 62.5 µs&#10;citm_catalog.json: 168 µs&#10;canada.json: 227 µs&#10;jeopardy.json: 5,756 µs&#10;simdjson::minify() only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="117" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="132" text-anchor="middle">0.18</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="145" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · write&#10;2.41× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 201 µs&#10;citm_catalog.json: 416 µs&#10;canada.json: 3,186 µs&#10;jeopardy.json: 32,185 µs">
<rect class="nj-heat-2" x="685" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="138" text-anchor="middle">2.41</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="174" text-anchor="end">sonic-rs (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · validate&#10;1.91× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 326 µs&#10;citm_catalog.json: 681 µs&#10;canada.json: 1,939 µs&#10;jeopardy.json: 31,450 µs">
<rect class="nj-heat-2" x="225" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="174" text-anchor="middle">1.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.54× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 364 µs&#10;citm_catalog.json: 778 µs&#10;canada.json: 2,703 µs&#10;jeopardy.json: 41,361 µs">
<rect class="nj-heat-2" x="317" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="174" text-anchor="middle">1.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.85× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 333 µs&#10;citm_catalog.json: 691 µs&#10;canada.json: 1,936 µs&#10;jeopardy.json: 40,660 µs">
<rect class="nj-heat-2" x="409" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="174" text-anchor="middle">1.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · edit&#10;2.10× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 634 µs&#10;citm_catalog.json: 1,257 µs&#10;canada.json: 4,396 µs&#10;jeopardy.json: 140,936 µs">
<rect class="nj-heat-2" x="501" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="174" text-anchor="middle">2.10</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · minify&#10;1.93× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 535 µs&#10;citm_catalog.json: 1,134 µs&#10;canada.json: 4,377 µs&#10;jeopardy.json: 64,832 µs">
<rect class="nj-heat-2" x="593" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="174" text-anchor="middle">1.93</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;2.34× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 212 µs&#10;citm_catalog.json: 446 µs&#10;canada.json: 2,419 µs&#10;jeopardy.json: 33,366 µs">
<rect class="nj-heat-2" x="685" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="174" text-anchor="middle">2.34</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="210" text-anchor="end">sonic-cpp</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · validate, checking less&#10;2.50× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 382 µs&#10;citm_catalog.json: 985 µs&#10;canada.json: 2,579 µs&#10;jeopardy.json: 40,996 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="225" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="204" text-anchor="middle">2.50</text>
<text class="nj-charts-cell nj-charts-cell--small" x="270" y="217" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · sum, checking less&#10;1.86× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 428 µs&#10;citm_catalog.json: 1,098 µs&#10;canada.json: 2,975 µs&#10;jeopardy.json: 48,487 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="317" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="204" text-anchor="middle">1.86</text>
<text class="nj-charts-cell nj-charts-cell--small" x="362" y="217" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · select, checking less&#10;2.34× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 385 µs&#10;citm_catalog.json: 993 µs&#10;canada.json: 2,611 µs&#10;jeopardy.json: 46,356 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="409" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="204" text-anchor="middle">2.34</text>
<text class="nj-charts-cell nj-charts-cell--small" x="454" y="217" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · edit, checking less&#10;1.70× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 488 µs&#10;citm_catalog.json: 1,218 µs&#10;canada.json: 5,662 µs&#10;jeopardy.json: 63,697 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="501" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="204" text-anchor="middle">1.70</text>
<text class="nj-charts-cell nj-charts-cell--small" x="546" y="217" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · minify, checking less&#10;2.03× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 504 µs&#10;citm_catalog.json: 1,217 µs&#10;canada.json: 5,634 µs&#10;jeopardy.json: 61,988 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="593" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="204" text-anchor="middle">2.03</text>
<text class="nj-charts-cell nj-charts-cell--small" x="638" y="217" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · write&#10;1.61× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 114 µs&#10;citm_catalog.json: 240 µs&#10;canada.json: 3,109 µs&#10;jeopardy.json: 20,327 µs">
<rect class="nj-heat-2" x="685" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="210" text-anchor="middle">1.61</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="246" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;2.05× the time of the fastest library (fully validating)&#10;way: tape (copy)&#10;twitter.json: 289 µs&#10;citm_catalog.json: 698 µs&#10;canada.json: 2,278 µs&#10;jeopardy.json: 38,874 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="225" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="246" text-anchor="middle">2.05</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.63× the time of the fastest library (fully validating)&#10;way: visitor (copy)&#10;twitter.json: 354 µs&#10;citm_catalog.json: 866 µs&#10;canada.json: 2,717 µs&#10;jeopardy.json: 47,518 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="317" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="246" text-anchor="middle">1.63</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.39× the time of the fastest library (fully validating)&#10;way: structs (copy)&#10;twitter.json: 364 µs&#10;citm_catalog.json: 914 µs&#10;canada.json: 2,657 µs&#10;jeopardy.json: 57,697 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="409" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="246" text-anchor="middle">2.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.85× the time of the fastest library (fully validating)&#10;way: borrowed (copy)&#10;twitter.json: 948 µs&#10;citm_catalog.json: 2,102 µs&#10;canada.json: 7,654 µs&#10;jeopardy.json: 110,693 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="246" text-anchor="middle">2.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.40× the time of the fastest library (fully validating)&#10;way: borrowed (copy)&#10;twitter.json: 952 µs&#10;citm_catalog.json: 2,111 µs&#10;canada.json: 7,658 µs&#10;jeopardy.json: 108,130 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="593" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="246" text-anchor="middle">3.40</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;3.05× the time of the fastest library (fully validating)&#10;way: borrowed&#10;twitter.json: 355 µs&#10;citm_catalog.json: 478 µs&#10;canada.json: 2,728 µs&#10;jeopardy.json: 47,412 µs">
<rect class="nj-heat-3" x="685" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="246" text-anchor="middle">3.05</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="282" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;1.38× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 234 µs&#10;citm_catalog.json: 456 µs&#10;canada.json: 1,253 µs&#10;jeopardy.json: 27,563 µs">
<rect class="nj-heat-1" x="225" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">1.38</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.34× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 303 µs&#10;citm_catalog.json: 602 µs&#10;canada.json: 2,208 µs&#10;jeopardy.json: 44,688 µs">
<rect class="nj-heat-1" x="317" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.34</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;6.09× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,208 µs&#10;citm_catalog.json: 2,128 µs&#10;canada.json: 5,088 µs&#10;jeopardy.json: 163,712 µs">
<rect class="nj-heat-4" x="409" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">6.09</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.22× the time of the fastest library (fully validating)&#10;twitter.json: 1,115 µs · ordered_json&#10;citm_catalog.json: 2,065 µs · ordered_json&#10;canada.json: 7,348 µs · parse&#10;jeopardy.json: 162,216 µs · ordered_json">
<rect class="nj-heat-3" x="501" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">3.22</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.39× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 1,446 µs&#10;citm_catalog.json: 2,406 µs&#10;canada.json: 7,328 µs&#10;jeopardy.json: 182,132 µs">
<rect class="nj-heat-3" x="593" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">4.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;2.03× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 216 µs&#10;citm_catalog.json: 287 µs&#10;canada.json: 2,274 µs&#10;jeopardy.json: 30,928 µs">
<rect class="nj-heat-2" x="685" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">2.03</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.03× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 333 µs&#10;citm_catalog.json: 854 µs&#10;canada.json: 1,302 µs&#10;jeopardy.json: 46,251 µs">
<rect class="nj-heat-2" x="225" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="318" text-anchor="middle">2.03</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;3.88× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 974 µs&#10;citm_catalog.json: 2,057 µs&#10;canada.json: 6,338 µs&#10;jeopardy.json: 100,272 µs">
<rect class="nj-heat-3" x="317" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">3.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.81× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 314 µs&#10;citm_catalog.json: 852 µs&#10;canada.json: 1,303 µs&#10;jeopardy.json: 47,692 µs">
<rect class="nj-heat-2" x="409" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="318" text-anchor="middle">1.81</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.81× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 238 µs&#10;citm_catalog.json: 253 µs&#10;canada.json: 310 µs&#10;jeopardy.json: 36,013 µs&#10;reads into structs and steps over fields it doesn&#x27;t know without checking them (validate_skipped checks them too)">
<rect class="nj-heat-0" x="455" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="312" text-anchor="middle">0.81</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="325" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;4.44× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 1,527 µs&#10;citm_catalog.json: 3,216 µs&#10;canada.json: 11,033 µs&#10;jeopardy.json: 183,648 µs">
<rect class="nj-heat-3" x="501" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">4.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;5.23× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 1,512 µs&#10;citm_catalog.json: 3,245 µs&#10;canada.json: 11,112 µs&#10;jeopardy.json: 172,173 µs">
<rect class="nj-heat-4" x="593" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="318" text-anchor="middle">5.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;1.05× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 284 µs&#10;citm_catalog.json: 747 µs&#10;canada.json: 1,746 µs&#10;jeopardy.json: 40,439 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="312" text-anchor="middle">1.05</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="325" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;2.19× the time of the fastest library (fully validating)&#10;twitter.json: 212 µs · generic&#10;citm_catalog.json: 476 µs · generic (strict)&#10;canada.json: 1,702 µs · generic (strict)&#10;jeopardy.json: 34,032 µs · generic">
<rect class="nj-heat-2" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.19</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="354" text-anchor="end">Boost.J&#8203;SON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · validate&#10;2.54× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 540 µs&#10;citm_catalog.json: 990 µs&#10;canada.json: 1,449 µs&#10;jeopardy.json: 54,480 µs">
<rect class="nj-heat-3" x="225" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="354" text-anchor="middle">2.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;2.02× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 538 µs&#10;citm_catalog.json: 1,028 µs&#10;canada.json: 3,084 µs&#10;jeopardy.json: 54,765 µs">
<rect class="nj-heat-2" x="317" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">2.02</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;3.31× the time of the fastest library (fully validating)&#10;twitter.json: 623 µs · parse_into structs&#10;citm_catalog.json: 1,208 µs · parse_into structs&#10;canada.json: 3,638 µs · parse&#10;jeopardy.json: 67,923 µs · parse_into structs">
<rect class="nj-heat-3" x="409" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="354" text-anchor="middle">3.31</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;3.23× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,355 µs&#10;citm_catalog.json: 1,997 µs&#10;canada.json: 6,522 µs&#10;jeopardy.json: 157,849 µs">
<rect class="nj-heat-3" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">3.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;3.89× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,407 µs&#10;citm_catalog.json: 2,003 µs&#10;canada.json: 6,555 µs&#10;jeopardy.json: 154,865 µs">
<rect class="nj-heat-3" x="593" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="354" text-anchor="middle">3.89</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;3.67× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 499 µs&#10;citm_catalog.json: 511 µs&#10;canada.json: 2,873 µs&#10;jeopardy.json: 63,201 µs">
<rect class="nj-heat-3" x="685" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="354" text-anchor="middle">3.67</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="390" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.44× the time of the fastest library (fully validating)&#10;way: from_utf8 + IgnoredAny&#10;twitter.json: 452 µs&#10;citm_catalog.json: 1,103 µs&#10;canada.json: 1,556 µs&#10;jeopardy.json: 46,517 µs">
<rect class="nj-heat-2" x="225" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="390" text-anchor="middle">2.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;2.21× the time of the fastest fully validating library&#10;way: IgnoredAny&#10;twitter.json: 354 µs&#10;citm_catalog.json: 1,047 µs&#10;canada.json: 1,451 µs&#10;jeopardy.json: 44,984 µs&#10;trusts U&#8203;TF-8 in the strings it skips (from_slice); strings it reads are checked">
<rect class="nj-heat-2" x="271" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="384" text-anchor="middle">2.21</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.60× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 652 µs&#10;citm_catalog.json: 1,242 µs&#10;canada.json: 4,772 µs&#10;jeopardy.json: 66,568 µs">
<rect class="nj-heat-3" x="317" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="390" text-anchor="middle">2.60</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;2.41× the time of the fastest library (fully validating)&#10;way: from_utf8 + structs&#10;twitter.json: 480 µs&#10;citm_catalog.json: 1,125 µs&#10;canada.json: 1,560 µs&#10;jeopardy.json: 62,378 µs">
<rect class="nj-heat-2" x="409" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="390" text-anchor="middle">2.41</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select, checking less&#10;2.26× the time of the fastest fully validating library&#10;twitter.json: 410 µs · structs&#10;citm_catalog.json: 1,084 µs · structs&#10;canada.json: 1,455 µs · structs&#10;jeopardy.json: 62,378 µs · from_utf8 + structs (validates fully)&#10;trusts U&#8203;TF-8 in the strings it skips (from_slice); strings it reads are checked">
<rect class="nj-heat-2" x="455" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="384" text-anchor="middle">2.26</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;5.02× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 2,009 µs&#10;citm_catalog.json: 3,316 µs&#10;canada.json: 9,666 µs&#10;jeopardy.json: 251,931 µs">
<rect class="nj-heat-4" x="501" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="390" text-anchor="middle">5.02</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;5.85× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 2,004 µs&#10;citm_catalog.json: 3,290 µs&#10;canada.json: 9,792 µs&#10;jeopardy.json: 227,369 µs">
<rect class="nj-heat-4" x="593" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="390" text-anchor="middle">5.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.90× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 322 µs&#10;citm_catalog.json: 490 µs&#10;canada.json: 2,286 µs&#10;jeopardy.json: 49,967 µs">
<rect class="nj-heat-3" x="685" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="390" text-anchor="middle">2.90</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="426" text-anchor="end">RapidJSON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate&#10;4.67× the time of the fastest library (fully validating)&#10;twitter.json: 1,318 µs · insitu (copy)&#10;citm_catalog.json: 1,391 µs · S&#8203;AX (string stream, default precision)&#10;canada.json: 1,971 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 133,695 µs · S&#8203;AX (string stream, default precision)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="426" text-anchor="middle">4.67</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.09× the time of the fastest fully validating library&#10;twitter.json: 706 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,033 µs · S&#8203;AX (string stream, default precision) (no encoding check)&#10;canada.json: 1,971 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 64,732 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="271" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="420" text-anchor="middle">3.09</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum&#10;4.18× the time of the fastest library (fully validating)&#10;twitter.json: 1,332 µs · S&#8203;AX&#10;citm_catalog.json: 1,472 µs · S&#8203;AX (string stream)&#10;canada.json: 6,448 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 136,330 µs · S&#8203;AX (string stream)">
<rect class="nj-heat-3" x="317" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="426" text-anchor="middle">4.18</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.89× the time of the fastest fully validating library&#10;twitter.json: 738 µs · S&#8203;AX (string stream) (no encoding check)&#10;citm_catalog.json: 1,157 µs · S&#8203;AX (string stream) (no encoding check)&#10;canada.json: 6,432 µs · S&#8203;AX (string stream) (no encoding check)&#10;jeopardy.json: 71,646 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="363" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="420" text-anchor="middle">2.89</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select&#10;6.02× the time of the fastest library (fully validating)&#10;twitter.json: 1,314 µs · insitu (copy)&#10;citm_catalog.json: 1,578 µs · insitu (copy)&#10;canada.json: 6,814 µs · Document (string stream)&#10;jeopardy.json: 144,649 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-4" x="409" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="426" text-anchor="middle">6.02</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.93× the time of the fastest fully validating library&#10;twitter.json: 701 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,166 µs · insitu (copy) (no encoding check)&#10;canada.json: 6,745 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 67,617 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="455" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="420" text-anchor="middle">3.93</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit&#10;4.85× the time of the fastest library (fully validating)&#10;twitter.json: 1,924 µs · Document&#10;citm_catalog.json: 2,393 µs · insitu (copy)&#10;canada.json: 13,711 µs · Document (string stream)&#10;jeopardy.json: 224,328 µs · Document (string stream)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="426" text-anchor="middle">4.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;3.83× the time of the fastest fully validating library&#10;twitter.json: 1,356 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,992 µs · insitu (copy) (no encoding check)&#10;canada.json: 13,711 µs · Document (string stream) (validates fully)&#10;jeopardy.json: 147,902 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="547" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="420" text-anchor="middle">3.83</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify&#10;4.85× the time of the fastest library (fully validating)&#10;twitter.json: 1,523 µs · S&#8203;AX to Writer&#10;citm_catalog.json: 1,803 µs · S&#8203;AX to Writer (string stream)&#10;canada.json: 14,378 µs · Document + Writer&#10;jeopardy.json: 174,958 µs · S&#8203;AX to Writer (string stream)">
<rect class="nj-heat-3" x="593" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="426" text-anchor="middle">4.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;3.66× the time of the fastest fully validating library&#10;twitter.json: 1,044 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;citm_catalog.json: 1,499 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;canada.json: 11,568 µs · S&#8203;AX to Writer (raw numbers) (validates fully)&#10;jeopardy.json: 123,908 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;copies each number&#x27;s text instead of formatting it (kParseNumbersAsStringsFlag)">
<rect class="nj-heat-3" x="639" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="420" text-anchor="middle">3.66</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="433" text-anchor="middle">U N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · write&#10;5.74× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 596 µs&#10;citm_catalog.json: 836 µs&#10;canada.json: 6,928 µs&#10;jeopardy.json: 80,160 µs">
<rect class="nj-heat-4" x="685" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="426" text-anchor="middle">5.74</text>
</g>
<text class="nj-charts-tick nj-charts-tick--l" x="8" y="472">time relative to the fastest fully validating library, less is better</text>
<g><rect class="nj-heat-0" x="8" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="46" y="496" text-anchor="middle">below 1.15</text></g>
<g><rect class="nj-heat-1" x="88" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="126" y="496" text-anchor="middle">1.15 to 1.5</text></g>
<g><rect class="nj-heat-2" x="168" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="206" y="496" text-anchor="middle">1.5 to 2.5</text></g>
<g><rect class="nj-heat-3" x="248" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="286" y="496" text-anchor="middle">2.5 to 5</text></g>
<g><rect class="nj-heat-4" x="328" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="366" y="496" text-anchor="middle">5 and more</text></g>
<rect class="nj-heat-na" x="420" y="482" width="40" height="20" rx="3"/>
<text class="nj-charts-tick" x="440" y="496">n/a</text>
<text class="nj-charts-tick nj-charts-tick--l" x="468" y="496">no A&#8203;PI for it</text>
</svg>

Before

Width:  |  Height:  |  Size: 46 KiB

@@ -1,379 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewBox="0 0 784 510" role="img" aria-labelledby="nj-blog-uc-x86-clang nj-blog-uc-x86-clang-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-uc-x86-clang">Use cases: time of each library relative to the fastest, x86-64 with Clang 23</title>
<desc id="nj-blog-uc-x86-clang-d">Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.05; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.81 doing less, N); nlohmann/json json_document minify: 1.00 (0.83 doing less, N); nlohmann/json json_document write: 1.00 (0.71 doing less, N); yyjson validate: 2.21; yyjson sum: 1.23; yyjson select: 1.40; yyjson edit: 1.48; yyjson minify: 1.27 (1.09 doing less, N); yyjson write: 1.16; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.26 doing less, U); sonic-cpp select: no fully validating way (1.50 doing less, U); sonic-cpp edit: no fully validating way (1.21 doing less, U); sonic-cpp minify: no fully validating way (1.36 doing less, U); sonic-cpp write: 1.33; simdjson validate: 2.06; simdjson sum: 1.19; simdjson select: 1.33 (0.56 doing less, P); simdjson edit: n/a; simdjson minify: 1.55 (0.18 doing less, P); simdjson write: 2.07; sonic-rs (Rust) validate: 1.90; sonic-rs (Rust) sum: 1.13; sonic-rs (Rust) select: 1.37; sonic-rs (Rust) edit: 1.90; sonic-rs (Rust) minify: 1.75; sonic-rs (Rust) write: 2.01; Boost.J&#8203;SON validate: 1.80; Boost.J&#8203;SON sum: 1.17; Boost.J&#8203;SON select: 2.19; Boost.J&#8203;SON edit: 2.37; Boost.J&#8203;SON minify: 2.65; Boost.J&#8203;SON write: 2.38; nlohmann/json json validate: 1.43; nlohmann/json json sum: 1.00; nlohmann/json json select: 6.54; nlohmann/json json edit: 3.53; nlohmann/json json minify: 4.31; nlohmann/json json write: 1.88; simd-json (Rust) validate: 3.57; simd-json (Rust) sum: 1.91; simd-json (Rust) select: 2.61; simd-json (Rust) edit: 2.88; simd-json (Rust) minify: 3.43; simd-json (Rust) write: 2.28; serde_json (Rust) validate: 2.36 (2.11 doing less, U); serde_json (Rust) sum: 2.35; serde_json (Rust) select: 1.75; serde_json (Rust) edit: 4.53; serde_json (Rust) minify: 4.99; serde_json (Rust) write: 2.22; Glaze validate: 2.24; Glaze sum: 4.24 (3.96 doing less, P); Glaze select: 1.39 (0.61 doing less, P); Glaze edit: 5.50; Glaze minify: 5.78 (0.69 doing less, P); Glaze write: 1.95; RapidJSON validate: 5.18 (3.77 doing less, U); RapidJSON sum: 3.25 (2.40 doing less, U); RapidJSON select: 4.45 (3.45 doing less, U); RapidJSON edit: 3.16 (2.68 doing less, U); RapidJSON minify: 3.43 (2.57 doing less, U N); RapidJSON write: 2.86.</desc>
<text class="nj-charts-tick" x="270" y="34">validate</text>
<text class="nj-charts-tick" x="362" y="34">sum</text>
<text class="nj-charts-tick" x="454" y="34">select</text>
<text class="nj-charts-tick" x="546" y="34">edit</text>
<text class="nj-charts-tick" x="638" y="34">minify</text>
<text class="nj-charts-tick" x="730" y="34">write</text>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="66" text-anchor="end">nlohmann/json json_document</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · validate&#10;1.00× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 250 µs&#10;citm_catalog.json: 509 µs&#10;canada.json: 1,032 µs&#10;jeopardy.json: 34,454 µs">
<rect class="nj-heat-0" x="225" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · sum&#10;1.05× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 366 µs&#10;citm_catalog.json: 941 µs&#10;canada.json: 3,680 µs&#10;jeopardy.json: 86,966 µs">
<rect class="nj-heat-0" x="317" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="66" text-anchor="middle">1.05</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · select&#10;1.00× the time of the fastest library (fully validating)&#10;twitter.json: 316 µs · structs (from_json)&#10;citm_catalog.json: 783 µs · parse&#10;canada.json: 1,368 µs · structs (from_json)&#10;jeopardy.json: 91,736 µs · parse">
<rect class="nj-heat-0" x="409" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit&#10;1.00× the time of the fastest library (fully validating)&#10;way: editable&#10;twitter.json: 519 µs&#10;citm_catalog.json: 1,152 µs&#10;canada.json: 5,671 µs&#10;jeopardy.json: 195,716 µs">
<rect class="nj-heat-0" x="501" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit, checking less&#10;0.81× the time of the fastest fully validating library&#10;twitter.json: 518 µs · editable (source numbers) (validates fully)&#10;citm_catalog.json: 1,152 µs · editable (validates fully)&#10;canada.json: 2,502 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 195,716 µs · editable (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="547" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="60" text-anchor="middle">0.81</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 472 µs&#10;citm_catalog.json: 1,055 µs&#10;canada.json: 5,041 µs&#10;jeopardy.json: 149,143 µs">
<rect class="nj-heat-0" x="593" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify, checking less&#10;0.83× the time of the fastest fully validating library&#10;twitter.json: 467 µs · parse + dump (source numbers) (validates fully)&#10;citm_catalog.json: 1,055 µs · parse + dump (validates fully)&#10;canada.json: 2,363 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 149,143 µs · parse + dump (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.83</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write&#10;1.00× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 158 µs&#10;citm_catalog.json: 279 µs&#10;canada.json: 3,637 µs&#10;jeopardy.json: 67,366 µs">
<rect class="nj-heat-0" x="685" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="707.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write, checking less&#10;0.71× the time of the fastest fully validating library&#10;twitter.json: 153 µs · dump (source numbers) (validates fully)&#10;citm_catalog.json: 276 µs · dump (source numbers) (validates fully)&#10;canada.json: 982 µs · dump (source numbers) (validates fully)&#10;jeopardy.json: 67,366 µs · dump (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="731" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="752.5" y="60" text-anchor="middle">0.71</text>
<text class="nj-charts-cell nj-charts-cell--small" x="752.5" y="73" text-anchor="middle">N</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="102" text-anchor="end">yyjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · validate&#10;2.21× the time of the fastest library (fully validating)&#10;twitter.json: 383 µs · read&#10;citm_catalog.json: 887 µs · read&#10;canada.json: 2,572 µs · read (raw numbers)&#10;jeopardy.json: 123,640 µs · read (raw numbers)">
<rect class="nj-heat-2" x="225" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="102" text-anchor="middle">2.21</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.23× the time of the fastest library (fully validating)&#10;twitter.json: 436 µs · read&#10;citm_catalog.json: 1,048 µs · insitu (copy)&#10;canada.json: 3,454 µs · read&#10;jeopardy.json: 133,577 µs · read&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="317" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="102" text-anchor="middle">1.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.40× the time of the fastest library (fully validating)&#10;twitter.json: 386 µs · insitu (copy)&#10;citm_catalog.json: 891 µs · insitu (copy)&#10;canada.json: 2,572 µs · read (raw numbers)&#10;jeopardy.json: 135,813 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="409" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="102" text-anchor="middle">1.40</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.48× the time of the fastest library (fully validating)&#10;twitter.json: 833 µs · mut copy&#10;citm_catalog.json: 1,674 µs · mut copy&#10;canada.json: 7,249 µs · mut copy&#10;jeopardy.json: 316,652 µs · insitu (copy) + mut copy&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="501" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="102" text-anchor="middle">1.48</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.27× the time of the fastest library (fully validating)&#10;way: read + write&#10;twitter.json: 626 µs&#10;citm_catalog.json: 1,261 µs&#10;canada.json: 6,179 µs&#10;jeopardy.json: 200,886 µs">
<rect class="nj-heat-1" x="593" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="102" text-anchor="middle">1.27</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;1.09× the time of the fastest fully validating library&#10;twitter.json: 626 µs · read + write (validates fully)&#10;citm_catalog.json: 1,236 µs · read (raw numbers) + write (validates fully)&#10;canada.json: 3,426 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 197,700 µs · read (raw numbers) + write (validates fully)&#10;copies each number&#x27;s text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)">
<rect class="nj-heat-0" x="639" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="96" text-anchor="middle">1.09</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="109" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · write&#10;1.16× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 216 µs&#10;citm_catalog.json: 367 µs&#10;canada.json: 3,366 µs&#10;jeopardy.json: 73,272 µs">
<rect class="nj-heat-1" x="685" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="102" text-anchor="middle">1.16</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="138" text-anchor="end">sonic-cpp</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · validate, checking less&#10;2.32× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 451 µs&#10;citm_catalog.json: 998 µs&#10;canada.json: 3,031 µs&#10;jeopardy.json: 95,823 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="225" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="132" text-anchor="middle">2.32</text>
<text class="nj-charts-cell nj-charts-cell--small" x="270" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · sum, checking less&#10;1.26× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 504 µs&#10;citm_catalog.json: 1,176 µs&#10;canada.json: 3,701 µs&#10;jeopardy.json: 104,509 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="317" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="132" text-anchor="middle">1.26</text>
<text class="nj-charts-cell nj-charts-cell--small" x="362" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · select, checking less&#10;1.50× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 454 µs&#10;citm_catalog.json: 1,015 µs&#10;canada.json: 3,025 µs&#10;jeopardy.json: 112,621 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="409" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="132" text-anchor="middle">1.50</text>
<text class="nj-charts-cell nj-charts-cell--small" x="454" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · edit, checking less&#10;1.21× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 642 µs&#10;citm_catalog.json: 1,497 µs&#10;canada.json: 8,153 µs&#10;jeopardy.json: 184,321 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="501" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="132" text-anchor="middle">1.21</text>
<text class="nj-charts-cell nj-charts-cell--small" x="546" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · minify, checking less&#10;1.36× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 655 µs&#10;citm_catalog.json: 1,474 µs&#10;canada.json: 7,856 µs&#10;jeopardy.json: 169,992 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="593" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="132" text-anchor="middle">1.36</text>
<text class="nj-charts-cell nj-charts-cell--small" x="638" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · write&#10;1.33× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 228 µs&#10;citm_catalog.json: 474 µs&#10;canada.json: 4,766 µs&#10;jeopardy.json: 66,619 µs">
<rect class="nj-heat-1" x="685" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="138" text-anchor="middle">1.33</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="174" text-anchor="end">simdjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · validate&#10;2.06× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 302 µs&#10;citm_catalog.json: 721 µs&#10;canada.json: 3,202 µs&#10;jeopardy.json: 116,859 µs">
<rect class="nj-heat-2" x="225" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="174" text-anchor="middle">2.06</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · sum&#10;1.19× the time of the fastest library (fully validating)&#10;twitter.json: 391 µs · D&#8203;OM&#10;citm_catalog.json: 969 µs · D&#8203;OM&#10;canada.json: 4,121 µs · D&#8203;OM&#10;jeopardy.json: 116,855 µs · On-Demand">
<rect class="nj-heat-1" x="317" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="174" text-anchor="middle">1.19</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select&#10;1.33× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 318 µs&#10;citm_catalog.json: 728 µs&#10;canada.json: 3,213 µs&#10;jeopardy.json: 129,986 µs">
<rect class="nj-heat-1" x="409" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="174" text-anchor="middle">1.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.56× the time of the fastest fully validating library&#10;way: On-Demand&#10;twitter.json: 182 µs&#10;citm_catalog.json: 494 µs&#10;canada.json: 692 µs&#10;jeopardy.json: 50,660 µs&#10;reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets">
<rect class="nj-heat-0" x="455" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="168" text-anchor="middle">0.56</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · edit&#10;simdjson&#x27;s documents are read-only: it has no A&#8203;PI to change a value and write the result">
<rect class="nj-heat-na" x="501" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-tick" x="546" y="174">n/a</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify&#10;1.55× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 706 µs&#10;citm_catalog.json: 1,411 µs&#10;canada.json: 8,125 µs&#10;jeopardy.json: 270,332 µs">
<rect class="nj-heat-2" x="593" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="174" text-anchor="middle">1.55</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify, checking less&#10;0.18× the time of the fastest fully validating library&#10;way: minify&#10;twitter.json: 99.0 µs&#10;citm_catalog.json: 270 µs&#10;canada.json: 329 µs&#10;jeopardy.json: 42,546 µs&#10;simdjson::minify() only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="168" text-anchor="middle">0.18</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · write&#10;2.07× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 382 µs&#10;citm_catalog.json: 661 µs&#10;canada.json: 4,787 µs&#10;jeopardy.json: 162,220 µs">
<rect class="nj-heat-2" x="685" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="174" text-anchor="middle">2.07</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="210" text-anchor="end">sonic-rs (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · validate&#10;1.90× the time of the fastest library (fully validating)&#10;way: IgnoredAny&#10;twitter.json: 501 µs&#10;citm_catalog.json: 970 µs&#10;canada.json: 2,249 µs&#10;jeopardy.json: 54,369 µs">
<rect class="nj-heat-2" x="225" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="210" text-anchor="middle">1.90</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.13× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 501 µs&#10;citm_catalog.json: 1,123 µs&#10;canada.json: 4,397 µs&#10;jeopardy.json: 59,583 µs">
<rect class="nj-heat-0" x="317" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="210" text-anchor="middle">1.13</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.37× the time of the fastest library (fully validating)&#10;way: structs&#10;twitter.json: 504 µs&#10;citm_catalog.json: 1,033 µs&#10;canada.json: 2,328 µs&#10;jeopardy.json: 90,486 µs">
<rect class="nj-heat-1" x="409" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="210" text-anchor="middle">1.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · edit&#10;1.90× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,197 µs&#10;citm_catalog.json: 2,389 µs&#10;canada.json: 7,744 µs&#10;jeopardy.json: 390,952 µs">
<rect class="nj-heat-2" x="501" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="210" text-anchor="middle">1.90</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · minify&#10;1.75× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,000 µs&#10;citm_catalog.json: 2,097 µs&#10;canada.json: 7,795 µs&#10;jeopardy.json: 215,280 µs">
<rect class="nj-heat-2" x="593" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="210" text-anchor="middle">1.75</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;2.01× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 434 µs&#10;citm_catalog.json: 927 µs&#10;canada.json: 3,987 µs&#10;jeopardy.json: 109,176 µs">
<rect class="nj-heat-2" x="685" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="210" text-anchor="middle">2.01</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="246" text-anchor="end">Boost.J&#8203;SON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · validate&#10;1.80× the time of the fastest library (fully validating)&#10;twitter.json: 570 µs · S&#8203;AX (numbers: none)&#10;citm_catalog.json: 903 µs · S&#8203;AX (numbers: none)&#10;canada.json: 1,678 µs · S&#8203;AX (numbers: none)&#10;jeopardy.json: 55,087 µs · S&#8203;AX">
<rect class="nj-heat-2" x="225" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="246" text-anchor="middle">1.80</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.17× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 580 µs&#10;citm_catalog.json: 928 µs&#10;canada.json: 5,715 µs&#10;jeopardy.json: 55,874 µs">
<rect class="nj-heat-1" x="317" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="246" text-anchor="middle">1.17</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.19× the time of the fastest library (fully validating)&#10;twitter.json: 760 µs · parse_into structs&#10;citm_catalog.json: 1,388 µs · parse_into structs&#10;canada.json: 7,026 µs · parse&#10;jeopardy.json: 97,008 µs · parse_into structs">
<rect class="nj-heat-2" x="409" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="246" text-anchor="middle">2.19</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.37× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,716 µs&#10;citm_catalog.json: 2,578 µs&#10;canada.json: 13,427 µs&#10;jeopardy.json: 354,510 µs">
<rect class="nj-heat-2" x="501" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="246" text-anchor="middle">2.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;2.65× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,722 µs&#10;citm_catalog.json: 2,573 µs&#10;canada.json: 12,678 µs&#10;jeopardy.json: 330,878 µs">
<rect class="nj-heat-3" x="593" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="246" text-anchor="middle">2.65</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;2.38× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 478 µs&#10;citm_catalog.json: 913 µs&#10;canada.json: 5,610 µs&#10;jeopardy.json: 141,994 µs">
<rect class="nj-heat-2" x="685" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="246" text-anchor="middle">2.38</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="282" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;1.43× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 335 µs&#10;citm_catalog.json: 711 µs&#10;canada.json: 2,018 µs&#10;jeopardy.json: 39,513 µs">
<rect class="nj-heat-1" x="225" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">1.43</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.00× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 431 µs&#10;citm_catalog.json: 914 µs&#10;canada.json: 3,824 µs&#10;jeopardy.json: 60,439 µs">
<rect class="nj-heat-0" x="317" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;6.54× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 3,181 µs&#10;citm_catalog.json: 4,583 µs&#10;canada.json: 9,599 µs&#10;jeopardy.json: 405,734 µs">
<rect class="nj-heat-4" x="409" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">6.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.53× the time of the fastest library (fully validating)&#10;twitter.json: 2,452 µs · ordered_json&#10;citm_catalog.json: 4,402 µs · ordered_json&#10;canada.json: 14,765 µs · parse&#10;jeopardy.json: 646,489 µs · ordered_json">
<rect class="nj-heat-3" x="501" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">3.53</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.31× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 3,525 µs&#10;citm_catalog.json: 5,178 µs&#10;canada.json: 14,024 µs&#10;jeopardy.json: 506,705 µs">
<rect class="nj-heat-3" x="593" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">4.31</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.88× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 438 µs&#10;citm_catalog.json: 599 µs&#10;canada.json: 4,458 µs&#10;jeopardy.json: 116,318 µs">
<rect class="nj-heat-2" x="685" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">1.88</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.57× the time of the fastest library (fully validating)&#10;way: tape (copy)&#10;twitter.json: 567 µs&#10;citm_catalog.json: 1,430 µs&#10;canada.json: 4,359 µs&#10;jeopardy.json: 207,551 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="318" text-anchor="middle">3.57</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.91× the time of the fastest library (fully validating)&#10;way: visitor (copy)&#10;twitter.json: 681 µs&#10;citm_catalog.json: 1,650 µs&#10;canada.json: 5,083 µs&#10;jeopardy.json: 210,185 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="317" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">1.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.61× the time of the fastest library (fully validating)&#10;way: structs (copy)&#10;twitter.json: 679 µs&#10;citm_catalog.json: 1,731 µs&#10;canada.json: 5,144 µs&#10;jeopardy.json: 239,164 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="318" text-anchor="middle">2.61</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.88× the time of the fastest library (fully validating)&#10;twitter.json: 1,862 µs · borrowed (copy)&#10;citm_catalog.json: 4,194 µs · borrowed (copy)&#10;canada.json: 14,896 µs · owned (copy)&#10;jeopardy.json: 391,369 µs · borrowed (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">2.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.43× the time of the fastest library (fully validating)&#10;way: borrowed (copy)&#10;twitter.json: 1,889 µs&#10;citm_catalog.json: 4,196 µs&#10;canada.json: 15,716 µs&#10;jeopardy.json: 414,377 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="593" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="318" text-anchor="middle">3.43</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.28× the time of the fastest library (fully validating)&#10;way: borrowed&#10;twitter.json: 582 µs&#10;citm_catalog.json: 800 µs&#10;canada.json: 5,147 µs&#10;jeopardy.json: 122,623 µs">
<rect class="nj-heat-2" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.28</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="354" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.36× the time of the fastest library (fully validating)&#10;way: from_utf8 + IgnoredAny&#10;twitter.json: 624 µs&#10;citm_catalog.json: 1,440 µs&#10;canada.json: 2,406 µs&#10;jeopardy.json: 64,720 µs">
<rect class="nj-heat-2" x="225" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="354" text-anchor="middle">2.36</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;2.11× the time of the fastest fully validating library&#10;way: IgnoredAny&#10;twitter.json: 484 µs&#10;citm_catalog.json: 1,370 µs&#10;canada.json: 2,314 µs&#10;jeopardy.json: 58,247 µs&#10;trusts U&#8203;TF-8 in the strings it skips (from_slice); strings it reads are checked">
<rect class="nj-heat-2" x="271" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="348" text-anchor="middle">2.11</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="361" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.35× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 1,311 µs&#10;citm_catalog.json: 2,288 µs&#10;canada.json: 7,127 µs&#10;jeopardy.json: 129,497 µs">
<rect class="nj-heat-2" x="317" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">2.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;1.75× the time of the fastest library (fully validating)&#10;way: from_utf8 + structs&#10;twitter.json: 701 µs&#10;citm_catalog.json: 1,532 µs&#10;canada.json: 2,529 µs&#10;jeopardy.json: 107,316 µs">
<rect class="nj-heat-2" x="409" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="354" text-anchor="middle">1.75</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.53× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,042 µs&#10;citm_catalog.json: 6,586 µs&#10;canada.json: 16,631 µs&#10;jeopardy.json: 632,766 µs">
<rect class="nj-heat-3" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">4.53</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;4.99× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,012 µs&#10;citm_catalog.json: 6,583 µs&#10;canada.json: 17,306 µs&#10;jeopardy.json: 509,702 µs">
<rect class="nj-heat-3" x="593" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="354" text-anchor="middle">4.99</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.22× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 550 µs&#10;citm_catalog.json: 887 µs&#10;canada.json: 4,005 µs&#10;jeopardy.json: 134,163 µs">
<rect class="nj-heat-2" x="685" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="354" text-anchor="middle">2.22</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="390" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.24× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 594 µs&#10;citm_catalog.json: 1,230 µs&#10;canada.json: 2,139 µs&#10;jeopardy.json: 73,235 µs">
<rect class="nj-heat-2" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.24</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.24× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,374 µs&#10;citm_catalog.json: 3,982 µs&#10;canada.json: 11,930 µs&#10;jeopardy.json: 261,204 µs">
<rect class="nj-heat-3" x="317" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="390" text-anchor="middle">4.24</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum, checking less&#10;3.96× the time of the fastest fully validating library&#10;twitter.json: 2,374 µs · generic (double, strict) (validates fully)&#10;citm_catalog.json: 3,982 µs · generic (double, strict) (validates fully)&#10;canada.json: 11,921 µs · generic (double)&#10;jeopardy.json: 198,036 µs · lazy_json&#10;accepts trailing garbage after the value: Glaze&#x27;s default (validate_trailing_whitespace checks it)&#10;reads lazily: lazy_json reads only what you ask for and steps over the rest">
<rect class="nj-heat-3" x="363" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="384" text-anchor="middle">3.96</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.39× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 542 µs&#10;citm_catalog.json: 1,369 µs&#10;canada.json: 1,846 µs&#10;jeopardy.json: 83,907 µs">
<rect class="nj-heat-1" x="409" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="390" text-anchor="middle">1.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.61× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 337 µs&#10;citm_catalog.json: 416 µs&#10;canada.json: 447 µs&#10;jeopardy.json: 68,455 µs&#10;reads into structs and steps over fields it doesn&#x27;t know without checking them (validate_skipped checks them too)">
<rect class="nj-heat-0" x="455" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="384" text-anchor="middle">0.61</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;5.50× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,896 µs&#10;citm_catalog.json: 7,671 µs&#10;canada.json: 28,104 µs&#10;jeopardy.json: 723,675 µs">
<rect class="nj-heat-4" x="501" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="390" text-anchor="middle">5.50</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;5.78× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,801 µs&#10;citm_catalog.json: 7,482 µs&#10;canada.json: 26,932 µs&#10;jeopardy.json: 544,342 µs">
<rect class="nj-heat-4" x="593" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="390" text-anchor="middle">5.78</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;0.69× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 422 µs&#10;citm_catalog.json: 1,051 µs&#10;canada.json: 2,140 µs&#10;jeopardy.json: 87,842 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="384" text-anchor="middle">0.69</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;1.95× the time of the fastest library (fully validating)&#10;twitter.json: 396 µs · generic&#10;citm_catalog.json: 725 µs · generic (strict)&#10;canada.json: 4,107 µs · generic (strict)&#10;jeopardy.json: 132,573 µs · generic">
<rect class="nj-heat-2" x="685" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="390" text-anchor="middle">1.95</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="426" text-anchor="end">RapidJSON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate&#10;5.18× the time of the fastest library (fully validating)&#10;twitter.json: 1,798 µs · insitu (copy)&#10;citm_catalog.json: 1,944 µs · S&#8203;AX (default precision)&#10;canada.json: 4,019 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 232,684 µs · S&#8203;AX (string stream, default precision)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-4" x="225" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="426" text-anchor="middle">5.18</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.77× the time of the fastest fully validating library&#10;twitter.json: 1,173 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,504 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 4,019 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 128,516 µs · S&#8203;AX (string stream, default precision) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="271" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="420" text-anchor="middle">3.77</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum&#10;3.25× the time of the fastest library (fully validating)&#10;twitter.json: 1,846 µs · insitu (copy)&#10;citm_catalog.json: 2,176 µs · S&#8203;AX&#10;canada.json: 10,561 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 239,499 µs · S&#8203;AX (string stream)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="317" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="426" text-anchor="middle">3.25</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.40× the time of the fastest fully validating library&#10;twitter.json: 1,229 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,761 µs · S&#8203;AX (no encoding check)&#10;canada.json: 10,561 µs · S&#8203;AX (string stream) (validates fully)&#10;jeopardy.json: 131,510 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="363" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="420" text-anchor="middle">2.40</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select&#10;4.45× the time of the fastest library (fully validating)&#10;way: insitu (copy)&#10;twitter.json: 1,806 µs&#10;citm_catalog.json: 2,303 µs&#10;canada.json: 11,395 µs&#10;jeopardy.json: 257,762 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="426" text-anchor="middle">4.45</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.45× the time of the fastest fully validating library&#10;twitter.json: 1,184 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,929 µs · insitu (copy) (no encoding check)&#10;canada.json: 11,261 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 171,716 µs · Document (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="455" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="420" text-anchor="middle">3.45</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit&#10;3.16× the time of the fastest library (fully validating)&#10;way: insitu (copy)&#10;twitter.json: 2,478 µs&#10;citm_catalog.json: 3,261 µs&#10;canada.json: 21,686 µs&#10;jeopardy.json: 378,727 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="426" text-anchor="middle">3.16</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.68× the time of the fastest fully validating library&#10;twitter.json: 1,842 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 2,887 µs · insitu (copy) (no encoding check)&#10;canada.json: 21,686 µs · insitu (copy) (validates fully)&#10;jeopardy.json: 294,727 µs · Document (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="547" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="420" text-anchor="middle">2.68</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify&#10;3.43× the time of the fastest library (fully validating)&#10;twitter.json: 2,456 µs · S&#8203;AX to Writer&#10;citm_catalog.json: 2,864 µs · S&#8203;AX to Writer&#10;canada.json: 21,753 µs · Document + Writer&#10;jeopardy.json: 338,985 µs · S&#8203;AX to Writer (string stream)">
<rect class="nj-heat-3" x="593" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="426" text-anchor="middle">3.43</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;2.57× the time of the fastest fully validating library&#10;twitter.json: 1,794 µs · S&#8203;AX to Writer (no encoding check)&#10;citm_catalog.json: 2,444 µs · S&#8203;AX to Writer (no encoding check)&#10;canada.json: 14,707 µs · S&#8203;AX to Writer (raw numbers) (no encoding check)&#10;jeopardy.json: 252,656 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;copies each number&#x27;s text instead of formatting it (kParseNumbersAsStringsFlag)">
<rect class="nj-heat-3" x="639" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="420" text-anchor="middle">2.57</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="433" text-anchor="middle">U N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · write&#10;2.86× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 633 µs&#10;citm_catalog.json: 960 µs&#10;canada.json: 9,388 µs&#10;jeopardy.json: 127,319 µs">
<rect class="nj-heat-3" x="685" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="426" text-anchor="middle">2.86</text>
</g>
<text class="nj-charts-tick nj-charts-tick--l" x="8" y="472">time relative to the fastest fully validating library, less is better</text>
<g><rect class="nj-heat-0" x="8" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="46" y="496" text-anchor="middle">below 1.15</text></g>
<g><rect class="nj-heat-1" x="88" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="126" y="496" text-anchor="middle">1.15 to 1.5</text></g>
<g><rect class="nj-heat-2" x="168" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="206" y="496" text-anchor="middle">1.5 to 2.5</text></g>
<g><rect class="nj-heat-3" x="248" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="286" y="496" text-anchor="middle">2.5 to 5</text></g>
<g><rect class="nj-heat-4" x="328" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="366" y="496" text-anchor="middle">5 and more</text></g>
<rect class="nj-heat-na" x="420" y="482" width="40" height="20" rx="3"/>
<text class="nj-charts-tick" x="440" y="496">n/a</text>
<text class="nj-charts-tick nj-charts-tick--l" x="468" y="496">no A&#8203;PI for it</text>
</svg>

Before

Width:  |  Height:  |  Size: 46 KiB

@@ -1,374 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewBox="0 0 784 510" role="img" aria-labelledby="nj-blog-uc-x86-gcc nj-blog-uc-x86-gcc-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-uc-x86-gcc">Use cases: time of each library relative to the fastest, x86-64 with G&#8203;CC 16.2</title>
<desc id="nj-blog-uc-x86-gcc-d">Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.10; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.78 doing less, N); nlohmann/json json_document minify: 1.00 (0.78 doing less, N); nlohmann/json json_document write: 1.00 (0.64 doing less, N); yyjson validate: 2.23; yyjson sum: 1.31; yyjson select: 1.37; yyjson edit: 1.43; yyjson minify: 1.24 (0.99 doing less, N); yyjson write: 1.08; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.26 doing less, U); sonic-cpp select: no fully validating way (1.43 doing less, U); sonic-cpp edit: no fully validating way (1.18 doing less, U); sonic-cpp minify: no fully validating way (1.33 doing less, U); sonic-cpp write: 1.49; simdjson validate: 2.08; simdjson sum: 1.00; simdjson select: 1.29 (0.55 doing less, P); simdjson edit: n/a; simdjson minify: 1.49 (0.17 doing less, P); simdjson write: 2.09; sonic-rs (Rust) validate: 1.98; sonic-rs (Rust) sum: 1.14; sonic-rs (Rust) select: 1.36; sonic-rs (Rust) edit: 1.87; sonic-rs (Rust) minify: 1.68; sonic-rs (Rust) write: 2.05; Boost.J&#8203;SON validate: 1.98; Boost.J&#8203;SON sum: 1.29; Boost.J&#8203;SON select: 2.21; Boost.J&#8203;SON edit: 2.33; Boost.J&#8203;SON minify: 2.54; Boost.J&#8203;SON write: 2.33; nlohmann/json json validate: 1.69; nlohmann/json json sum: 1.17; nlohmann/json json select: 6.20; nlohmann/json json edit: 3.42; nlohmann/json json minify: 4.07; nlohmann/json json write: 1.84; simd-json (Rust) validate: 3.71; simd-json (Rust) sum: 1.93; simd-json (Rust) select: 2.59; simd-json (Rust) edit: 2.83; simd-json (Rust) minify: 3.30; simd-json (Rust) write: 2.34; serde_json (Rust) validate: 2.46 (2.19 doing less, U); serde_json (Rust) sum: 2.38; serde_json (Rust) select: 1.74; serde_json (Rust) edit: 4.45; serde_json (Rust) minify: 4.80; serde_json (Rust) write: 2.27; RapidJSON validate: 3.86 (3.48 doing less, U); RapidJSON sum: 2.35 (2.15 doing less, U); RapidJSON select: 3.17 (3.02 doing less, U); RapidJSON edit: 2.49 (2.40 doing less, U); RapidJSON minify: 2.58 (2.36 doing less, U N); RapidJSON write: 2.94; Glaze validate: 2.87; Glaze sum: 4.05; Glaze select: 1.71 (0.59 doing less, P); Glaze edit: 4.48; Glaze minify: 4.56 (0.75 doing less, P); Glaze write: 1.96.</desc>
<text class="nj-charts-tick" x="270" y="34">validate</text>
<text class="nj-charts-tick" x="362" y="34">sum</text>
<text class="nj-charts-tick" x="454" y="34">select</text>
<text class="nj-charts-tick" x="546" y="34">edit</text>
<text class="nj-charts-tick" x="638" y="34">minify</text>
<text class="nj-charts-tick" x="730" y="34">write</text>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="66" text-anchor="end">nlohmann/json json_document</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · validate&#10;1.00× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 254 µs&#10;citm_catalog.json: 515 µs&#10;canada.json: 892 µs&#10;jeopardy.json: 33,006 µs">
<rect class="nj-heat-0" x="225" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · sum&#10;1.10× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 384 µs&#10;citm_catalog.json: 1,066 µs&#10;canada.json: 3,526 µs&#10;jeopardy.json: 88,527 µs">
<rect class="nj-heat-0" x="317" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="66" text-anchor="middle">1.10</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · select&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 325 µs&#10;citm_catalog.json: 863 µs&#10;canada.json: 1,302 µs&#10;jeopardy.json: 87,940 µs">
<rect class="nj-heat-0" x="409" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit&#10;1.00× the time of the fastest library (fully validating)&#10;way: editable&#10;twitter.json: 538 µs&#10;citm_catalog.json: 1,214 µs&#10;canada.json: 5,640 µs&#10;jeopardy.json: 193,024 µs">
<rect class="nj-heat-0" x="501" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit, checking less&#10;0.78× the time of the fastest fully validating library&#10;twitter.json: 533 µs · editable (source numbers) (validates fully)&#10;citm_catalog.json: 1,214 µs · editable (validates fully)&#10;canada.json: 2,140 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 193,024 µs · editable (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="547" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="60" text-anchor="middle">0.78</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 478 µs&#10;citm_catalog.json: 1,152 µs&#10;canada.json: 5,209 µs&#10;jeopardy.json: 152,631 µs">
<rect class="nj-heat-0" x="593" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify, checking less&#10;0.78× the time of the fastest fully validating library&#10;way: parse + dump (source numbers)&#10;twitter.json: 467 µs (validates fully)&#10;citm_catalog.json: 1,118 µs (validates fully)&#10;canada.json: 2,150 µs (validates fully)&#10;jeopardy.json: 145,664 µs (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.78</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write&#10;1.00× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 154 µs&#10;citm_catalog.json: 251 µs&#10;canada.json: 3,946 µs&#10;jeopardy.json: 64,776 µs">
<rect class="nj-heat-0" x="685" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="707.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write, checking less&#10;0.64× the time of the fastest fully validating library&#10;way: dump (source numbers)&#10;twitter.json: 139 µs (validates fully)&#10;citm_catalog.json: 229 µs (validates fully)&#10;canada.json: 831 µs (validates fully)&#10;jeopardy.json: 62,866 µs (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="731" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="752.5" y="60" text-anchor="middle">0.64</text>
<text class="nj-charts-cell nj-charts-cell--small" x="752.5" y="73" text-anchor="middle">N</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="102" text-anchor="end">yyjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · validate&#10;2.23× the time of the fastest library (fully validating)&#10;twitter.json: 393 µs · read&#10;citm_catalog.json: 930 µs · read (raw numbers)&#10;canada.json: 2,140 µs · read (raw numbers)&#10;jeopardy.json: 122,230 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="225" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="102" text-anchor="middle">2.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.31× the time of the fastest library (fully validating)&#10;way: read&#10;twitter.json: 445 µs&#10;citm_catalog.json: 1,093 µs&#10;canada.json: 3,948 µs&#10;jeopardy.json: 133,860 µs">
<rect class="nj-heat-1" x="317" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="102" text-anchor="middle">1.31</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.37× the time of the fastest library (fully validating)&#10;twitter.json: 402 µs · read (raw numbers)&#10;citm_catalog.json: 954 µs · read&#10;canada.json: 2,127 µs · read (raw numbers)&#10;jeopardy.json: 140,491 µs · read">
<rect class="nj-heat-1" x="409" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="102" text-anchor="middle">1.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.43× the time of the fastest library (fully validating)&#10;twitter.json: 786 µs · mut copy&#10;citm_catalog.json: 1,642 µs · insitu (copy) + mut copy&#10;canada.json: 7,599 µs · insitu (copy) + mut copy&#10;jeopardy.json: 303,303 µs · mut copy&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="501" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="102" text-anchor="middle">1.43</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.24× the time of the fastest library (fully validating)&#10;twitter.json: 610 µs · read + write&#10;citm_catalog.json: 1,277 µs · read + write&#10;canada.json: 6,630 µs · read + write&#10;jeopardy.json: 199,086 µs · insitu (copy) + write&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="593" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="102" text-anchor="middle">1.24</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;0.99× the time of the fastest fully validating library&#10;twitter.json: 609 µs · read (raw numbers) + write (validates fully)&#10;citm_catalog.json: 1,221 µs · read (raw numbers) + write (validates fully)&#10;canada.json: 2,860 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 199,086 µs · insitu (copy) + write (validates fully)&#10;copies each number&#x27;s text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-0" x="639" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="96" text-anchor="middle">0.99</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="109" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · write&#10;1.08× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 185 µs&#10;citm_catalog.json: 318 µs&#10;canada.json: 3,330 µs&#10;jeopardy.json: 67,531 µs">
<rect class="nj-heat-0" x="685" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="102" text-anchor="middle">1.08</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="138" text-anchor="end">sonic-cpp</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · validate, checking less&#10;2.32× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 404 µs&#10;citm_catalog.json: 923 µs&#10;canada.json: 3,216 µs&#10;jeopardy.json: 93,142 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="225" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="132" text-anchor="middle">2.32</text>
<text class="nj-charts-cell nj-charts-cell--small" x="270" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · sum, checking less&#10;1.26× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 458 µs&#10;citm_catalog.json: 1,120 µs&#10;canada.json: 3,887 µs&#10;jeopardy.json: 107,494 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="317" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="132" text-anchor="middle">1.26</text>
<text class="nj-charts-cell nj-charts-cell--small" x="362" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · select, checking less&#10;1.43× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 408 µs&#10;citm_catalog.json: 942 µs&#10;canada.json: 3,166 µs&#10;jeopardy.json: 110,763 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="409" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="132" text-anchor="middle">1.43</text>
<text class="nj-charts-cell nj-charts-cell--small" x="454" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · edit, checking less&#10;1.18× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 620 µs&#10;citm_catalog.json: 1,426 µs&#10;canada.json: 8,466 µs&#10;jeopardy.json: 181,035 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="501" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="132" text-anchor="middle">1.18</text>
<text class="nj-charts-cell nj-charts-cell--small" x="546" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · minify, checking less&#10;1.33× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 636 µs&#10;citm_catalog.json: 1,498 µs&#10;canada.json: 8,354 µs&#10;jeopardy.json: 173,180 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="593" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="132" text-anchor="middle">1.33</text>
<text class="nj-charts-cell nj-charts-cell--small" x="638" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · write&#10;1.49× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 258 µs&#10;citm_catalog.json: 508 µs&#10;canada.json: 5,077 µs&#10;jeopardy.json: 72,262 µs">
<rect class="nj-heat-1" x="685" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="138" text-anchor="middle">1.49</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="174" text-anchor="end">simdjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · validate&#10;2.08× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 297 µs&#10;citm_catalog.json: 687 µs&#10;canada.json: 3,165 µs&#10;jeopardy.json: 111,631 µs">
<rect class="nj-heat-2" x="225" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="174" text-anchor="middle">2.08</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · sum&#10;1.00× the time of the fastest library (fully validating)&#10;way: On-Demand&#10;twitter.json: 344 µs&#10;citm_catalog.json: 809 µs&#10;canada.json: 3,405 µs&#10;jeopardy.json: 90,960 µs">
<rect class="nj-heat-0" x="317" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="174" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select&#10;1.29× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 311 µs&#10;citm_catalog.json: 698 µs&#10;canada.json: 3,141 µs&#10;jeopardy.json: 130,228 µs">
<rect class="nj-heat-1" x="409" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="174" text-anchor="middle">1.29</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.55× the time of the fastest fully validating library&#10;twitter.json: 178 µs · On-Demand&#10;citm_catalog.json: 494 µs · On-Demand (key selectors)&#10;canada.json: 674 µs · On-Demand&#10;jeopardy.json: 48,492 µs · On-Demand&#10;reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets">
<rect class="nj-heat-0" x="455" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="168" text-anchor="middle">0.55</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · edit&#10;simdjson&#x27;s documents are read-only: it has no A&#8203;PI to change a value and write the result">
<rect class="nj-heat-na" x="501" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-tick" x="546" y="174">n/a</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify&#10;1.49× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 666 µs&#10;citm_catalog.json: 1,354 µs&#10;canada.json: 8,606 µs&#10;jeopardy.json: 280,739 µs">
<rect class="nj-heat-1" x="593" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="174" text-anchor="middle">1.49</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify, checking less&#10;0.17× the time of the fastest fully validating library&#10;way: minify&#10;twitter.json: 93.3 µs&#10;citm_catalog.json: 279 µs&#10;canada.json: 314 µs&#10;jeopardy.json: 46,006 µs&#10;simdjson::minify() only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="168" text-anchor="middle">0.17</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · write&#10;2.09× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 346 µs&#10;citm_catalog.json: 610 µs&#10;canada.json: 5,580 µs&#10;jeopardy.json: 158,670 µs">
<rect class="nj-heat-2" x="685" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="174" text-anchor="middle">2.09</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="210" text-anchor="end">sonic-rs (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · validate&#10;1.98× the time of the fastest library (fully validating)&#10;way: IgnoredAny&#10;twitter.json: 501 µs&#10;citm_catalog.json: 970 µs&#10;canada.json: 2,249 µs&#10;jeopardy.json: 54,369 µs">
<rect class="nj-heat-2" x="225" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="210" text-anchor="middle">1.98</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.14× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 501 µs&#10;citm_catalog.json: 1,123 µs&#10;canada.json: 4,397 µs&#10;jeopardy.json: 59,583 µs">
<rect class="nj-heat-0" x="317" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="210" text-anchor="middle">1.14</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.36× the time of the fastest library (fully validating)&#10;way: structs&#10;twitter.json: 504 µs&#10;citm_catalog.json: 1,033 µs&#10;canada.json: 2,328 µs&#10;jeopardy.json: 90,486 µs">
<rect class="nj-heat-1" x="409" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="210" text-anchor="middle">1.36</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · edit&#10;1.87× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,197 µs&#10;citm_catalog.json: 2,389 µs&#10;canada.json: 7,744 µs&#10;jeopardy.json: 390,952 µs">
<rect class="nj-heat-2" x="501" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="210" text-anchor="middle">1.87</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · minify&#10;1.68× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,000 µs&#10;citm_catalog.json: 2,097 µs&#10;canada.json: 7,795 µs&#10;jeopardy.json: 215,280 µs">
<rect class="nj-heat-2" x="593" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="210" text-anchor="middle">1.68</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;2.05× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 434 µs&#10;citm_catalog.json: 927 µs&#10;canada.json: 3,987 µs&#10;jeopardy.json: 109,176 µs">
<rect class="nj-heat-2" x="685" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="210" text-anchor="middle">2.05</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="246" text-anchor="end">Boost.J&#8203;SON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · validate&#10;1.98× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 683 µs&#10;citm_catalog.json: 913 µs&#10;canada.json: 1,642 µs&#10;jeopardy.json: 57,932 µs">
<rect class="nj-heat-2" x="225" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="246" text-anchor="middle">1.98</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.29× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 690 µs&#10;citm_catalog.json: 956 µs&#10;canada.json: 5,762 µs&#10;jeopardy.json: 62,051 µs">
<rect class="nj-heat-1" x="317" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="246" text-anchor="middle">1.29</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.21× the time of the fastest library (fully validating)&#10;twitter.json: 883 µs · parse_into structs&#10;citm_catalog.json: 1,286 µs · parse_into structs&#10;canada.json: 6,690 µs · parse&#10;jeopardy.json: 101,286 µs · parse_into structs">
<rect class="nj-heat-2" x="409" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="246" text-anchor="middle">2.21</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.33× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,859 µs&#10;citm_catalog.json: 2,513 µs&#10;canada.json: 12,765 µs&#10;jeopardy.json: 348,703 µs">
<rect class="nj-heat-2" x="501" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="246" text-anchor="middle">2.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;2.54× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,783 µs&#10;citm_catalog.json: 2,498 µs&#10;canada.json: 12,367 µs&#10;jeopardy.json: 329,300 µs">
<rect class="nj-heat-3" x="593" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="246" text-anchor="middle">2.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;2.33× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 451 µs&#10;citm_catalog.json: 832 µs&#10;canada.json: 5,570 µs&#10;jeopardy.json: 138,780 µs">
<rect class="nj-heat-2" x="685" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="246" text-anchor="middle">2.33</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="282" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;1.69× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 370 µs&#10;citm_catalog.json: 883 µs&#10;canada.json: 2,441 µs&#10;jeopardy.json: 39,142 µs">
<rect class="nj-heat-2" x="225" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">1.69</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.17× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 533 µs&#10;citm_catalog.json: 1,113 µs&#10;canada.json: 4,134 µs&#10;jeopardy.json: 66,403 µs">
<rect class="nj-heat-1" x="317" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.17</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;6.20× the time of the fastest library (fully validating)&#10;twitter.json: 2,984 µs · parse&#10;citm_catalog.json: 4,548 µs · parse&#10;canada.json: 9,124 µs · structs (from_json)&#10;jeopardy.json: 383,108 µs · parse">
<rect class="nj-heat-4" x="409" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">6.20</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.42× the time of the fastest library (fully validating)&#10;twitter.json: 2,535 µs · ordered_json&#10;citm_catalog.json: 4,484 µs · ordered_json&#10;canada.json: 13,526 µs · parse&#10;jeopardy.json: 635,912 µs · ordered_json">
<rect class="nj-heat-3" x="501" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">3.42</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.07× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 3,369 µs&#10;citm_catalog.json: 5,399 µs&#10;canada.json: 13,402 µs&#10;jeopardy.json: 493,302 µs">
<rect class="nj-heat-3" x="593" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">4.07</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.84× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 413 µs&#10;citm_catalog.json: 611 µs&#10;canada.json: 3,905 µs&#10;jeopardy.json: 113,990 µs">
<rect class="nj-heat-2" x="685" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">1.84</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.71× the time of the fastest library (fully validating)&#10;way: tape (copy)&#10;twitter.json: 567 µs&#10;citm_catalog.json: 1,430 µs&#10;canada.json: 4,359 µs&#10;jeopardy.json: 207,551 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="318" text-anchor="middle">3.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.93× the time of the fastest library (fully validating)&#10;way: visitor (copy)&#10;twitter.json: 681 µs&#10;citm_catalog.json: 1,650 µs&#10;canada.json: 5,083 µs&#10;jeopardy.json: 210,185 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="317" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">1.93</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.59× the time of the fastest library (fully validating)&#10;way: structs (copy)&#10;twitter.json: 679 µs&#10;citm_catalog.json: 1,731 µs&#10;canada.json: 5,144 µs&#10;jeopardy.json: 239,164 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="318" text-anchor="middle">2.59</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.83× the time of the fastest library (fully validating)&#10;twitter.json: 1,862 µs · borrowed (copy)&#10;citm_catalog.json: 4,194 µs · borrowed (copy)&#10;canada.json: 14,896 µs · owned (copy)&#10;jeopardy.json: 391,369 µs · borrowed (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">2.83</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.30× the time of the fastest library (fully validating)&#10;way: borrowed (copy)&#10;twitter.json: 1,889 µs&#10;citm_catalog.json: 4,196 µs&#10;canada.json: 15,716 µs&#10;jeopardy.json: 414,377 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="593" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="318" text-anchor="middle">3.30</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.34× the time of the fastest library (fully validating)&#10;way: borrowed&#10;twitter.json: 582 µs&#10;citm_catalog.json: 800 µs&#10;canada.json: 5,147 µs&#10;jeopardy.json: 122,623 µs">
<rect class="nj-heat-2" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.34</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="354" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.46× the time of the fastest library (fully validating)&#10;way: from_utf8 + IgnoredAny&#10;twitter.json: 624 µs&#10;citm_catalog.json: 1,440 µs&#10;canada.json: 2,406 µs&#10;jeopardy.json: 64,720 µs">
<rect class="nj-heat-2" x="225" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="354" text-anchor="middle">2.46</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;2.19× the time of the fastest fully validating library&#10;way: IgnoredAny&#10;twitter.json: 484 µs&#10;citm_catalog.json: 1,370 µs&#10;canada.json: 2,314 µs&#10;jeopardy.json: 58,247 µs&#10;trusts U&#8203;TF-8 in the strings it skips (from_slice); strings it reads are checked">
<rect class="nj-heat-2" x="271" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="348" text-anchor="middle">2.19</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="361" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.38× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 1,311 µs&#10;citm_catalog.json: 2,288 µs&#10;canada.json: 7,127 µs&#10;jeopardy.json: 129,497 µs">
<rect class="nj-heat-2" x="317" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">2.38</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;1.74× the time of the fastest library (fully validating)&#10;way: from_utf8 + structs&#10;twitter.json: 701 µs&#10;citm_catalog.json: 1,532 µs&#10;canada.json: 2,529 µs&#10;jeopardy.json: 107,316 µs">
<rect class="nj-heat-2" x="409" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="354" text-anchor="middle">1.74</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.45× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,042 µs&#10;citm_catalog.json: 6,586 µs&#10;canada.json: 16,631 µs&#10;jeopardy.json: 632,766 µs">
<rect class="nj-heat-3" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">4.45</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;4.80× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,012 µs&#10;citm_catalog.json: 6,583 µs&#10;canada.json: 17,306 µs&#10;jeopardy.json: 509,702 µs">
<rect class="nj-heat-3" x="593" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="354" text-anchor="middle">4.80</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.27× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 550 µs&#10;citm_catalog.json: 887 µs&#10;canada.json: 4,005 µs&#10;jeopardy.json: 134,163 µs">
<rect class="nj-heat-2" x="685" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="354" text-anchor="middle">2.27</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="390" text-anchor="end">RapidJSON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate&#10;3.86× the time of the fastest library (fully validating)&#10;twitter.json: 1,215 µs · insitu (copy)&#10;citm_catalog.json: 1,550 µs · S&#8203;AX (string stream, default precision)&#10;canada.json: 3,625 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 125,139 µs · S&#8203;AX (string stream, default precision)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="390" text-anchor="middle">3.86</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.48× the time of the fastest fully validating library&#10;twitter.json: 1,052 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,427 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 3,625 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 104,342 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="271" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="384" text-anchor="middle">3.48</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum&#10;2.35× the time of the fastest library (fully validating)&#10;twitter.json: 1,256 µs · insitu (copy)&#10;citm_catalog.json: 1,713 µs · S&#8203;AX (string stream)&#10;canada.json: 9,547 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 127,564 µs · S&#8203;AX (string stream)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="317" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="390" text-anchor="middle">2.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.15× the time of the fastest fully validating library&#10;twitter.json: 1,099 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,635 µs · S&#8203;AX (string stream) (no encoding check)&#10;canada.json: 9,105 µs · S&#8203;AX (string stream) (no encoding check)&#10;jeopardy.json: 113,500 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="363" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="384" text-anchor="middle">2.15</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select&#10;3.17× the time of the fastest library (fully validating)&#10;twitter.json: 1,217 µs · insitu (copy)&#10;citm_catalog.json: 1,807 µs · insitu (copy)&#10;canada.json: 9,688 µs · Document (string stream)&#10;jeopardy.json: 152,275 µs · Document (string stream)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="390" text-anchor="middle">3.17</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.02× the time of the fastest fully validating library&#10;twitter.json: 1,056 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,767 µs · insitu (copy) (no encoding check)&#10;canada.json: 9,632 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 148,964 µs · Document (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="455" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="384" text-anchor="middle">3.02</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit&#10;2.49× the time of the fastest library (fully validating)&#10;twitter.json: 1,896 µs · insitu (copy)&#10;citm_catalog.json: 2,754 µs · insitu (copy)&#10;canada.json: 19,359 µs · Document (string stream)&#10;jeopardy.json: 269,071 µs · Document (string stream)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="501" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="390" text-anchor="middle">2.49</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.40× the time of the fastest fully validating library&#10;twitter.json: 1,749 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 2,730 µs · insitu (copy) (no encoding check)&#10;canada.json: 19,155 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 259,148 µs · Document (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="547" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="384" text-anchor="middle">2.40</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="397" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify&#10;2.58× the time of the fastest library (fully validating)&#10;way: S&#8203;AX to Writer (string stream)&#10;twitter.json: 1,851 µs&#10;citm_catalog.json: 2,429 µs&#10;canada.json: 18,810 µs&#10;jeopardy.json: 229,769 µs">
<rect class="nj-heat-3" x="593" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="390" text-anchor="middle">2.58</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;2.36× the time of the fastest fully validating library&#10;twitter.json: 1,710 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;citm_catalog.json: 2,429 µs · S&#8203;AX to Writer (string stream) (validates fully)&#10;canada.json: 14,205 µs · S&#8203;AX to Writer (raw numbers) (validates fully)&#10;jeopardy.json: 229,769 µs · S&#8203;AX to Writer (string stream) (validates fully)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;copies each number&#x27;s text instead of formatting it (kParseNumbersAsStringsFlag)">
<rect class="nj-heat-2" x="639" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="384" text-anchor="middle">2.36</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="397" text-anchor="middle">U N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · write&#10;2.94× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 638 µs&#10;citm_catalog.json: 984 µs&#10;canada.json: 8,886 µs&#10;jeopardy.json: 131,435 µs">
<rect class="nj-heat-3" x="685" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="390" text-anchor="middle">2.94</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="426" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.87× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 705 µs&#10;citm_catalog.json: 1,971 µs&#10;canada.json: 2,532 µs&#10;jeopardy.json: 74,805 µs">
<rect class="nj-heat-3" x="225" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="426" text-anchor="middle">2.87</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.05× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,317 µs&#10;citm_catalog.json: 4,068 µs&#10;canada.json: 10,333 µs&#10;jeopardy.json: 237,723 µs">
<rect class="nj-heat-3" x="317" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="426" text-anchor="middle">4.05</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.71× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 608 µs&#10;citm_catalog.json: 1,978 µs&#10;canada.json: 2,521 µs&#10;jeopardy.json: 90,807 µs">
<rect class="nj-heat-2" x="409" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="426" text-anchor="middle">1.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.59× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 345 µs&#10;citm_catalog.json: 401 µs&#10;canada.json: 415 µs&#10;jeopardy.json: 67,456 µs&#10;reads into structs and steps over fields it doesn&#x27;t know without checking them (validate_skipped checks them too)">
<rect class="nj-heat-0" x="455" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="420" text-anchor="middle">0.59</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="433" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;4.48× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,364 µs&#10;citm_catalog.json: 6,036 µs&#10;canada.json: 21,592 µs&#10;jeopardy.json: 652,302 µs">
<rect class="nj-heat-3" x="501" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="426" text-anchor="middle">4.48</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;4.56× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,243 µs&#10;citm_catalog.json: 6,175 µs&#10;canada.json: 20,961 µs&#10;jeopardy.json: 451,368 µs">
<rect class="nj-heat-3" x="593" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="426" text-anchor="middle">4.56</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;0.75× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 417 µs&#10;citm_catalog.json: 1,299 µs&#10;canada.json: 2,699 µs&#10;jeopardy.json: 93,794 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="420" text-anchor="middle">0.75</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="433" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;1.96× the time of the fastest library (fully validating)&#10;way: generic&#10;twitter.json: 377 µs&#10;citm_catalog.json: 730 µs&#10;canada.json: 4,050 µs&#10;jeopardy.json: 129,720 µs">
<rect class="nj-heat-2" x="685" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="426" text-anchor="middle">1.96</text>
</g>
<text class="nj-charts-tick nj-charts-tick--l" x="8" y="472">time relative to the fastest fully validating library, less is better</text>
<g><rect class="nj-heat-0" x="8" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="46" y="496" text-anchor="middle">below 1.15</text></g>
<g><rect class="nj-heat-1" x="88" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="126" y="496" text-anchor="middle">1.15 to 1.5</text></g>
<g><rect class="nj-heat-2" x="168" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="206" y="496" text-anchor="middle">1.5 to 2.5</text></g>
<g><rect class="nj-heat-3" x="248" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="286" y="496" text-anchor="middle">2.5 to 5</text></g>
<g><rect class="nj-heat-4" x="328" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="366" y="496" text-anchor="middle">5 and more</text></g>
<rect class="nj-heat-na" x="420" y="482" width="40" height="20" rx="3"/>
<text class="nj-charts-tick" x="440" y="496">n/a</text>
<text class="nj-charts-tick nj-charts-tick--l" x="468" y="496">no A&#8203;PI for it</text>
</svg>

Before

Width:  |  Height:  |  Size: 46 KiB

@@ -1,379 +0,0 @@
<svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewBox="0 0 784 510" role="img" aria-labelledby="nj-blog-uc-x86-gcc13 nj-blog-uc-x86-gcc13-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-uc-x86-gcc13">Use cases: time of each library relative to the fastest, x86-64 with G&#8203;CC 13</title>
<desc id="nj-blog-uc-x86-gcc13-d">Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.10; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.82 doing less, N); nlohmann/json json_document minify: 1.00 (0.81 doing less, N); nlohmann/json json_document write: 1.00 (0.71 doing less, N); yyjson validate: 2.06; yyjson sum: 1.44; yyjson select: 1.37; yyjson edit: 1.57; yyjson minify: 1.37 (1.03 doing less, N); yyjson write: 1.08; sonic-cpp validate: no fully validating way (2.21 doing less, U); sonic-cpp sum: no fully validating way (1.28 doing less, U); sonic-cpp select: no fully validating way (1.48 doing less, U); sonic-cpp edit: no fully validating way (1.22 doing less, U); sonic-cpp minify: no fully validating way (1.40 doing less, U); sonic-cpp write: 1.50; simdjson validate: 1.93; simdjson sum: 1.00; simdjson select: 1.29 (0.56 doing less, P); simdjson edit: n/a; simdjson minify: 1.55 (0.21 doing less, P); simdjson write: 2.09; sonic-rs (Rust) validate: 1.77; sonic-rs (Rust) sum: 1.13; sonic-rs (Rust) select: 1.33; sonic-rs (Rust) edit: 1.86; sonic-rs (Rust) minify: 1.71; sonic-rs (Rust) write: 2.00; Boost.J&#8203;SON validate: 1.83; Boost.J&#8203;SON sum: 1.30; Boost.J&#8203;SON select: 2.23; Boost.J&#8203;SON edit: 2.45; Boost.J&#8203;SON minify: 2.83; Boost.J&#8203;SON write: 2.50; nlohmann/json json validate: 1.34; nlohmann/json json sum: 1.04; nlohmann/json json select: 6.05; nlohmann/json json edit: 3.37; nlohmann/json json minify: 4.13; nlohmann/json json write: 1.85; simd-json (Rust) validate: 3.31; simd-json (Rust) sum: 1.91; simd-json (Rust) select: 2.54; simd-json (Rust) edit: 2.82; simd-json (Rust) minify: 3.35; simd-json (Rust) write: 2.28; serde_json (Rust) validate: 2.19 (1.96 doing less, U); serde_json (Rust) sum: 2.35; serde_json (Rust) select: 1.70; serde_json (Rust) edit: 4.44; serde_json (Rust) minify: 4.88; serde_json (Rust) write: 2.21; Glaze validate: 2.05; Glaze sum: 4.06 (3.93 doing less, P); Glaze select: 1.39 (0.58 doing less, P); Glaze edit: 4.71; Glaze minify: 4.96 (0.70 doing less, P); Glaze write: 1.80; RapidJSON validate: 3.88 (3.36 doing less, U); RapidJSON sum: 2.67 (2.34 doing less, U); RapidJSON select: 3.39 (3.12 doing less, U); RapidJSON edit: 2.65 (2.52 doing less, U); RapidJSON minify: 3.64 (2.61 doing less, U N); RapidJSON write: 2.95.</desc>
<text class="nj-charts-tick" x="270" y="34">validate</text>
<text class="nj-charts-tick" x="362" y="34">sum</text>
<text class="nj-charts-tick" x="454" y="34">select</text>
<text class="nj-charts-tick" x="546" y="34">edit</text>
<text class="nj-charts-tick" x="638" y="34">minify</text>
<text class="nj-charts-tick" x="730" y="34">write</text>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="66" text-anchor="end">nlohmann/json json_document</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · validate&#10;1.00× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 267 µs&#10;citm_catalog.json: 664 µs&#10;canada.json: 986 µs&#10;jeopardy.json: 34,874 µs">
<rect class="nj-heat-0" x="225" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · sum&#10;1.10× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 387 µs&#10;citm_catalog.json: 1,036 µs&#10;canada.json: 3,704 µs&#10;jeopardy.json: 89,477 µs">
<rect class="nj-heat-0" x="317" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="66" text-anchor="middle">1.10</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · select&#10;1.00× the time of the fastest library (fully validating)&#10;twitter.json: 329 µs · structs (from_json)&#10;citm_catalog.json: 855 µs · parse&#10;canada.json: 1,360 µs · structs (from_json)&#10;jeopardy.json: 90,597 µs · parse">
<rect class="nj-heat-0" x="409" y="45" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit&#10;1.00× the time of the fastest library (fully validating)&#10;way: editable&#10;twitter.json: 530 µs&#10;citm_catalog.json: 1,209 µs&#10;canada.json: 5,792 µs&#10;jeopardy.json: 193,925 µs">
<rect class="nj-heat-0" x="501" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · edit, checking less&#10;0.82× the time of the fastest fully validating library&#10;twitter.json: 530 µs · editable (validates fully)&#10;citm_catalog.json: 1,209 µs · editable (validates fully)&#10;canada.json: 2,621 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 193,925 µs · editable (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="547" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="60" text-anchor="middle">0.82</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify&#10;1.00× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 475 µs&#10;citm_catalog.json: 1,102 µs&#10;canada.json: 5,414 µs&#10;jeopardy.json: 144,877 µs">
<rect class="nj-heat-0" x="593" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · minify, checking less&#10;0.81× the time of the fastest fully validating library&#10;twitter.json: 471 µs · parse + dump (source numbers) (validates fully)&#10;citm_catalog.json: 1,102 µs · parse + dump (validates fully)&#10;canada.json: 2,372 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 144,877 µs · parse + dump (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.81</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="73" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write&#10;1.00× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 152 µs&#10;citm_catalog.json: 260 µs&#10;canada.json: 3,811 µs&#10;jeopardy.json: 72,196 µs">
<rect class="nj-heat-0" x="685" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="707.5" y="66" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json_document · write, checking less&#10;0.71× the time of the fastest fully validating library&#10;twitter.json: 147 µs · dump (source numbers) (validates fully)&#10;citm_catalog.json: 260 µs · dump (validates fully)&#10;canada.json: 997 µs · dump (source numbers) (validates fully)&#10;jeopardy.json: 71,822 µs · dump (source numbers) (validates fully)&#10;copies each number&#x27;s text instead of formatting it (number_format::source)">
<rect class="nj-heat-0" x="731" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="752.5" y="60" text-anchor="middle">0.71</text>
<text class="nj-charts-cell nj-charts-cell--small" x="752.5" y="73" text-anchor="middle">N</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="102" text-anchor="end">yyjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · validate&#10;2.06× the time of the fastest library (fully validating)&#10;twitter.json: 394 µs · insitu (copy)&#10;citm_catalog.json: 984 µs · read&#10;canada.json: 2,222 µs · read (raw numbers)&#10;jeopardy.json: 128,528 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="225" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="102" text-anchor="middle">2.06</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.44× the time of the fastest library (fully validating)&#10;twitter.json: 443 µs · insitu (copy)&#10;citm_catalog.json: 1,146 µs · insitu (copy)&#10;canada.json: 5,974 µs · read&#10;jeopardy.json: 129,054 µs · read&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="317" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="102" text-anchor="middle">1.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.37× the time of the fastest library (fully validating)&#10;twitter.json: 397 µs · read&#10;citm_catalog.json: 994 µs · insitu (copy)&#10;canada.json: 2,228 µs · read (raw numbers)&#10;jeopardy.json: 140,073 µs · read (raw numbers)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="409" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="102" text-anchor="middle">1.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.57× the time of the fastest library (fully validating)&#10;twitter.json: 841 µs · insitu (copy) + mut copy&#10;citm_catalog.json: 1,719 µs · mut copy&#10;canada.json: 9,803 µs · insitu (copy) + mut copy&#10;jeopardy.json: 309,935 µs · insitu (copy) + mut copy&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="501" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="102" text-anchor="middle">1.57</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.37× the time of the fastest library (fully validating)&#10;twitter.json: 600 µs · insitu (copy) + write&#10;citm_catalog.json: 1,316 µs · insitu (copy) + write&#10;canada.json: 9,151 µs · read + write&#10;jeopardy.json: 201,645 µs · read + write&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-1" x="593" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="102" text-anchor="middle">1.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;1.03× the time of the fastest fully validating library&#10;twitter.json: 600 µs · read (raw numbers) + write (validates fully)&#10;citm_catalog.json: 1,264 µs · read (raw numbers) + write (validates fully)&#10;canada.json: 2,994 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 201,645 µs · read + write (validates fully)&#10;copies each number&#x27;s text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)">
<rect class="nj-heat-0" x="639" y="81" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="96" text-anchor="middle">1.03</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="109" text-anchor="middle">N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · write&#10;1.08× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 180 µs&#10;citm_catalog.json: 325 µs&#10;canada.json: 3,548 µs&#10;jeopardy.json: 71,044 µs">
<rect class="nj-heat-0" x="685" y="81" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="102" text-anchor="middle">1.08</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="138" text-anchor="end">sonic-cpp</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · validate, checking less&#10;2.21× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 409 µs&#10;citm_catalog.json: 1,025 µs&#10;canada.json: 3,561 µs&#10;jeopardy.json: 96,607 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-2" x="225" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="132" text-anchor="middle">2.21</text>
<text class="nj-charts-cell nj-charts-cell--small" x="270" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · sum, checking less&#10;1.28× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 459 µs&#10;citm_catalog.json: 1,209 µs&#10;canada.json: 4,247 µs&#10;jeopardy.json: 103,731 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="317" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="132" text-anchor="middle">1.28</text>
<text class="nj-charts-cell nj-charts-cell--small" x="362" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · select, checking less&#10;1.48× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 412 µs&#10;citm_catalog.json: 1,044 µs&#10;canada.json: 3,632 µs&#10;jeopardy.json: 106,188 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="409" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="132" text-anchor="middle">1.48</text>
<text class="nj-charts-cell nj-charts-cell--small" x="454" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · edit, checking less&#10;1.22× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 632 µs&#10;citm_catalog.json: 1,583 µs&#10;canada.json: 8,734 µs&#10;jeopardy.json: 184,592 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="501" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="132" text-anchor="middle">1.22</text>
<text class="nj-charts-cell nj-charts-cell--small" x="546" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · minify, checking less&#10;1.40× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 647 µs&#10;citm_catalog.json: 1,563 µs&#10;canada.json: 8,917 µs&#10;jeopardy.json: 176,625 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-1" x="593" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="132" text-anchor="middle">1.40</text>
<text class="nj-charts-cell nj-charts-cell--small" x="638" y="145" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-cpp · write&#10;1.50× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 268 µs&#10;citm_catalog.json: 543 µs&#10;canada.json: 5,057 µs&#10;jeopardy.json: 75,734 µs">
<rect class="nj-heat-2" x="685" y="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="138" text-anchor="middle">1.50</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="174" text-anchor="end">simdjson</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · validate&#10;1.93× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 309 µs&#10;citm_catalog.json: 737 µs&#10;canada.json: 3,183 µs&#10;jeopardy.json: 115,296 µs">
<rect class="nj-heat-2" x="225" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="174" text-anchor="middle">1.93</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · sum&#10;1.00× the time of the fastest library (fully validating)&#10;way: On-Demand&#10;twitter.json: 356 µs&#10;citm_catalog.json: 819 µs&#10;canada.json: 3,291 µs&#10;jeopardy.json: 94,267 µs">
<rect class="nj-heat-0" x="317" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="174" text-anchor="middle">1.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select&#10;1.29× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 323 µs&#10;citm_catalog.json: 748 µs&#10;canada.json: 3,189 µs&#10;jeopardy.json: 126,288 µs">
<rect class="nj-heat-1" x="409" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="174" text-anchor="middle">1.29</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.56× the time of the fastest fully validating library&#10;twitter.json: 186 µs · On-Demand&#10;citm_catalog.json: 508 µs · On-Demand&#10;canada.json: 707 µs · On-Demand&#10;jeopardy.json: 50,215 µs · On-Demand (key selectors)&#10;reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets">
<rect class="nj-heat-0" x="455" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="168" text-anchor="middle">0.56</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · edit&#10;simdjson&#x27;s documents are read-only: it has no A&#8203;PI to change a value and write the result">
<rect class="nj-heat-na" x="501" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-tick" x="546" y="174">n/a</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify&#10;1.55× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 689 µs&#10;citm_catalog.json: 1,394 µs&#10;canada.json: 8,457 µs&#10;jeopardy.json: 292,576 µs">
<rect class="nj-heat-2" x="593" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="174" text-anchor="middle">1.55</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify, checking less&#10;0.21× the time of the fastest fully validating library&#10;way: minify&#10;twitter.json: 122 µs&#10;citm_catalog.json: 336 µs&#10;canada.json: 426 µs&#10;jeopardy.json: 49,731 µs&#10;simdjson::minify() only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="153" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="168" text-anchor="middle">0.21</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="181" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · write&#10;2.09× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 360 µs&#10;citm_catalog.json: 636 µs&#10;canada.json: 5,363 µs&#10;jeopardy.json: 169,032 µs">
<rect class="nj-heat-2" x="685" y="153" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="174" text-anchor="middle">2.09</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="210" text-anchor="end">sonic-rs (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · validate&#10;1.77× the time of the fastest library (fully validating)&#10;way: IgnoredAny&#10;twitter.json: 501 µs&#10;citm_catalog.json: 970 µs&#10;canada.json: 2,249 µs&#10;jeopardy.json: 54,369 µs">
<rect class="nj-heat-2" x="225" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="210" text-anchor="middle">1.77</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.13× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 501 µs&#10;citm_catalog.json: 1,123 µs&#10;canada.json: 4,397 µs&#10;jeopardy.json: 59,583 µs">
<rect class="nj-heat-0" x="317" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="210" text-anchor="middle">1.13</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.33× the time of the fastest library (fully validating)&#10;way: structs&#10;twitter.json: 504 µs&#10;citm_catalog.json: 1,033 µs&#10;canada.json: 2,328 µs&#10;jeopardy.json: 90,486 µs">
<rect class="nj-heat-1" x="409" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="210" text-anchor="middle">1.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · edit&#10;1.86× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,197 µs&#10;citm_catalog.json: 2,389 µs&#10;canada.json: 7,744 µs&#10;jeopardy.json: 390,952 µs">
<rect class="nj-heat-2" x="501" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="210" text-anchor="middle">1.86</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · minify&#10;1.71× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 1,000 µs&#10;citm_catalog.json: 2,097 µs&#10;canada.json: 7,795 µs&#10;jeopardy.json: 215,280 µs">
<rect class="nj-heat-2" x="593" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="210" text-anchor="middle">1.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;2.00× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 434 µs&#10;citm_catalog.json: 927 µs&#10;canada.json: 3,987 µs&#10;jeopardy.json: 109,176 µs">
<rect class="nj-heat-2" x="685" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="210" text-anchor="middle">2.00</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="246" text-anchor="end">Boost.J&#8203;SON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · validate&#10;1.83× the time of the fastest library (fully validating)&#10;twitter.json: 730 µs · S&#8203;AX (numbers: none)&#10;citm_catalog.json: 934 µs · S&#8203;AX (numbers: none)&#10;canada.json: 1,637 µs · S&#8203;AX (numbers: none)&#10;jeopardy.json: 60,745 µs · S&#8203;AX">
<rect class="nj-heat-2" x="225" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="246" text-anchor="middle">1.83</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.30× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 746 µs&#10;citm_catalog.json: 1,025 µs&#10;canada.json: 5,370 µs&#10;jeopardy.json: 63,333 µs">
<rect class="nj-heat-1" x="317" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="246" text-anchor="middle">1.30</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.23× the time of the fastest library (fully validating)&#10;twitter.json: 899 µs · parse_into structs&#10;citm_catalog.json: 1,353 µs · parse_into structs&#10;canada.json: 7,011 µs · parse&#10;jeopardy.json: 100,039 µs · parse_into structs">
<rect class="nj-heat-2" x="409" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="246" text-anchor="middle">2.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.45× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,889 µs&#10;citm_catalog.json: 2,952 µs&#10;canada.json: 13,537 µs&#10;jeopardy.json: 346,542 µs">
<rect class="nj-heat-2" x="501" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="246" text-anchor="middle">2.45</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;2.83× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,907 µs&#10;citm_catalog.json: 2,950 µs&#10;canada.json: 13,662 µs&#10;jeopardy.json: 342,183 µs">
<rect class="nj-heat-3" x="593" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="246" text-anchor="middle">2.83</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;2.50× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 474 µs&#10;citm_catalog.json: 1,003 µs&#10;canada.json: 6,012 µs&#10;jeopardy.json: 148,120 µs">
<rect class="nj-heat-2" x="685" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="246" text-anchor="middle">2.50</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="282" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;1.34× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 312 µs&#10;citm_catalog.json: 686 µs&#10;canada.json: 2,345 µs&#10;jeopardy.json: 38,948 µs">
<rect class="nj-heat-1" x="225" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">1.34</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.04× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 451 µs&#10;citm_catalog.json: 941 µs&#10;canada.json: 3,816 µs&#10;jeopardy.json: 64,406 µs">
<rect class="nj-heat-0" x="317" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.04</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;6.05× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 3,032 µs&#10;citm_catalog.json: 4,466 µs&#10;canada.json: 9,085 µs&#10;jeopardy.json: 376,812 µs">
<rect class="nj-heat-4" x="409" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">6.05</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.37× the time of the fastest library (fully validating)&#10;twitter.json: 2,503 µs · ordered_json&#10;citm_catalog.json: 4,414 µs · ordered_json&#10;canada.json: 13,479 µs · parse&#10;jeopardy.json: 622,816 µs · ordered_json">
<rect class="nj-heat-3" x="501" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">3.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.13× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 3,417 µs&#10;citm_catalog.json: 5,153 µs&#10;canada.json: 13,425 µs&#10;jeopardy.json: 504,511 µs">
<rect class="nj-heat-3" x="593" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">4.13</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.85× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 413 µs&#10;citm_catalog.json: 617 µs&#10;canada.json: 4,036 µs&#10;jeopardy.json: 124,865 µs">
<rect class="nj-heat-2" x="685" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">1.85</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.31× the time of the fastest library (fully validating)&#10;way: tape (copy)&#10;twitter.json: 567 µs&#10;citm_catalog.json: 1,430 µs&#10;canada.json: 4,359 µs&#10;jeopardy.json: 207,551 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="318" text-anchor="middle">3.31</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.91× the time of the fastest library (fully validating)&#10;way: visitor (copy)&#10;twitter.json: 681 µs&#10;citm_catalog.json: 1,650 µs&#10;canada.json: 5,083 µs&#10;jeopardy.json: 210,185 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="317" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">1.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.54× the time of the fastest library (fully validating)&#10;way: structs (copy)&#10;twitter.json: 679 µs&#10;citm_catalog.json: 1,731 µs&#10;canada.json: 5,144 µs&#10;jeopardy.json: 239,164 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="318" text-anchor="middle">2.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.82× the time of the fastest library (fully validating)&#10;twitter.json: 1,862 µs · borrowed (copy)&#10;citm_catalog.json: 4,194 µs · borrowed (copy)&#10;canada.json: 14,896 µs · owned (copy)&#10;jeopardy.json: 391,369 µs · borrowed (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">2.82</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.35× the time of the fastest library (fully validating)&#10;way: borrowed (copy)&#10;twitter.json: 1,889 µs&#10;citm_catalog.json: 4,196 µs&#10;canada.json: 15,716 µs&#10;jeopardy.json: 414,377 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="593" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="318" text-anchor="middle">3.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.28× the time of the fastest library (fully validating)&#10;way: borrowed&#10;twitter.json: 582 µs&#10;citm_catalog.json: 800 µs&#10;canada.json: 5,147 µs&#10;jeopardy.json: 122,623 µs">
<rect class="nj-heat-2" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.28</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="354" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.19× the time of the fastest library (fully validating)&#10;way: from_utf8 + IgnoredAny&#10;twitter.json: 624 µs&#10;citm_catalog.json: 1,440 µs&#10;canada.json: 2,406 µs&#10;jeopardy.json: 64,720 µs">
<rect class="nj-heat-2" x="225" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="354" text-anchor="middle">2.19</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;1.96× the time of the fastest fully validating library&#10;way: IgnoredAny&#10;twitter.json: 484 µs&#10;citm_catalog.json: 1,370 µs&#10;canada.json: 2,314 µs&#10;jeopardy.json: 58,247 µs&#10;trusts U&#8203;TF-8 in the strings it skips (from_slice); strings it reads are checked">
<rect class="nj-heat-2" x="271" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="348" text-anchor="middle">1.96</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="361" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.35× the time of the fastest library (fully validating)&#10;way: visitor&#10;twitter.json: 1,311 µs&#10;citm_catalog.json: 2,288 µs&#10;canada.json: 7,127 µs&#10;jeopardy.json: 129,497 µs">
<rect class="nj-heat-2" x="317" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">2.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;1.70× the time of the fastest library (fully validating)&#10;way: from_utf8 + structs&#10;twitter.json: 701 µs&#10;citm_catalog.json: 1,532 µs&#10;canada.json: 2,529 µs&#10;jeopardy.json: 107,316 µs">
<rect class="nj-heat-2" x="409" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="354" text-anchor="middle">1.70</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.44× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,042 µs&#10;citm_catalog.json: 6,586 µs&#10;canada.json: 16,631 µs&#10;jeopardy.json: 632,766 µs">
<rect class="nj-heat-3" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">4.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;4.88× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 4,012 µs&#10;citm_catalog.json: 6,583 µs&#10;canada.json: 17,306 µs&#10;jeopardy.json: 509,702 µs">
<rect class="nj-heat-3" x="593" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="354" text-anchor="middle">4.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.21× the time of the fastest library (fully validating)&#10;way: Value&#10;twitter.json: 550 µs&#10;citm_catalog.json: 887 µs&#10;canada.json: 4,005 µs&#10;jeopardy.json: 134,163 µs">
<rect class="nj-heat-2" x="685" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="354" text-anchor="middle">2.21</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="390" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.05× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 584 µs&#10;citm_catalog.json: 1,402 µs&#10;canada.json: 1,837 µs&#10;jeopardy.json: 71,382 µs">
<rect class="nj-heat-2" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.05</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.06× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,341 µs&#10;citm_catalog.json: 4,037 µs&#10;canada.json: 10,434 µs&#10;jeopardy.json: 249,828 µs">
<rect class="nj-heat-3" x="317" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="390" text-anchor="middle">4.06</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum, checking less&#10;3.93× the time of the fastest fully validating library&#10;twitter.json: 2,341 µs · generic (double, strict) (validates fully)&#10;citm_catalog.json: 4,037 µs · generic (double, strict) (validates fully)&#10;canada.json: 10,434 µs · generic (double, strict) (validates fully)&#10;jeopardy.json: 219,119 µs · lazy_json&#10;reads lazily: lazy_json reads only what you ask for and steps over the rest">
<rect class="nj-heat-3" x="363" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="384" text-anchor="middle">3.93</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.39× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 523 µs&#10;citm_catalog.json: 1,473 µs&#10;canada.json: 1,853 µs&#10;jeopardy.json: 89,506 µs">
<rect class="nj-heat-1" x="409" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="390" text-anchor="middle">1.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.58× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 338 µs&#10;citm_catalog.json: 406 µs&#10;canada.json: 434 µs&#10;jeopardy.json: 66,029 µs&#10;reads into structs and steps over fields it doesn&#x27;t know without checking them (validate_skipped checks them too)">
<rect class="nj-heat-0" x="455" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="384" text-anchor="middle">0.58</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;4.71× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,474 µs&#10;citm_catalog.json: 6,531 µs&#10;canada.json: 23,193 µs&#10;jeopardy.json: 673,526 µs">
<rect class="nj-heat-3" x="501" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="390" text-anchor="middle">4.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;4.96× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,359 µs&#10;citm_catalog.json: 6,437 µs&#10;canada.json: 23,896 µs&#10;jeopardy.json: 480,814 µs">
<rect class="nj-heat-3" x="593" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="390" text-anchor="middle">4.96</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;0.70× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 417 µs&#10;citm_catalog.json: 1,116 µs&#10;canada.json: 2,113 µs&#10;jeopardy.json: 97,812 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="369" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="384" text-anchor="middle">0.70</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="397" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;1.80× the time of the fastest library (fully validating)&#10;way: generic&#10;twitter.json: 336 µs&#10;citm_catalog.json: 682 µs&#10;canada.json: 3,750 µs&#10;jeopardy.json: 133,730 µs">
<rect class="nj-heat-2" x="685" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="390" text-anchor="middle">1.80</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="426" text-anchor="end">RapidJSON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate&#10;3.88× the time of the fastest library (fully validating)&#10;twitter.json: 1,201 µs · insitu (copy)&#10;citm_catalog.json: 1,931 µs · insitu (copy)&#10;canada.json: 4,114 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 145,137 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="225" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="426" text-anchor="middle">3.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.36× the time of the fastest fully validating library&#10;twitter.json: 1,033 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,487 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 3,966 µs · S&#8203;AX (string stream, default precision) (no encoding check)&#10;jeopardy.json: 127,587 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="271" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="420" text-anchor="middle">3.36</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum&#10;2.67× the time of the fastest library (fully validating)&#10;twitter.json: 1,256 µs · insitu (copy)&#10;citm_catalog.json: 2,114 µs · insitu (copy)&#10;canada.json: 11,059 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 155,532 µs · insitu (copy)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="317" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="426" text-anchor="middle">2.67</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.34× the time of the fastest fully validating library&#10;twitter.json: 1,085 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,750 µs · S&#8203;AX (no encoding check)&#10;canada.json: 11,008 µs · S&#8203;AX (string stream) (no encoding check)&#10;jeopardy.json: 128,734 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-2" x="363" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="420" text-anchor="middle">2.34</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select&#10;3.39× the time of the fastest library (fully validating)&#10;way: insitu (copy)&#10;twitter.json: 1,207 µs&#10;citm_catalog.json: 1,947 µs&#10;canada.json: 11,910 µs&#10;jeopardy.json: 164,386 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="409" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="426" text-anchor="middle">3.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.12× the time of the fastest fully validating library&#10;twitter.json: 1,037 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 1,847 µs · insitu (copy) (no encoding check)&#10;canada.json: 11,692 µs · Document (no encoding check)&#10;jeopardy.json: 147,489 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="455" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="420" text-anchor="middle">3.12</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit&#10;2.65× the time of the fastest library (fully validating)&#10;way: insitu (copy)&#10;twitter.json: 1,920 µs&#10;citm_catalog.json: 2,977 µs&#10;canada.json: 21,152 µs&#10;jeopardy.json: 293,851 µs&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="501" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="426" text-anchor="middle">2.65</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.52× the time of the fastest fully validating library&#10;twitter.json: 1,747 µs · insitu (copy) (no encoding check)&#10;citm_catalog.json: 2,823 µs · insitu (copy) (no encoding check)&#10;canada.json: 20,998 µs · Document (no encoding check)&#10;jeopardy.json: 280,165 µs · insitu (copy) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;(copy): parses in place, on a copy of the input that is part of the time">
<rect class="nj-heat-3" x="547" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="420" text-anchor="middle">2.52</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="433" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify&#10;3.64× the time of the fastest library (fully validating)&#10;twitter.json: 2,746 µs · S&#8203;AX to Writer (string stream)&#10;citm_catalog.json: 3,162 µs · S&#8203;AX to Writer (string stream)&#10;canada.json: 21,674 µs · S&#8203;AX to Writer&#10;jeopardy.json: 381,832 µs · S&#8203;AX to Writer (string stream)">
<rect class="nj-heat-3" x="593" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="426" text-anchor="middle">3.64</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;2.61× the time of the fastest fully validating library&#10;twitter.json: 1,824 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;citm_catalog.json: 2,672 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;canada.json: 15,166 µs · S&#8203;AX to Writer (raw numbers) (no encoding check)&#10;jeopardy.json: 259,100 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)&#10;copies each number&#x27;s text instead of formatting it (kParseNumbersAsStringsFlag)">
<rect class="nj-heat-3" x="639" y="405" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="420" text-anchor="middle">2.61</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="433" text-anchor="middle">U N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · write&#10;2.95× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 661 µs&#10;citm_catalog.json: 1,015 µs&#10;canada.json: 8,980 µs&#10;jeopardy.json: 136,957 µs">
<rect class="nj-heat-3" x="685" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="426" text-anchor="middle">2.95</text>
</g>
<text class="nj-charts-tick nj-charts-tick--l" x="8" y="472">time relative to the fastest fully validating library, less is better</text>
<g><rect class="nj-heat-0" x="8" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="46" y="496" text-anchor="middle">below 1.15</text></g>
<g><rect class="nj-heat-1" x="88" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="126" y="496" text-anchor="middle">1.15 to 1.5</text></g>
<g><rect class="nj-heat-2" x="168" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="206" y="496" text-anchor="middle">1.5 to 2.5</text></g>
<g><rect class="nj-heat-3" x="248" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="286" y="496" text-anchor="middle">2.5 to 5</text></g>
<g><rect class="nj-heat-4" x="328" y="482" width="76" height="20" rx="3"/>
<text class="nj-charts-cell nj-charts-cell--small" x="366" y="496" text-anchor="middle">5 and more</text></g>
<rect class="nj-heat-na" x="420" y="482" width="40" height="20" rx="3"/>
<text class="nj-charts-tick" x="440" y="496">n/a</text>
<text class="nj-charts-tick nj-charts-tick--l" x="468" y="496">no A&#8203;PI for it</text>
</svg>

Before

Width:  |  Height:  |  Size: 46 KiB

+2 -2
View File
@@ -58,7 +58,7 @@ Clang).
anything, or link a library. Put the file in a directory named `nlohmann` that is on your include path (for
example `third_party/nlohmann/json.hpp` with `-I third_party`), so that `#include <nlohmann/json.hpp>` works.
Download the companion headers listed below only if you use them: `json_view.hpp` for the
[zero-copy views](../features/json_view.md), `json_fwd.hpp` for forward declarations, and `json_literals.hpp` if
[zero-copy views](../features/json_view/index.md), `json_fwd.hpp` for forward declarations, and `json_literals.hpp` if
you define `JSON_NO_AUTOMATIC_UDLS`. Keep them in the same `nlohmann` directory.
Do not copy only parts of the repository's `include/` directory: the headers in it include each other and must be
@@ -75,7 +75,7 @@ for the user-defined string literals if you define
For the read-only, non-owning [`basic_json_document`](../api/basic_json_document/index.md)/[`basic_json_view`](../api/basic_json_view/index.md)
types, additionally include
[`single_include/nlohmann/json_view.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_view.hpp);
see [Zero-copy JSON views](../features/json_view.md).
see [Zero-copy JSON views](../features/json_view/index.md).
## Notes for builds and distribution
+2 -3
View File
@@ -1,8 +1,7 @@
/*
* Marks links that leave the site with the class "nj-external", which brand.css turns into a small icon in front of
* the link. A link is external when its host is neither the current one nor the production site. Links in the page
* actions (edit, raw), buttons, header anchors, a blog post's byline, and links that only wrap an image (badges) are
* left alone.
* actions (edit, raw), buttons, header anchors, and links that only wrap an image (badges) are left alone.
* Runs through Material's document$ (navigation.instant), so it also applies after an instant page switch.
*/
(function () {
@@ -18,7 +17,7 @@
if (a.protocol !== "http:" && a.protocol !== "https:") {
continue;
}
if (a.matches(".md-button, .md-content__button, .headerlink, .nj-byline a") || a.querySelector("img, svg")) {
if (a.matches(".md-button, .md-content__button, .headerlink") || a.querySelector("img, svg")) {
continue;
}
a.classList.add("nj-external");
-69
View File
@@ -104,72 +104,3 @@
init();
}
})();
/* figures: the tooltips of the heatmaps in home/blog/how_3_13_0_got_faster.md (perf_blog_usecases_*.svg). Each
cell is a focusable <g data-tip>: its lines (the first one the heading) are shown on hover, keyboard focus or tap.
Without JS, the figure's <desc> and the tables in the appendix carry the same numbers. */
(function () {
"use strict";
var tip = null;
var current = null;
function show(cell) {
if (!tip) {
tip = document.createElement("div");
tip.className = "nj-heat-tip";
tip.setAttribute("role", "tooltip");
tip.hidden = true;
document.body.appendChild(tip);
}
if (current) current.classList.remove("nj-heat-on");
current = cell;
cell.classList.add("nj-heat-on");
var lines = (cell.getAttribute("data-tip") || "").split("\n");
tip.textContent = "";
lines.forEach(function (line, i) {
var el = document.createElement(i === 0 ? "strong" : "div");
el.textContent = line;
tip.appendChild(el);
});
tip.hidden = false;
var r = cell.getBoundingClientRect();
var w = tip.offsetWidth, h = tip.offsetHeight;
var x = Math.min(Math.max(8, r.left + r.width / 2 - w / 2), document.documentElement.clientWidth - w - 8);
var y = r.bottom + 8 + h > window.innerHeight ? r.top - h - 8 : r.bottom + 8;
tip.style.left = (x + window.scrollX) + "px";
tip.style.top = (y + window.scrollY) + "px";
}
function hide() {
if (current) current.classList.remove("nj-heat-on");
current = null;
if (tip) tip.hidden = true;
}
function init() {
hide();
Array.prototype.forEach.call(document.querySelectorAll("svg.nj-charts--heat .nj-heat-cell"), function (cell) {
if (cell.dataset.njHeatReady) return;
cell.dataset.njHeatReady = "1";
cell.addEventListener("mouseenter", function () { show(cell); });
cell.addEventListener("mouseleave", hide);
cell.addEventListener("focus", function () { show(cell); });
cell.addEventListener("blur", hide);
// a tap also focuses the cell; a tap elsewhere or Escape hides the tooltip
cell.addEventListener("click", function (ev) { ev.stopPropagation(); show(cell); });
});
}
document.addEventListener("click", hide);
document.addEventListener("keydown", function (ev) { if (ev.key === "Escape") hide(); });
window.addEventListener("scroll", hide, { passive: true });
if (typeof document$ !== "undefined" && document$ && typeof document$.subscribe === "function") {
document$.subscribe(init);
} else if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();
Loaded 100 of 130 files, more files were not shown because too many files have changed in this diff. Show more