Compare commits

..
Author SHA1 Message Date
Niels Lohmann 379756e92e json_view: no byte range in exceptions about a removed value
#5990 dropped the found flag from diagnostics(), reasoning that a value
value_path() does not find leaves no tokens, like the root. But the node
of a value that is no longer part of the document still holds the bytes
it had in the source, so with JSON_DIAGNOSTICS and
JSON_DIAGNOSTIC_POSITIONS its exceptions gained "(bytes 1-4)" for text
that is no longer there. The test #5997 added for exactly this case
(unit-json_view_positions.cpp, "views of values that are no longer part
of the document") has failed on develop since both were merged.

Restore the flag: a value that is not found gets no context, the root
keeps its byte range.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 19:08:09 +01:00
Niels Lohmann b18b6fc7e6 Build the parser's syntax error prefix with one concat() (#6013)
Since #6004 made the "while parsing" part unconditional, the three appends
at the start of exception_message() are one fixed string around the
context. Review follow-up to #6004.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 18:27:08 +01:00
Niels Lohmann 6d5581c4e8 CBOR/MessagePack readers: leave one-element arrays to the general path (#6008)
enter_cbor_array and enter_msgpack_array called the out-of-line scalar
run for every non-empty array. When the array's element is an object or
an array, as on every level of [[...]] or the single ring of a GeoJSON
polygon, the call reads nothing; it made 1,000 arrays nested in each
other cost 4 % more instructions (GCC 13) and up to 8 % more time (Apple
clang) than without the run. #5975 had fixed that with an inline
pre-check, which was later dropped after measuring canada only.

The run is now entered only for arrays of two or more elements: the same
comparison as before, so no other row changes. Arrays of one scalar,
which the run read faster, now take the general path; they are rare in
documents (one in citm_catalog, none in twitter or canada). The new
benchmark FromBinaryShape/singles measures them, next to
FromBinaryShape/nested.

Instructions per repetition, new/old, GCC 13 callgrind: nested arrays
0.973 (CBOR) and 0.971 (MessagePack), arrays of one scalar 1.037 and
1.021, every other row within 0.15 %.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 18:25:44 +01:00
Niels LohmannandClaude 590b622d48 parse(): propagate std::bad_alloc instead of crashing on a half-constructed member (#5991)
* Create the DOM parser's member value before placing it (#5985)

json_sax_dom_parser::set_member() constructed the new value in place over
the null member. basic_json(value_t) sets the type before the json_value
allocates, so a std::bad_alloc left a member typed object/array with a
null pointer, and the destructor crashed instead of propagating the
exception. Construct the value first and move it over the member (the
move constructor is noexcept).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix CI for the parse() bad_alloc sweep test (#5985)

- sweep_allocator: provide max_size(), construct() and destroy(), which
  GCC 4.8's std::map calls on the allocator directly.
- Declare the non-throwing test lambdas noexcept (-Werror=noexcept on
  recent GCC).
- Give the sax_parse lambda an explicit return type; Clang 3.4 crashes on
  the deduced one in C++11 mode.
- Skip the parser callback sweep with iterator debugging (MSVC debug
  builds, clang-cl), where containers allocate debug proxies inside
  noexcept move constructors and terminate instead of throwing, as in the
  other allocator tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* Construct a scalar member in place; only a throwing value goes through a temporary

Creating the value first and moving it over the member is needed only when
creating it can throw (a string, a binary value or a container). A scalar
or null is again constructed in place, without the extra move and destroy
per member (and, with JSON_DIAGNOSTICS, without the extra set_parents()).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Spell the nothrow trait without && and fix the construct_member comments

The dispatch in set_member tests std::is_nothrow_constructible, not
whether the value is a scalar. Say so in the comments, and drop the &&
from the trait argument (equivalent for a forwarding reference) so that
astyle no longer inserts spaces around the template brackets.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Say "for example" in the construct_member comments

The overloads are selected by std::is_nothrow_constructible, not by the
kind of value: a custom type that cannot throw takes the first one.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 18:25:30 +01:00
Niels Lohmann 100f676b3e Restore the two commits of #6005 that the stack merge dropped (fixes the build of develop) (#6012)
* basic_json, iterators, serializer: remove checks that invariants make dead

Branch coverage of the test suite and of 24k mutated inputs showed
these conditions as never taken; each is implied by the code around it:

- copy_object_level(): `src_it != src_object.cend()`; dst was built from
  exactly src_object.size() unique keys and src_it advances at most once
  per member
- the general comparison operators (equal_general, less_general,
  three_way_general): the five same-type scalar cases, which the inline
  fast path of every operator handles before calling them (now an
  assert); and the NaN half of compares_unordered() in the mixed-type
  branch, reached only after all six number pairs returned, where only
  a discarded operand is unordered
- serializer, ensure_ascii: the reset of `bytes` under error_handler_t::keep
  and the surrogate-pair escape in the UTF8_ACCEPT case; every
  well-formed multi-byte character is escaped by write_u_escapes() before
  decode() sees it, so decode() only ever accepts DEL here, a single byte
  of which nothing was buffered (now asserts)
- iter_impl(pointer): the if/else chain assigned value-initialized
  iterators to the value-initialized m_it

No change in behaviour: a build that aborts on each removed side passes
the test suite, the fuzz corpora and 23.2M dumps of all 1-, 2- and
boundary 4-byte strings in both ensure_ascii modes.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* iter_impl: keep the type-dependent initialization in the constructor

The check is not needed for correctness (m_it is value-initialized), but
without it GCC 13 generates slower iteration loops: a recursive walk over
a parsed document takes 0.5-2.7 % longer (callgrind: +1.9 % instructions
on twitter.json, +0.95 % on canada.json). Clang generates identical code
either way. See the measurements in #6005.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 18:23:44 +01:00
dependabot[bot] bd067fd08c Bump mkdocs-git-revision-date-localized-plugin in /docs/mkdocs (#6011)
Bumps [mkdocs-git-revision-date-localized-plugin](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin) from 1.6.0 to 1.6.2.
- [Release notes](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin/releases)
- [Commits](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin/compare/v1.6.0...v1.6.2)

---
updated-dependencies:
- dependency-name: mkdocs-git-revision-date-localized-plugin
  dependency-version: 1.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-02 17:57:02 +01:00
Niels Lohmann 3354436ec4 json_view: remove checks that invariants make dead (#6006)
Branch coverage of the test suite and of 24k mutated inputs showed
these conditions as never taken; each is implied by the code around it:

- view_serializer::write_codepoint<EnsureAscii>(): the only caller
  passes the byte a run of plain output stopped at (a quote, a
  backslash or a control character), so the function is now
  write_escaped(), which writes that byte's escape sequence
- load_image(): `owned_image.empty() || image != owned_image.data()`;
  both callers hand in a fresh document_data, and for load(vector&&)
  the image is owned_image itself
- set_moved(): reserve_moved(); all three callers reserved first or
  have the moved flag set (the documented precondition)
- view_side::string() and json_side::string() in equal(): only used
  after both sides were found to be strings, so they read the string
  directly (and are noexcept)
- number<false>(): the '1'..'9' test after a sign-less dispatch, which
  only happens for a digit
- value_range(): the pre-loop `is_new || off >= size` test, which the
  loop's first pass repeats on the same node

No change in behaviour: a build that aborts on each removed side passes
the test suite and the fuzz corpora.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 17:54:40 +01:00
Niels Lohmann 596028c460 Drop the null_result parameter JSON_IMPLEMENT_OPERATOR no longer uses (#6005)
Without the same-type scalar cases, the macro body has no use for it, and
JSON_IMPLEMENT_SCALAR_CASES is now used only by JSON_IMPLEMENT_SCALAR_FAST.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 17:54:39 +01:00
Niels Lohmann 5c4f585ac2 Lexer, parser, stream adapter, SAX: remove checks that invariants make dead (#6004)
Branch coverage of the test suite and of 24k mutated inputs showed
these conditions as never taken; each is implied by the code around it:

- lexer: `next_unget` in get_codepoint_bulk() and scan_literal_bulk().
  unget() is only called at the end of scan_number(), in scan_comment()
  and in skip_bom(); every token scan starts with a plain get() in
  skip_whitespace() that consumes a pending unget, and nothing between
  that get() and the bulk helpers ungets (now asserts, as in
  get_after_string_run())
- lexer: `number_type == value_integer` in convert_integer(): both
  callers exclude value_float and the type has three values
- parser: `!context.empty()` in exception_message(): all callers pass a
  literal
- input_stream_adapter: `refill` in get_character_slow(): the function
  is only called after get_character() found the get area exhausted,
  and the variable recomputed that comparison
- json_sax_dom_callback_parser: `ref_stack.back()` in key() (the null
  case returned a few lines earlier, and the callback in between cannot
  reach ref_stack), `is_structured()` in end_object() (non-null entries
  are only pushed for objects and arrays), `!key_stack.empty()` in
  current_key() (a kept object pushed its key before any value)

No change in behaviour: a build that aborts on each removed side passes
the test suite, the fuzz corpora and 40k random documents through every
input adapter in four macro configurations.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 17:54:39 +01:00
Niels LohmannandClaude Opus 5.5 1d69ef9ab4 Raise line coverage to 99.9 %: fix the measurement, remove unreachable code, add tests (#5997)
* CI: measure line coverage without lcov's unexecuted-block adjustment

Drop geninfo_unexecuted_blocks=1 from the lcov capture of ci_test_coverage:
it reset every line of an inlined or templated function to 0 as soon as one
copy had an unexecuted block, which understated the line coverage by about
three points.

Add -fvar-tracking-assignments to both coverage builds. At -O0, GCC inlines
always_inline functions before it places the coverage counters, so the call
sites of such helpers (put_literal() and others) got no line record and
showed as 0 in an -O3 translation unit that never reaches them. With the
flag, the call sites carry counts in every translation unit. The generated
code is identical.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Remove unreachable code found by the coverage analysis

Remove code that no input can reach, and mark the lines that cannot be
covered with LCOV_EXCL_LINE:

- BJData writer: the dry_run parameter of the ND-array element writers was
  always true; replace them by range checks.
- BON8 writer: call throw_integer_out_of_range() directly instead of
  write_bon8_value() for values that always throw.
- binary_writer: integer_bits() is only called for integers of up to 64 bits.
- serializer, view serializer, lexer: replace guards that the callers make
  unreachable by assertions or by the simpler code (surrogate pairs under
  ensure_ascii, next_unget, '-' at the end of the buffer).
- json_view: drop unreachable branches in scalar(), set(), check_utf8_scan(),
  append_input_impl() and unescape().
- Mark exception-cleanup braces, 2 GiB limits, big-endian and 32-bit code, and
  fall-through case labels with LCOV_EXCL_LINE.

No behavior changes for any input that reaches these functions.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Tests: cover the remaining lines of the library headers

Add tests for the lines of include/nlohmann that were not covered: the
binary readers and writers, the lexer and locale paths, the json_view
modules, the custom number, key and array types, json_pointer, json_patch,
diff and the iterators.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix test failures in the coverage tests

- unit-custom-object-key-type: remove the unused make_strict_key(strict_key)
  overload, the unused range constructor and default constructor, and guard
  data() with JSON_DIAGNOSTICS (unused-function/-member-function errors with
  GCC and clang -Weverything).
- unit-json_view_compare: move the two new sections to the new
  unit-json_view_compare_values.cpp, as the object file got too large for the
  MinGW assembler again, and use a std::map with std::greater instead of
  std::unordered_map, which does not accept the incomplete basic_json
  (clang 3.9, icpc).
- unit-json_view_dump: rename the variables that hid outer ones (MSVC C4456).
- unit-stream-bulk-scan: restore the real size of the oversized get area
  before the adapter is destroyed (JSON_PRECISE_STREAM_POSITION reads the
  character at the read position), and skip the test where the streambuf
  cannot hold a get area larger than an int (MSVC).
- unit-regression1: with JSON_NO_THREAD_LOCAL, copies are built member by
  member and keep correct timestamps, so check the corresponding outcome.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* Return std::size_t from the hash helper in the ordered_json test

MSVC (Win32) rejected the implicit conversion of the unsigned long long
product to the 32-bit std::size_t (C4244 as an error). Also note when
JSON_NO_THREAD_LOCAL is set in the regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:54:38 +01:00
Niels Lohmann ff0bdfdef3 Keep the byte range in exceptions about the root value (#5990)
* Keep the byte range in exceptions about the root value (#5987)

With JSON_DIAGNOSTICS and JSON_DIAGNOSTIC_POSITIONS both set, exception::diagnostics()
and the json_view diagnostics() returned early for a value without a path (the
root), dropping "(bytes a-b)". Build the "(path) " prefix only when there are
tokens and always append the byte range.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Guard the null value of a value-initialized iterator; drop the unneeded found flag

With the root's byte range, diagnostics() reaches get_byte_positions() also
with JSON_DIAGNOSTICS when there is no value, as for a value-initialized
iterator (invalid_iterator.212). get_byte_positions() now returns no range
for a null value, the same change as #6003, so either can be merged first.

In the view, a value that value_path() does not find leaves no tokens, so the
found flag added nothing to the tokens.empty() test.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 17:50:40 +01:00
dependabot[bot] 7328310136 Bump mkdocs-material from 9.7.7 to 9.8.0 in /docs/mkdocs (#6010)
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.7.7 to 9.8.0.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.7.7...9.8.0)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-version: 9.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-02 17:48:55 +01:00
Niels LohmannandClaude Opus 5.5 bfe69c73c2 json_view: get<T>() of a boolean throws for the exact number types, as basic_json does (#5992)
* json_view: get<T>() of a boolean throws for number_integer_t, number_unsigned_t and number_float_t like basic_json (#5988)

basic_json::get<T>() of a boolean throws type_error.302 for exactly
number_integer_t, number_unsigned_t and number_float_t (dedicated from_json()
overloads) and gives 0/1 for every other arithmetic type. The view returned
0/1 for all of them, contradicting its documentation. The view now throws
the same exception (same message, with path/bytes decoration) for these three
types. basic_json is unchanged; its behavior is documented and pinned by a test.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* tests: skip throwing json_view bool get<T>() combinations without exceptions (#5988)

check_boolean_get_parity() called get<T>() for number_integer_t,
number_unsigned_t and number_float_t in its JSON_NOEXCEPTION branch, but a
boolean throws type_error.302 for exactly these types, so JSON_THROW aborted
test-json_view_cpp11/cpp17 in ci_test_noexceptions. Skip these combinations
there; the throwing checks stay in the exceptions-enabled build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* Expect the byte range of the root in the json_view boolean get<T>() test

With JSON_DIAGNOSTIC_POSITIONS, the type_error.302 message starts with
"(bytes 0-4)"; build the expected text with json_view_test::message(),
as the other tests of the root value do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:48:43 +01:00
Niels LohmannandClaude 494a74c242 insert(): strong guarantee for single elements, basic guarantee for the rest (#5996)
* Make basic_json::insert() provide its documented strong exception guarantee (#5986)

A failed allocation while the new elements were copied left the value
changed, and with JSON_DIAGNOSTICS stale parent pointers behind. The
extra work now happens almost only on the failure path:

- Array insert(pos, cnt, val) and insert(pos, first, last) append the
  copies at the end and rotate them into place. If a copy throws, the
  appended elements are erased again (noexcept) and the parents are set.
  Moving a basic_json cannot throw, so reallocation is safe. This is no
  slower than vector::insert (faster for numbers), needs no temporary
  array, and keeps the elements that libstdc++ lost on reallocation.
- Array insert(pos, val) copies a non-scalar value first and inserts it
  by move, except at the end, where vector::insert is strong. Scalars
  keep the direct path.
- The object range insert(first, last) into an empty object uses the
  container's own range insertion and clears the object on an exception.
  Into a non-empty object it inserts member by member and logs one bit
  per source member (a new member is detected by the size change; no
  allocation for the first 256 members); on an exception the members
  added are erased by walking the source range. No assumption that
  key_type is string_t.
- The parents are set when a failed insertion is undone.

The regression test fails every allocation of every insert() overload in
turn, for json and ordered_json, and checks the value and its parents.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix clang-tidy and -Wnrvo findings in insert rollback helpers

Declare the rollback helpers non-movable, replace the nested conditional
and C array in object_insert_rollback, silence the intentional copy in the
allocator test, and avoid the missed NRVO in the test factory lambda.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* insert(): strong guarantee for single elements, basic for the rest

Rework of the previous two commits, following the discussion in #5996:
the standard containers give the strong guarantee only for a single
element (std::vector: at the end, or if the exception does not come from
copying T; std::map: single-element insert), and copying a basic_json
allocates. Rebuilding a rollback for the count, range and object-range
overloads on top of array_t/object_t made the code verbose and slower.

- insert(pos, const basic_json&): at end() forward as before (the
  standard covers it); elsewhere copy first and insert by move, as
  libstdc++ does internally (libc++ shifts the tail before copying).
- insert_iterator() and object insert(first, last) set the parents in a
  scope guard, so a failed insertion leaves a valid value with
  JSON_DIAGNOSTICS too (the next assert_invariant() aborted before).
- Docs: strong guarantee for (1), basic guarantee for (2)-(5); the
  argument checks throw before anything is changed.
- Test: allocation-failure sweep checks the strong guarantee for (1) and
  validity, type and parents for the other overloads.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* insert(): document the exception safety of overloads 2 to 5 once

The four basic-guarantee statements were identical up to array/object.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* insert(): simplify the wording of the basic guarantee

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:48:29 +01:00
Niels LohmannandClaude Opus 5.5 bdc737db6d json_view: dump() without StringType::capacity() (#5999)
* json_view: dump() without StringType::capacity() (#5994)

output_buffer::grow() compared the output size with m_out.capacity(),
which the StringType requirements do not include, so dump() did not
compile with the tests' alt_string. Keep what was last reserved in the
buffer itself and use it as a lower bound of the capacity instead.

Add json_view tests with alt_string (read-only and editable documents,
dump with several growth steps, save/load), and document reserve(n) and
resize(n) as the StringType requirements of basic_json_view::dump.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Use a raw string literal in the alt-string json_view test

clang-tidy (modernize-raw-string-literal) rejects the escaped literal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:48:16 +01:00
Niels LohmannandClaude 66e2eeeec0 Do not construct the base class when destroying a container (#6000)
* Do not construct the base class when destroying a container (#5995)

json_value::destroy_container() and destroy_walk() used default-
constructed basic_json values as stand-ins, which construct a
CustomBaseClass that belongs to no value. A base class whose default
constructor allocates made the noexcept destructor allocate again, and
terminate if that allocation failed, which #5762 set out to prevent.

Use data (type and value, no base class) as the stand-in instead, and
pass the children's m_data to the walk helpers.

Add a test with a counting base class: destroying a value constructs no
base object and destroys exactly one per value, also for values nested
deeper than the recursion depth limit.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Release the test value with = nullptr instead of reset()

clang-tidy (readability-ambiguous-smartptr-reset-call) rejects j.reset()
because the pointee inherits a reset() from counting_base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* Use std::swap for the container stand-in in destroy_container

The unqualified call after `using std::swap` would let a user-provided
swap(json_value&, json_value&) intercept the destruction path. Call
std::swap directly.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:48:03 +01:00
Niels LohmannandClaude Opus 5.5 03d408aafa JSON_DIAGNOSTIC_POSITIONS: comparing a value-initialized iterator throws instead of crashing (#6003)
* JSON_DIAGNOSTIC_POSITIONS: comparing a value-initialized iterator throws instead of crashing

With JSON_DIAGNOSTIC_POSITIONS, comparing a value-initialized iterator
(which has no container) with another iterator built the
invalid_iterator.212 message from the byte positions of the iterator's
value, which is a null pointer: UBSan reports "member call on null
pointer" in exception::get_byte_positions(), then the process crashes.
Every other configuration throws invalid_iterator.212.

get_byte_positions() now returns no positions for a null value, as the
JSON_DIAGNOSTICS path already does.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Declare the value-initialized iterator in the test const

clang-tidy (misc-const-correctness) flags it, as it is only compared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:47:48 +01:00
Niels LohmannandClaude Opus 5.5 76dbe8f9c9 Fix the red CI on develop: Visual Studio 2017 build of the BSON writer, Valgrind timeouts (#6009)
* CI: give the Valgrind tests a timeout of one hour

Under Valgrind, test-json_view_builder_cpp11 and test-ordered_json_cpp11
took 1435 s and 1390 s on develop (ddc34f5), close to ctest's default
timeout of 1500 s. On the next run (b2674a4) the whole job was about 10 %
slower and both timed out, failing ci_test_valgrind on develop and on
every PR based on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

* BSON writer: drop the SFINAE guard that Visual Studio 2017 cannot deduce

write_bson_document_single_pass() was a member template enabled by
is_detected<sink_written_t, SinkType>. MSVC 19.16 (Visual Studio 2017)
fails to deduce it through the class-scope alias template (C2672, C2783)
when it compiles to_bson() and to_bon8(), so every Visual Studio 2017
job on AppVeyor fails since #5979.

The guard is not needed: as a non-template member of the class template,
the function is only instantiated when called, and its only caller is
the write_bson_document() overload for sinks that have written(), which
already calls oa.written() and oa.rewind() itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 17:47:21 +01:00
Niels Lohmann b2674a4a2f BSON reader: check array element names in place in strict mode (#5984) 2026-11-01 21:03:35 +01:00
Niels Lohmann e2423a1857 CI: pin ubuntu-latest jobs to ubuntu-26.04 (#5983)
GitHub is moving the ubuntu-latest label from Ubuntu 24.04 to 26.04
between October 19 and November 19, 2026 (actions/runner-images#14748).
Pin every ubuntu-latest job to ubuntu-26.04 so the switch does not
change the toolchain under our jobs, and so the behaviour does not
depend on when GitHub reaches our runs.

Jobs pinned to ubuntu-24.04 and ubuntu-24.04-arm are unchanged.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 20:43:07 +01:00
Niels Lohmann 67b103e506 Fix clang-tidy errors in json_view tests on develop (#5989)
readability-math-missing-parentheses in unit-json_view_builder.cpp (#5974)
and performance-inefficient-string-concatenation in
unit-json_view_positions.cpp.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 20:42:58 +01:00
Niels Lohmann ddc34f546a json_view: exceptions name the path and the bytes of the value (#5974)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:25:26 +01:00
Niels Lohmann f022e3c59c Binary readers and writers: faster UTF-8 checks of strings (#5982)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:23:27 +01:00
Niels Lohmann 9742edc294 BSON writer: write to_bson(j) in one pass, with sizes written afterwards (#5979)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:23:12 +01:00
Niels Lohmann 517444b504 accept() checks strings without copying them (#5978)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:22:58 +01:00
Niels Lohmann fb515ddc34 UBJSON/BJData readers: read optimized arrays of numbers in one loop (#5981)
* UBJSON/BJData readers: read optimized arrays of numbers in one loop

An array with a type marker for a fixed-size number ($U, $i, $I, $l, $L,
$d, $D, and BJData's $u, $m, $M), including the data of a BJData ndarray,
gives its elements no markers. When the input is contiguous, read the
elements that are in the input in one loop - load, byte swap for the
format's byte order, emit - instead of one trip through
parse_ubjson_internal and get_ubjson_value per element. Elements the
input ends before, other types, and non-contiguous inputs are read as
before.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* UBJSON/BJData tests: assign the parsed value instead of casting it to void

GCC reports -Werror=unused-result for static_cast<void>(json::from_ubjson(...))
and json::from_bjdata(...): a cast to void does not silence warn_unused_result
on GCC. Assign to a json, as the other tests do.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:22:33 +01:00
Niels Lohmann edf8d17601 MessagePack reader: read runs of scalar array elements in one loop (#5980)
* MessagePack reader: read runs of scalar array elements in one loop

As for CBOR: when an array opens and the input is contiguous, read the
integers, floats, booleans, and nils that follow in a tight loop instead
of going through parse_msgpack_internal and parse_msgpack_value for every
element. The loop stops at any other kind of value and when fewer than 9
bytes are left; those values are read by the general path as before.
Non-contiguous inputs are not affected.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: enter the scalar run only when a scalar follows

As for CBOR: enter_msgpack_array tests the first byte and the remaining length
inline and calls the out-of-line run only for a scalar, so arrays of maps or
strings no longer pay for a call that reads nothing; the run's loop condition
moves to the end (do-while).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: mark the initial accepted in the scalar run as a false-positive dead store

ci_infer reports DEAD_STORE for 'bool accepted = true;' in the MessagePack
scalar run, as in the CBOR one, because every case assigns accepted before it
is read.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack tests: assign the parsed value instead of casting it to void

GCC (ci_test_gcc) reports -Werror=unused-result for
static_cast<void>(json::from_msgpack(...)): a cast to void does not silence
warn_unused_result on GCC. Assign to a json, as the other tests in the file do.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: drop the scalar pre-check before the run

enter_msgpack_array now calls the run directly, and parse_msgpack_scalar_run
tests the remaining count and length at the top of a while loop instead of
relying on msgpack_scalar_follows(); its own switch already leaves on any
value that is not a scalar.

Instructions per repetition, new/old: SAX canada 0.946 (clang) and 0.973
(GCC 13), DOM read canada 0.991 / 0.992; no row more than 0.3 % higher.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: say why the initial accepted in the scalar run stays

As for CBOR: Infer's DEAD_STORE report is right, not a false positive. The
initializer is kept for clang-tidy's cppcoreguidelines-init-variables.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: give the scalar run the bulk tag instead of a wrapper

As for CBOR: parse_msgpack_scalar_run takes the bulk-scan tag itself and is
the function kept out of line, so parse_msgpack_array_start goes.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: start the scalar run's accepted at false

As for CBOR: Infer ignores dead stores of 0, so the suppression goes.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* MessagePack reader: let the scalar run find its array itself

As for CBOR: parse_msgpack_scalar_run reads container_stack.back() in its
bulk version, so the caller no longer evaluates it for input that is not
contiguous.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:22:32 +01:00
Niels Lohmann aecbef3949 Binary readers: swap the bytes of floats with a single byteswap (#5976)
* Binary readers: swap the bytes of floats with a single byteswap

byte_swap reversed float and double values byte by byte. GCC does not
merge that loop into one bswap, and C++23's std::byteswap accepts only
integers. Overloads for float and double now copy the bits into a
uint32_t/uint64_t, call detail::byteswap, and copy them back. This
applies to every binary reader that uses get_number.

In the CBOR reader, the single- and double-precision float cases call a
non-inlined helper. Without it, GCC stopped inlining the stream
adapter's get_character() into parse_cbor_internal, which made reading
from a std::istream about 0.5 % slower.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: inline get_cbor_float() and always inline get() instead

The never-inlined get_cbor_float() costs a call for every float read
from input without bulk access: reading canada.json from CBOR through a
FILE* became 5.6 % slower on Apple clang in the benchmark suite. The
helper existed only because GCC 13 stopped inlining the stream adapter's
get_character() into parse_cbor_internal. Always inlining
binary_reader::get() fixes that as well.

callgrind, all binary formats on buffer, std::istringstream and FILE*
input (canada and citm_catalog): GCC 13 0.986-1.003, GCC 16 0.994-1.006,
Clang 23 identical. Apple clang suite: FromBinaryFile/cbor/canada 0.939,
geomean of the 53 binary reader rows 0.998.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:22:32 +01:00
Niels Lohmann 6c3ab966d3 CBOR reader: read runs of scalar array elements in one loop (#5975)
* CBOR reader: read runs of scalar array elements in one loop

When a definite-length CBOR array opens and the input is contiguous, read
the integers, floats, booleans, and nulls that follow in a tight loop
instead of going through parse_cbor_internal's container logic and
parse_cbor_value's dispatch for every element. The loop stops at any other
kind of value and when fewer than 9 bytes are left; those values are read
by the general path exactly as before. Non-contiguous inputs are not
affected (tag dispatch on the bulk-scan capability).

Also pass a member empty string as the number source to number_float
instead of constructing a std::string for every float.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: address review of the scalar-run reader

- parse_cbor_scalar_run: set the size explicitly in every case that
  reads a value, instead of relying on a default that every other case
  overwrites.
- Remove cbor_scalar_follows(): parse_cbor_scalar_run already returns on
  the same conditions, and without the pre-check SAX canada needs another
  8.5 % fewer instructions with GCC 13 (0.915 against the previous
  version), with no row more than 0.5 % worse (Mac and GCC).
- Restore the comment on why parse_cbor_internal copies the container
  frame.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: enter the scalar run only when a scalar follows

An array of containers or strings called the out-of-line run start once per
array only to leave it at once; on nested data (arrays of objects) that call
made reading slower than before the run reader. enter_cbor_array now tests the
first byte and the remaining length inline and calls the run only for a
scalar, so the run's loop condition moves to the end (do-while).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: mark the initial accepted in the scalar run as a false-positive dead store

ci_infer reports DEAD_STORE for 'bool accepted = true;' in
parse_cbor_scalar_run because every case assigns accepted before it is read.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: drop the scalar pre-check before the run

enter_cbor_array calls the run directly again, and parse_cbor_scalar_run
tests the remaining count and length at the top of a while loop; its own
switch already leaves on any value that is not a scalar. The MessagePack
reader is built the same way.

Instructions per repetition, new/old: clang SAX canada 0.983, read canada
0.993; GCC 13 read canada 0.997, the other rows at most 1.004.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: say why the initial accepted in the scalar run stays

Infer's DEAD_STORE report is right, not a false positive: every case that
reaches the read assigns accepted. The initializer is kept for clang-tidy's
cppcoreguidelines-init-variables.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: give the scalar run the bulk tag instead of a wrapper

parse_cbor_scalar_run takes the bulk-scan tag itself and is the function that
is kept out of line, so the one-line parse_cbor_array_start wrapper goes, as
the UBJSON typed run already does.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: start the scalar run's accepted at false

Infer ignores dead stores of 0 (--liveness-ignored-constant defaults to "0"),
and false is 0 to it, so the suppression and its comment go.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* CBOR reader: let the scalar run find its array itself

parse_cbor_scalar_run reads container_stack.back() in its bulk version, so
the caller no longer evaluates it for input that is not contiguous.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:22:31 +01:00
Niels Lohmann 5337d841d4 Document and test the lifetime of string_view members decoded from a json_view (#5973)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:21:31 +01:00
Niels Lohmann 162eda2574 json_view: skip the digits of a fraction 16 bytes at a time (SSE2) (#5971)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:21:19 +01:00
Niels Lohmann 1a018577cc json_view: accept() checks the text without writing an index (#5970)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:21:06 +01:00
Niels Lohmann 76001c6b4c BSON reader: find C-string terminators 8 bytes at a time, skip array element names (#5968)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:20:54 +01:00
Niels Lohmann ec6986c918 Add natvis visualizers for json_document and json_view (#5967)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:20:41 +01:00
Niels Lohmann 3fd3e0fdaa json_view: dump and read canada.json-style floats faster (batched float decisions) (#5908)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-01 17:20:29 +01:00
Niels Lohmann 9c349b1d7c Write integers of 17 to 20 digits eight digits at a time in dump() (#5964)
#5634 made dump() write integers below 10^16 eight digits at a time; larger
ones still took the two-digits-per-division loop and count_digits(). Random
64-bit integers almost all have 17 to 20 digits (99.9 % of signed_ints.json
and unsigned_ints.json), so Dump/signed_ints and Dump/unsigned_ints gained
only 1.4x over 3.12.0, against 2.3x for small integers.

A 64-bit magnitude is now written as its first one to four digits and two
groups of eight. Wider magnitudes (__int128 and class types, #5805) keep the
loop: number types of at most 64 bits are selected by type, so no comparison
is reported as always true; for others the value is compared. The sign
handling of #1447/#5815 (remove_sign() into number_magnitude_t) is unchanged.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-31 13:54:45 +01:00
Niels Lohmann 367963f6bb Test escaped object keys decoded through NLOHMANN_DEFINE_TYPE from a json_view (#5972)
A json_view or json_document decodes a macro-defined struct directly and looks
the members up by their decoded keys. Only plain keys were covered so far.

The new section decodes structs defined with NLOHMANN_DEFINE_TYPE_INTRUSIVE,
..._WITH_DEFAULT and ..._WITH_NAMES from documents whose keys contain escape
sequences, and compares the result with the conversion of the materialized
value. It also pins the difference for a duplicate key written once plain and
once escaped (the view takes the first member, the materialized value keeps
the last one), and that an escaped backslash is part of the decoded key.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-31 13:54:20 +01:00
Niels Lohmann 4fe670b5f4 json_view: decode chains of unicode escapes in a loop (#5969)
After the first \uXXXX escape of a string, slow_string() now decodes the
escapes that follow it directly, while the next six bytes are \u and four hex
digits that are not a surrogate, instead of going round its main loop for each
of them (that is how Python's json.dumps writes non-ASCII text by default).
A surrogate, a bad digit, or fewer than six bytes leave the position at the
backslash: the main loop handles them as before and reports the same error at
the same position.

twitterescaped.json (simdjson-data, 549 KB, 33,036 escapes), json_document::parse(),
A/B in one binary, 6 code layouts, time after / before:

- Apple M1 Max, Apple clang 21: 0.897
- x86-64 Haswell, GCC 16.2: 0.907
- x86-64 Haswell, Clang 23: 0.910

The other files of the benchmark set (twitter, citm_catalog, canada, gsoc-2018,
apache_builds, instruments, tree-pretty, github_events, random, update-center,
semanticscholar-corpus, twitter_timeline) stay within the noise of each machine.

New test: chains of every length from 1 to 40 of escapes that give one, two,
and three bytes of UTF-8, followed by the end of the string, text, escapes,
surrogates, bad digits, and cut in every place, in keys and in values, against
json::parse().

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-31 13:54:02 +01:00
Niels Lohmann 755bb16d7a Fix the red CI on develop: remove the duplicate is_editable in basic_json_view (#5966)
#5919 replaced the bool template parameter Editable of basic_json_view by
view_mode Mode and defined is_editable from Mode. #5890 was written before
that and added a second is_editable = Editable to the private section, which
no longer compiles ("duplicate member", "undeclared identifier Editable"). It
broke every job that builds the json_view tests (macOS, MSVC, clang-cl,
clang on Windows, the C++20 module job, CodeQL).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-30 16:48:31 +01:00
169 changed files with 22875 additions and 76386 deletions

No files matched your search

+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
permissions:
actions: write
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
steps:
- name: Harden Runner
+1 -1
View File
@@ -19,7 +19,7 @@ permissions:
jobs:
save:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
+1 -1
View File
@@ -16,7 +16,7 @@ concurrency:
jobs:
check_docs_links:
if: github.repository == 'nlohmann/json'
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
timeout-minutes: 30
steps:
- name: Harden Runner
@@ -12,7 +12,7 @@ jobs:
comment:
# push runs on develop have no PR to comment on (and no "pr" artifact)
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }}
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
permissions:
contents: read
actions: read
+1 -1
View File
@@ -18,7 +18,7 @@ permissions:
jobs:
dependency-review:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
+1 -1
View File
@@ -24,7 +24,7 @@ on:
jobs:
flawfinder:
name: Flawfinder
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
permissions:
actions: read
contents: read
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
contents: read
pull-requests: write
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
steps:
- name: Harden Runner
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
contents: write
if: github.repository == 'nlohmann/json'
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
+1 -1
View File
@@ -24,7 +24,7 @@ permissions:
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
+1 -1
View File
@@ -8,7 +8,7 @@ permissions:
jobs:
stale:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
permissions:
issues: write
+13 -13
View File
@@ -18,7 +18,7 @@ concurrency:
jobs:
ci_test_gcc:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: gcc:latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -130,7 +130,7 @@ jobs:
run: cmake --build build --target ${{ matrix.target }}
ci_static_analysis_clang:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: silkeh/clang:22
strategy:
matrix:
@@ -149,7 +149,7 @@ jobs:
run: cmake --build build --target ${{ matrix.target }}
ci_cmake_options:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: ubuntu:24.04
strategy:
matrix:
@@ -209,7 +209,7 @@ jobs:
fail-on-error: false
ci_test_compilers_gcc_old:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
strategy:
matrix:
compiler: ['4.8', '4.9', '5', '6']
@@ -251,7 +251,7 @@ jobs:
run: cmake --build build --target ci_test_compiler_g++-${{ matrix.compiler }}
ci_test_compilers_gcc:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
strategy:
matrix:
# older GCC docker images (4, 5, 6) fail to check out code
@@ -269,7 +269,7 @@ jobs:
run: cmake --build build --target ci_test_compiler_default
ci_test_compilers_clang:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
strategy:
matrix:
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest']
@@ -289,7 +289,7 @@ jobs:
run: cmake --build build --target ci_test_compiler_default
ci_test_standards_gcc:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: gcc:latest
strategy:
matrix:
@@ -306,7 +306,7 @@ jobs:
run: cmake --build build --target ci_test_gcc_cxx${{ matrix.standard }}
ci_test_standards_clang:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: silkeh/clang:latest
strategy:
matrix:
@@ -330,7 +330,7 @@ jobs:
if: ${{ matrix.stdlib == 'libstdcxx' }}
ci_cuda_example:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
strategy:
fail-fast: false
matrix:
@@ -356,7 +356,7 @@ jobs:
strategy:
matrix:
container: ['gcc:latest', 'silkeh/clang:latest']
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -383,7 +383,7 @@ jobs:
run: cmake --build build --target ci_module_cpp20
ci_icpc:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
# Intel discontinued the classic icc/icpc compiler in oneAPI 2024.0; this is
# Intel's own last officially published image that still includes it.
container: intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04
@@ -402,7 +402,7 @@ jobs:
run: cmake --build build --target ci_icpc
ci_icpx:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: intel/oneapi-hpckit:latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -416,7 +416,7 @@ jobs:
run: cmake --build build --target ci_icpx
ci_nvhpc:
runs-on: ubuntu-latest
runs-on: ubuntu-26.04
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+3 -3
View File
@@ -348,20 +348,20 @@ add_custom_target(ci_test_no_thread_local
add_custom_target(ci_test_coverage
COMMAND CXX=g++ ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="--coverage;-fprofile-arcs;-ftest-coverage"
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="--coverage;-fprofile-arcs;-ftest-coverage;-fvar-tracking-assignments"
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_coverage
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_coverage
COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMAND CXX=g++ ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="-m32;--coverage;-fprofile-arcs;-ftest-coverage"
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="-m32;--coverage;-fprofile-arcs;-ftest-coverage;-fvar-tracking-assignments"
-DJSON_BuildTests=ON -DJSON_32bitTest=ONLY
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_coverage32
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_coverage32
COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage32 && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused --ignore-errors inconsistent
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --ignore-errors mismatch --ignore-errors unused --ignore-errors inconsistent
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused --ignore-errors inconsistent
COMMAND ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
COMMAND ${GENHTML_TOOL} --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage --ignore-errors inconsistent json.info.filtered.noexcept
+3 -1
View File
@@ -178,8 +178,10 @@ function(_json_test_add_test test_name file main cxx_standard)
COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
# under Valgrind the slowest tests take close to 25 minutes, so ctest's
# default timeout of 1500 seconds leaves no headroom
set_tests_properties(${test_target}_valgrind PROPERTIES
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA TIMEOUT 3600
)
endif()
endfunction()
+10
View File
@@ -120,6 +120,16 @@ overload (3).
See [Number conversion](../../features/types/number_handling.md#number-conversion)
for more information.
!!! note "Booleans as numbers"
A JSON boolean converts to `#!cpp 0` or `#!cpp 1` for every arithmetic type **except** [`number_integer_t`](number_integer_t.md),
[`number_unsigned_t`](number_unsigned_t.md) and [`number_float_t`](number_float_t.md) (by default `#!cpp std::int64_t`,
`#!cpp std::uint64_t`, and `#!cpp double`), for which `#!cpp get<T>()` throws
[`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) ("type must be number, but is boolean"). So
`#!cpp json(true).get<int>()` is `#!cpp 1`, while `#!cpp json(true).get<std::int64_t>()` and
`#!cpp json(true).get<double>()` throw. This is the behavior of all 3.x versions;
[`basic_json_view::get<T>()`](../basic_json_view/get.md) behaves the same.
!!! note "`std::optional` conversions"
Prior to version 3.13.0, `#!cpp get<std::optional<T>>()` (and other conversions to `std::optional<T>`) failed to
+6 -1
View File
@@ -65,7 +65,12 @@ the same index, which is now a different value.
## Exception safety
Strong exception safety: if an exception occurs, the original value stays intact.
Overload (1) gives the strong guarantee: if an exception is thrown, there are no changes in the JSON value.
Overloads (2) to (5) give the basic guarantee: if an exception is thrown while the elements or members are copied
(for example, `std::bad_alloc`), the JSON value may be partially modified, but it stays a valid array or object.
The exceptions listed below are thrown before the JSON value is changed.
## Exceptions
@@ -13,9 +13,15 @@ function never throws an exception for invalid input, and the returned `#!cpp bo
is returned.
The result is the same as that of `BasicJsonType::accept()` by design; the difference is how the check is made. This
function runs the document's index builder (and discards the index), while `BasicJsonType::accept()` runs the SAX
parser with a handler that ignores every event. Use this one if you go on to parse the same input with
[`parse()`](parse.md) anyway, so that both use the same code; either is fine for a plain yes/no answer.
function runs the document's builder, which checks the text as [`parse()`](parse.md) does, while
`BasicJsonType::accept()` runs the SAX parser with a handler that ignores every event. Use this one if you go on to
parse the same input with [`parse()`](parse.md) anyway, so that both use the same code; either is fine for a plain
yes/no answer.
When both `ignore_comments` and `ignore_trailing_commas` are `#!cpp false` (the default), the builder writes no index.
With either option set, it builds the index as [`parse()`](parse.md) does and discards it: the result is the same, only
the time differs. (Neither option needs the index; the variant that skips it exists only for the default options to
keep the code size down.)
## Template parameters
+4 -3
View File
@@ -68,9 +68,10 @@ Strong guarantee: there are no changes to the view or the document it refers to.
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if `ptr` cannot be resolved
because a reference token is used on a primitive value.
None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) these exceptions name the JSON
Pointer path of the value within the document, and with
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) its bytes in the source text (when
[`materialize()`](materialize.md) sets them).
## Complexity
+3 -3
View File
@@ -20,9 +20,9 @@ Strong guarantee: there are no changes to the view or the document it refers to.
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) the exception names the JSON Pointer
path of the value within the document, and with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md)
its bytes in the source text (when [`materialize()`](materialize.md) sets them).
## Complexity
@@ -20,9 +20,9 @@ Strong guarantee: there are no changes to the view or the document it refers to.
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) the exception names the JSON Pointer
path of the value within the document, and with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md)
its bytes in the source text (when [`materialize()`](materialize.md) sets them).
## Complexity
+9 -9
View File
@@ -11,7 +11,8 @@ For the types below, the conversion works directly on the flat index — no `Bas
- `#!cpp bool`
- arithmetic types other than `#!cpp bool` (for a boolean, `#!cpp 0`/`#!cpp 1`, exactly as for
[`BasicJsonType::get<T>()`](../basic_json/get.md))
[`BasicJsonType::get<T>()`](../basic_json/get.md#notes), except for `number_integer_t`, `number_unsigned_t` and
`number_float_t`, which throw `type_error.302` for a boolean, as `BasicJsonType::get<T>()` does)
- `#!cpp std::nullptr_t`
- `#!cpp std::basic_string<char, Traits, Alloc>` (including `string_t`) — a copy of the string
- [`string_view_t`](index.md#member-types) — **no copy**: the returned view points into the document's
@@ -80,14 +81,13 @@ Strong guarantee: there are no changes to the view or the document it refers to.
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws — typically `type_error.302`,
or whatever a user-provided `from_json()` throws.
None of the exceptions thrown directly by this function or by a `from_json()` that reads the view (the first four
bullets above) carry a
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
exception thrown while converting through `materialize()` (the last bullet) is different: it is thrown by a real
`BasicJsonType` value, so it **does** carry a `JSON_DIAGNOSTICS` path if `BasicJsonType` was built with it enabled.
That path is relative to the root of the view's subtree, because `materialize()` builds only the subtree (with parent
pointers): it is empty if the failing value is the subtree's root itself, and it never is the path within the whole
document.
The exceptions thrown directly by this function or by a `from_json()` that reads the view (the first four bullets
above) carry the context of those of `BasicJsonType`: with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) the
JSON Pointer path of the value within the document, and with
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) its bytes in the source text. An exception
thrown while converting through `materialize()` (the last bullet) is thrown by the materialized `BasicJsonType` value
instead: its path is relative to the root of the view's subtree, because `materialize()` builds only the subtree
(with parent pointers), so it is empty if the failing value is the subtree's root itself.
## Complexity
@@ -22,9 +22,9 @@ Strong guarantee: there are no changes to the view or the document it refers to.
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if the value is not a string; example:
`"type must be string, but is array"`.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) the exception names the JSON Pointer
path of the value within the document, and with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md)
its bytes in the source text (when [`materialize()`](materialize.md) sets them).
## Complexity
@@ -22,9 +22,9 @@ Strong guarantee: there are no changes to the view or the document it refers to.
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if the value is not a number; example:
`"type must be number, but is string"`.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) the exception names the JSON Pointer
path of the value within the document, and with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md)
its bytes in the source text (when [`materialize()`](materialize.md) sets them).
## Complexity
@@ -73,9 +73,10 @@ Strong guarantee: there are no changes to the view or the document it refers to.
- [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in `ptr` is not a
number.
None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) these exceptions name the JSON
Pointer path of the value within the document, and with
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) its bytes in the source text (when
[`materialize()`](materialize.md) sets them).
## Complexity
@@ -61,9 +61,10 @@ Strong guarantee: there are no changes to the view or the document it refers to.
`default_value` instead of throwing, exactly as [`BasicJsonType::value`](../basic_json/value.md) catches
`out_of_range` and returns `default_value`.
None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
As for `BasicJsonType`, with [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) these exceptions name the JSON
Pointer path of the value within the document, and with
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) its bytes in the source text (when
[`materialize()`](materialize.md) sets them).
## Complexity
@@ -35,6 +35,9 @@ Note that enabling this macro increases the size of every JSON value by two `std
overhead to parsing, copying JSON value objects, and the generation of error messages for exceptions. It also causes
these values to be reported in those error messages.
If [`JSON_DIAGNOSTICS`](json_diagnostics.md) is also set, the message contains the path and the byte range, such as
`(/1) (bytes 4-8)`. An exception about the root value has no path and only the range, such as `(bytes 0-4)`.
## Default definition
The default value is `0` (position diagnostics are switched off).
+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; }
+47 -15
View File
@@ -134,9 +134,21 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
- **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 others either do not apply ([`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md)
needs parent pointers in `basic_json` values) or only affect the values `materialize()` produces, through
`BasicJsonType`.
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
@@ -167,10 +179,6 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
[`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.
- **No [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) path.** Exceptions thrown by `basic_json_view`'s own
element access and lookup functions never carry the JSON Pointer path `JSON_DIAGNOSTICS` would otherwise add: the
view has no `basic_json` value to point at, so the exception is created without one, regardless of how
`BasicJsonType` was built.
- **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
@@ -253,6 +261,34 @@ Two conversions never copy at all:
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):
@@ -329,14 +365,10 @@ Its body may only use what views and `basic_json` have in common: the type check
a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is
converted through `materialize()` as well.
Two things differ when a `from_json()` reads the view:
- **Duplicate keys.** 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.
- **[`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md).** Exceptions thrown by the view carry no path to the
value.
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.
@@ -406,6 +406,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
| `#!cpp operator<<(std::ostream&, const json_pointer&)` | streamability to `#!cpp std::ostream` |
| [`to_string`](../../api/basic_json/to_string.md) | conversion of `StringType` to `#!cpp std::string` (the function returns a `#!cpp std::string`) |
| exception messages | `data()` and `size()`, or `begin()` and `end()` |
| [`basic_json_view::dump`](../../api/basic_json_view/dump.md) | `reserve(n)` and `resize(n)` (one argument); `capacity()` is **not** required |
### Compatible types
File diff suppressed because it is too large. Load diff
+8 -1
View File
@@ -10,6 +10,13 @@ at its root, a [Natvis](https://learn.microsoft.com/en-us/visualstudio/debugger/
file that gives `json`/`ordered_json` values a friendly, key/value debugger view instead of showing raw internal
fields, when debugging with the MSVC debug engine (`cppvsdbg`) in Visual Studio or VS Code.
The file also has visualizers for `json_document` and `json_view` (and their `ordered_json`/editable variants). They
show the value of the document or view, and its elements as an expandable list. Because a document is only a flat index
into the source text, the strings of the direct elements are shown, but the elements of nested arrays and objects are
shown as index nodes (their kind, size, and numbers; strings only by length). Arrays and objects that have been edited
in a `json_editable_document` are not expanded. The visualizers read the internal layout of the MSVC STL (`std::array`,
`std::unique_ptr`).
The checked-in visualizers cover namespace variants with zero, one, or two ABI tags. Configurations with three or more
ABI tags are not covered and may show raw internal fields instead. To generate a Natvis file for such a configuration:
@@ -29,7 +36,7 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
4. Use the generated file instead of `nlohmann_json.natvis`.
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 12
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 11
ABI tags, doubling with each further tag). See
[`tools/generate_natvis`](https://github.com/nlohmann/json/tree/develop/tools/generate_natvis) for all options.
+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: 1; 1 to 1.5x: 22; 1.5 to 2x: 12; 2 to 3x: 60; 3 to 5x: 58; 5 to 10x: 25; 10x or more: 4. Median 2.9x, geometric mean 3.0x.</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="144.571" x2="548" y2="144.571"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="148.571">20</text>
<line class="nj-charts-grid" x1="52" y1="93.1429" x2="548" y2="93.1429"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="97.1429">40</text>
<line class="nj-charts-grid" x1="52" y1="41.7143" x2="548" y2="41.7143"/>
<text class="nj-charts-tick nj-charts-tick--r" x="46" y="45.7143">60</text>
<rect class="nj-charts-c2" x="60.0" y="193.4" width="54.9" height="2.6" rx="3"><title>below 1&#215;: 1</title></rect>
<text class="nj-charts-val" x="87.4" y="188.4" text-anchor="middle">1</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="139.4" width="54.9" height="56.6" rx="3"><title>1 to 1.5&#215;: 22</title></rect>
<text class="nj-charts-val" x="158.3" y="134.4" text-anchor="middle">22</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="165.1" width="54.9" height="30.9" rx="3"><title>1.5 to 2&#215;: 12</title></rect>
<text class="nj-charts-val" x="229.1" y="160.1" text-anchor="middle">12</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="41.7" width="54.9" height="154.3" rx="3"><title>2 to 3&#215;: 60</title></rect>
<text class="nj-charts-val" x="300.0" y="36.7" text-anchor="middle">60</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="46.9" width="54.9" height="149.1" rx="3"><title>3 to 5&#215;: 58</title></rect>
<text class="nj-charts-val" x="370.9" y="41.9" text-anchor="middle">58</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="131.7" width="54.9" height="64.3" rx="3"><title>5 to 10&#215;: 25</title></rect>
<text class="nj-charts-val" x="441.7" y="126.7" text-anchor="middle">25</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="185.7" width="54.9" height="10.3" rx="3"><title>10&#215; or more: 4</title></rect>
<text class="nj-charts-val" x="512.6" y="180.7" text-anchor="middle">4</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.68, x86-64 0.44 (serde_json (Rust)); marine_ik: Mac 0.59, x86-64 0.64 (Boost.J&#8203;SON); semanticscholar-corpus: Mac 0.79, x86-64 0.65 (sonic-rs (Rust)); gsoc-2018: Mac 0.60, x86-64 0.66 (Boost.J&#8203;SON); twitter_api_compact_response: Mac 0.91, x86-64 0.70 (simdjson); twitterescaped: Mac 0.93, x86-64 0.76 (simdjson); numbers: Mac 0.67, x86-64 0.77 (Boost.J&#8203;SON); github_events: Mac 0.79, x86-64 0.77 (simdjson); update-center: Mac 0.88, x86-64 0.79 (simdjson); twitter_timeline: Mac 0.97, x86-64 0.80 (yyjson); twitter_api_response: Mac 0.93, x86-64 0.81 (simdjson); google_maps_api_compact_response: Mac 0.86, x86-64 0.81 (yyjson); repeat: Mac 0.65, x86-64 0.82 (simdjson); random: Mac 0.81, x86-64 0.88 (simdjson); apache_builds: Mac 1.08, x86-64 0.90 (simdjson); instruments: Mac 0.90, x86-64 0.92 (simdjson); mesh.pretty: Mac 0.86, x86-64 0.92 (Boost.J&#8203;SON); tree-pretty: Mac 0.93, x86-64 0.96 (simdjson); google_maps_api_response: Mac 0.93, x86-64 0.99 (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="344.8" cy="60.5" r="4.5"><title>mesh, Apple M1 Max: 0.68&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="273.6" 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">marine&#95;ik</text>
<circle class="nj-charts-json-dot" cx="319.5" cy="80.5" r="4.5"><title>marine&#95;ik, Apple M1 Max: 0.59&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="334.2" cy="87.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="88">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="108" text-anchor="end">semanticscholar-corpus</text>
<circle class="nj-charts-json-dot" cx="377.9" cy="100.5" r="4.5"><title>semanticscholar-corpus, Apple M1 Max: 0.79&#215; the time of sonic-rs (Rust)</title></circle>
<circle class="nj-charts-ojson-dot" cx="336.0" cy="107.5" r="4.5"><title>semanticscholar-corpus, x86-64, G&#8203;CC 16.2: 0.65&#215; the time of sonic-rs (Rust)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="108">sonic-rs (Rust)</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="128" text-anchor="end">gsoc-2018</text>
<circle class="nj-charts-json-dot" cx="322.9" cy="120.5" r="4.5"><title>gsoc-2018, Apple M1 Max: 0.60&#215; the time of sonic-rs (Rust)</title></circle>
<circle class="nj-charts-ojson-dot" cx="338.8" cy="127.5" r="4.5"><title>gsoc-2018, x86-64, G&#8203;CC 16.2: 0.66&#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="352.1" cy="147.5" r="4.5"><title>twitter&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.70&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="148">simdjson</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="419.5" cy="160.5" r="4.5"><title>twitterescaped, Apple M1 Max: 0.93&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="370.8" 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">numbers</text>
<circle class="nj-charts-json-dot" cx="343.3" cy="180.5" r="4.5"><title>numbers, Apple M1 Max: 0.67&#215; the time of Boost.J&#8203;SON</title></circle>
<circle class="nj-charts-ojson-dot" cx="373.1" cy="187.5" r="4.5"><title>numbers, x86-64, G&#8203;CC 16.2: 0.77&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="188">Boost.J&#8203;SON</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="379.5" cy="200.5" r="4.5"><title>github&#95;events, Apple M1 Max: 0.79&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="373.4" cy="207.5" r="4.5"><title>github&#95;events, 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="208">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="228" text-anchor="end">update-center</text>
<circle class="nj-charts-json-dot" cx="405.1" cy="220.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="377.7" cy="227.5" r="4.5"><title>update-center, x86-64, G&#8203;CC 16.2: 0.79&#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="431.6" cy="240.5" r="4.5"><title>twitter&#95;timeline, Apple M1 Max: 0.97&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="381.3" cy="247.5" r="4.5"><title>twitter&#95;timeline, x86-64, G&#8203;CC 16.2: 0.80&#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">twitter&#95;api&#95;response</text>
<circle class="nj-charts-json-dot" cx="420.4" cy="260.5" r="4.5"><title>twitter&#95;api&#95;response, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="384.1" cy="267.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="268">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="288" text-anchor="end">google&#95;maps&#95;api&#95;compact&#95;response</text>
<circle class="nj-charts-json-dot" cx="399.2" cy="280.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, Apple M1 Max: 0.86&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="384.2" cy="287.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.81&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="288">yyjson</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="388.2" cy="307.5" r="4.5"><title>repeat, x86-64, G&#8203;CC 16.2: 0.82&#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">random</text>
<circle class="nj-charts-json-dot" cx="383.7" cy="320.5" r="4.5"><title>random, Apple M1 Max: 0.81&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="404.9" cy="327.5" r="4.5"><title>random, x86-64, G&#8203;CC 16.2: 0.88&#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">apache&#95;builds</text>
<circle class="nj-charts-json-dot" cx="463.6" cy="340.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.4" cy="347.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="348">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="368" text-anchor="end">instruments</text>
<circle class="nj-charts-json-dot" cx="412.5" cy="360.5" r="4.5"><title>instruments, Apple M1 Max: 0.90&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="416.2" cy="367.5" r="4.5"><title>instruments, x86-64, G&#8203;CC 16.2: 0.92&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="368">simdjson</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="398.9" cy="380.5" r="4.5"><title>mesh.pretty, Apple M1 Max: 0.86&#215; the time of Glaze</title></circle>
<circle class="nj-charts-ojson-dot" cx="418.6" cy="387.5" r="4.5"><title>mesh.pretty, x86-64, G&#8203;CC 16.2: 0.92&#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="420.1" cy="400.5" r="4.5"><title>tree-pretty, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="429.3" cy="407.5" r="4.5"><title>tree-pretty, x86-64, G&#8203;CC 16.2: 0.96&#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="419.0" cy="420.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="439.0" cy="427.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 0.99&#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,87 +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.1x; citm_catalog.json 4.2x; canada.json 3.4x; canada.json, indented 6.5x; citm, ordered_json 6.8x; twitter, std::ifstream 2.5x; citm, FILE* 4.7x; citm, accept() 7.1x; dump() twitter 6.7x; dump() canada 3.0x; dump(4) citm 4.7x; to_cbor() twitter 4.6x; twitter, memory 3.4x; twitter, FILE* 6.6x; diff() canada 10x; iterate canada 2.7x; copy + destroy citm 1.13x; == citm 1.06x.</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="220" y1="8" x2="220" y2="560"/>
<text class="nj-charts-tick" x="220" y="576">1&#215;</text>
<line class="nj-charts-grid" x1="250" y1="8" x2="250" y2="560"/>
<text class="nj-charts-tick" x="250" y="576">2&#215;</text>
<line class="nj-charts-grid" x1="280" y1="8" x2="280" y2="560"/>
<text class="nj-charts-tick" x="280" y="576">3&#215;</text>
<line class="nj-charts-grid" x1="310" y1="8" x2="310" y2="560"/>
<text class="nj-charts-tick" x="310" y="576">4&#215;</text>
<line class="nj-charts-grid" x1="340" y1="8" x2="340" y2="560"/>
<text class="nj-charts-tick" x="340" y="576">5&#215;</text>
<line class="nj-charts-grid" x1="370" y1="8" x2="370" y2="560"/>
<text class="nj-charts-tick" x="370" y="576">6&#215;</text>
<line class="nj-charts-grid" x1="400" y1="8" x2="400" y2="560"/>
<text class="nj-charts-tick" x="400" y="576">7&#215;</text>
<line class="nj-charts-grid" x1="430" y1="8" x2="430" y2="560"/>
<text class="nj-charts-tick" x="430" y="576">8&#215;</text>
<line class="nj-charts-grid" x1="460" y1="8" x2="460" y2="560"/>
<text class="nj-charts-tick" x="460" y="576">9&#215;</text>
<line class="nj-charts-grid" x1="490" y1="8" x2="490" y2="560"/>
<text class="nj-charts-tick" x="490" y="576">10&#215;</text>
<line class="nj-charts-grid" x1="520" y1="8" x2="520" y2="560"/>
<text class="nj-charts-tick" x="520" y="576">11&#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 H280.2 Q284.2 30 284.2 34 V41 Q284.2 45 280.2 45 H190 Z"><title>twitter.json: 3.1&#215;</title></path>
<text class="nj-charts-val" x="289.2" y="42">3.1&#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 H313.5 Q317.5 54 317.5 58 V65 Q317.5 69 313.5 69 H190 Z"><title>citm_catalog.json: 4.2&#215;</title></path>
<text class="nj-charts-val" x="322.5" y="66">4.2&#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 H286.5 Q290.5 78 290.5 82 V89 Q290.5 93 286.5 93 H190 Z"><title>canada.json: 3.4&#215;</title></path>
<text class="nj-charts-val" x="295.5" y="90">3.4&#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 H381.3 Q385.3 102 385.3 106 V113 Q385.3 117 381.3 117 H190 Z"><title>canada.json, indented: 6.5&#215;</title></path>
<text class="nj-charts-val" x="390.3" y="114">6.5&#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 H391.5 Q395.5 126 395.5 130 V137 Q395.5 141 391.5 141 H190 Z"><title>citm, ordered_json: 6.8&#215;</title></path>
<text class="nj-charts-val" x="400.5" y="138">6.8&#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 H261 Q265 150 265 154 V161 Q265 165 261 165 H190 Z"><title>twitter, std::ifstream: 2.5&#215;</title></path>
<text class="nj-charts-val" x="270" 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 H328.2 Q332.2 174 332.2 178 V185 Q332.2 189 328.2 189 H190 Z"><title>citm, FILE*: 4.7&#215;</title></path>
<text class="nj-charts-val" x="337.2" y="186">4.7&#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 H398.1 Q402.1 198 402.1 202 V209 Q402.1 213 398.1 213 H190 Z"><title>citm, accept(): 7.1&#215;</title></path>
<text class="nj-charts-val" x="407.1" y="210">7.1&#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 H387 Q391 254 391 258 V265 Q391 269 387 269 H190 Z"><title>dump() twitter: 6.7&#215;</title></path>
<text class="nj-charts-val" x="396" y="266">6.7&#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 H275.4 Q279.4 278 279.4 282 V289 Q279.4 293 275.4 293 H190 Z"><title>dump() canada: 3.0&#215;</title></path>
<text class="nj-charts-val" x="284.4" y="290">3.0&#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 H327 Q331 302 331 306 V313 Q331 317 327 317 H190 Z"><title>dump(4) citm: 4.7&#215;</title></path>
<text class="nj-charts-val" x="336" y="314">4.7&#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 H323.7 Q327.7 326 327.7 330 V337 Q327.7 341 323.7 341 H190 Z"><title>to_cbor() twitter: 4.6&#215;</title></path>
<text class="nj-charts-val" x="332.7" y="338">4.6&#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 H287.7 Q291.7 382 291.7 386 V393 Q291.7 397 287.7 397 H190 Z"><title>twitter, memory: 3.4&#215;</title></path>
<text class="nj-charts-val" x="296.7" y="394">3.4&#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 H383.7 Q387.7 406 387.7 410 V417 Q387.7 421 383.7 421 H190 Z"><title>twitter, FILE*: 6.6&#215;</title></path>
<text class="nj-charts-val" x="392.7" y="418">6.6&#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 H499.8 Q503.8 462 503.8 466 V473 Q503.8 477 499.8 477 H190 Z"><title>diff() canada: 10&#215;</title></path>
<text class="nj-charts-val" x="508.8" 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 H267.9 Q271.9 486 271.9 490 V497 Q271.9 501 267.9 501 H190 Z"><title>iterate canada: 2.7&#215;</title></path>
<text class="nj-charts-val" x="276.9" y="498">2.7&#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 H219.9 Q223.9 510 223.9 514 V521 Q223.9 525 219.9 525 H190 Z"><title>copy + destroy citm: 1.13&#215;</title></path>
<text class="nj-charts-val" x="228.9" y="522">1.13&#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 H217.8 Q221.8 534 221.8 538 V545 Q221.8 549 217.8 549 H190 Z"><title>== citm: 1.06&#215;</title></path>
<text class="nj-charts-val" x="226.8" y="546">1.06&#215;</text>
<line class="nj-charts-ref" x1="220" y1="8" x2="220" 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: 8.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: +38 %; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, precompiled header: -28 %; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, module: -4 %; Apple clang 21, -O0 (debug), server_config, 3.13.0: +34 %; Apple clang 21, -O0 (debug), server_config, 3.13.0, precompiled header: -23 %; Apple clang 21, -O0 (debug), server_config, 3.13.0, module: +2 %; Apple clang 21, -O2, count_numbers, 3.13.0: +49 %; Apple clang 21, -O2, count_numbers, 3.13.0, precompiled header: +5 %; Apple clang 21, -O2, count_numbers, 3.13.0, module: +21 %; Apple clang 21, -O2, server_config, 3.13.0: +45 %; Apple clang 21, -O2, server_config, 3.13.0, precompiled header: +10 %; Apple clang 21, -O2, server_config, 3.13.0, module: +24 %; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0: +62 %; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, precompiled header: +10 %; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, module: +8 %; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0: +47 %; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, precompiled header: +14 %; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, module: +15 %; G&#8203;CC 16, -O2, count_numbers, 3.13.0: +58 %; G&#8203;CC 16, -O2, count_numbers, 3.13.0, precompiled header: +28 %; G&#8203;CC 16, -O2, count_numbers, 3.13.0, module: +25 %; G&#8203;CC 16, -O2, server_config, 3.13.0: +51 %; G&#8203;CC 16, -O2, server_config, 3.13.0, precompiled header: +28 %; G&#8203;CC 16, -O2, server_config, 3.13.0, module: +30 %.</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 H446.667 Q450.667 78 450.667 82 V85 Q450.667 89 446.667 89 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0: 1,320 ms against 955 ms with 3.12.0 (+38 %)</title></path>
<text class="nj-charts-val" x="455.667" y="87.5">+38 %</text>
<path class="nj-charts-c1" d="M320.833 92 H229.167 Q225.167 92 225.167 96 V99 Q225.167 103 229.167 103 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 688 ms against 955 ms with 3.12.0 (&#8722;28 %)</title></path>
<text class="nj-charts-val" x="220.167" y="101.5" text-anchor="end">&#8722;28 %</text>
<path class="nj-charts-c3" d="M320.833 106 H311.167 Q307.167 106 307.167 110 V113 Q307.167 117 311.167 117 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, module: 918 ms against 955 ms with 3.12.0 (&#8722;4 %)</title></path>
<text class="nj-charts-val" x="302.167" y="115.5" text-anchor="end">&#8722;4 %</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 H433 Q437 127 437 131 V134 Q437 138 433 138 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0: 1,496 ms against 1,113 ms with 3.12.0 (+34 %)</title></path>
<text class="nj-charts-val" x="442" y="136.5">+34 %</text>
<path class="nj-charts-c1" d="M320.833 141 H246.25 Q242.25 141 242.25 145 V148 Q242.25 152 246.25 152 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 863 ms against 1,113 ms with 3.12.0 (&#8722;23 %)</title></path>
<text class="nj-charts-val" x="237.25" y="150.5" text-anchor="end">&#8722;23 %</text>
<path class="nj-charts-c3" d="M320.833 155 H323.667 Q327.667 155 327.667 159 V162 Q327.667 166 323.667 166 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, module: 1,136 ms against 1,113 ms with 3.12.0 (+2 %)</title></path>
<text class="nj-charts-val" x="332.667" y="164.5">+2 %</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 H484.25 Q488.25 208 488.25 212 V215 Q488.25 219 484.25 219 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0: 2,081 ms against 1,393 ms with 3.12.0 (+49 %)</title></path>
<text class="nj-charts-val" x="493.25" y="217.5">+49 %</text>
<path class="nj-charts-c1" d="M320.833 222 H333.917 Q337.917 222 337.917 226 V229 Q337.917 233 333.917 233 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, precompiled header: 1,458 ms against 1,393 ms with 3.12.0 (+5 %)</title></path>
<text class="nj-charts-val" x="342.917" y="231.5">+5 %</text>
<path class="nj-charts-c3" d="M320.833 236 H388.583 Q392.583 236 392.583 240 V243 Q392.583 247 388.583 247 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, module: 1,685 ms against 1,393 ms with 3.12.0 (+21 %)</title></path>
<text class="nj-charts-val" x="397.583" y="245.5">+21 %</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 H470.583 Q474.583 257 474.583 261 V264 Q474.583 268 470.583 268 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0: 2,546 ms against 1,754 ms with 3.12.0 (+45 %)</title></path>
<text class="nj-charts-val" x="479.583" y="266.5">+45 %</text>
<path class="nj-charts-c1" d="M320.833 271 H351 Q355 271 355 275 V278 Q355 282 351 282 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, precompiled header: 1,925 ms against 1,754 ms with 3.12.0 (+10 %)</title></path>
<text class="nj-charts-val" x="360" y="280.5">+10 %</text>
<path class="nj-charts-c3" d="M320.833 285 H398.833 Q402.833 285 402.833 289 V292 Q402.833 296 398.833 296 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, module: 2,169 ms against 1,754 ms with 3.12.0 (+24 %)</title></path>
<text class="nj-charts-val" x="407.833" y="294.5">+24 %</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 H528.667 Q532.667 338 532.667 342 V345 Q532.667 349 528.667 349 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,548 ms against 1,569 ms with 3.12.0 (+62 %)</title></path>
<text class="nj-charts-val" x="537.667" y="347.5">+62 %</text>
<path class="nj-charts-c1" d="M320.833 352 H351 Q355 352 355 356 V359 Q355 363 351 363 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 1,725 ms against 1,569 ms with 3.12.0 (+10 %)</title></path>
<text class="nj-charts-val" x="360" y="361.5">+10 %</text>
<path class="nj-charts-c3" d="M320.833 366 H344.167 Q348.167 366 348.167 370 V373 Q348.167 377 344.167 377 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 1,700 ms against 1,569 ms with 3.12.0 (+8 %)</title></path>
<text class="nj-charts-val" x="353.167" y="375.5">+8 %</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 H477.417 Q481.417 387 481.417 391 V394 Q481.417 398 477.417 398 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,985 ms against 2,025 ms with 3.12.0 (+47 %)</title></path>
<text class="nj-charts-val" x="486.417" y="396.5">+47 %</text>
<path class="nj-charts-c1" d="M320.833 401 H364.667 Q368.667 401 368.667 405 V408 Q368.667 412 364.667 412 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 2,302 ms against 2,025 ms with 3.12.0 (+14 %)</title></path>
<text class="nj-charts-val" x="373.667" y="410.5">+14 %</text>
<path class="nj-charts-c3" d="M320.833 415 H368.083 Q372.083 415 372.083 419 V422 Q372.083 426 368.083 426 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 2,326 ms against 2,025 ms with 3.12.0 (+15 %)</title></path>
<text class="nj-charts-val" x="377.083" y="424.5">+15 %</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 H515 Q519 468 519 472 V475 Q519 479 515 479 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0: 3,702 ms against 2,336 ms with 3.12.0 (+58 %)</title></path>
<text class="nj-charts-val" x="524" y="477.5">+58 %</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,987 ms against 2,336 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 H402.25 Q406.25 496 406.25 500 V503 Q406.25 507 402.25 507 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0, module: 2,913 ms against 2,336 ms with 3.12.0 (+25 %)</title></path>
<text class="nj-charts-val" x="411.25" y="505.5">+25 %</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 H491.083 Q495.083 517 495.083 521 V524 Q495.083 528 491.083 528 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0: 4,714 ms against 3,122 ms with 3.12.0 (+51 %)</title></path>
<text class="nj-charts-val" x="500.083" y="526.5">+51 %</text>
<path class="nj-charts-c1" d="M320.833 531 H412.5 Q416.5 531 416.5 535 V538 Q416.5 542 412.5 542 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, precompiled header: 4,006 ms against 3,122 ms with 3.12.0 (+28 %)</title></path>
<text class="nj-charts-val" x="421.5" y="540.5">+28 %</text>
<path class="nj-charts-c3" d="M320.833 545 H419.333 Q423.333 545 423.333 549 V552 Q423.333 556 419.333 556 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, module: 4,055 ms against 3,122 ms with 3.12.0 (+30 %)</title></path>
<text class="nj-charts-val" x="428.333" y="554.5">+30 %</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,45 +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 353 commits, ending at 5.1x. Labeled steps, by theme: 4, 1, 4, 4, 2, 2.</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="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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.8 46.4,207.8 46.4,208.0 47.2,208.0 47.2,207.7 48.1,207.7 48.1,207.9 48.9,207.9 48.9,208.0 49.7,208.0 49.7,208.1 50.5,208.1 50.5,208.4 51.3,208.4 51.3,207.1 52.1,207.1 52.1,207.9 52.9,207.9 52.9,208.2 53.8,208.2 53.8,207.9 54.6,207.9 54.6,207.9 55.4,207.9 55.4,207.7 56.2,207.7 56.2,207.9 57.0,207.9 57.0,207.8 57.8,207.8 57.8,207.7 58.6,207.7 58.6,208.2 59.4,208.2 59.4,207.3 60.2,207.3 60.2,208.0 61.1,208.0 61.1,208.0 61.9,208.0 61.9,207.8 62.7,207.8 62.7,207.9 63.5,207.9 63.5,207.9 64.3,207.9 64.3,207.2 65.1,207.2 65.1,207.8 65.9,207.8 65.9,207.6 66.8,207.6 66.8,207.8 67.6,207.8 67.6,207.9 68.4,207.9 68.4,207.9 69.2,207.9 69.2,207.4 70.0,207.4 70.0,207.7 70.8,207.7 70.8,207.6 71.6,207.6 71.6,207.7 72.4,207.7 72.4,208.1 73.2,208.1 73.2,207.8 74.1,207.8 74.1,207.1 74.9,207.1 74.9,207.9 75.7,207.9 75.7,207.1 76.5,207.1 76.5,207.8 77.3,207.8 77.3,207.3 78.1,207.3 78.1,208.1 78.9,208.1 78.9,207.6 79.8,207.6 79.8,207.6 80.6,207.6 80.6,208.1 81.4,208.1 81.4,208.3 82.2,208.3 82.2,207.8 83.0,207.8 83.0,207.7 83.8,207.7 83.8,207.9 84.6,207.9 84.6,207.8 85.4,207.8 85.4,207.5 86.2,207.5 86.2,207.9 87.1,207.9 87.1,207.8 87.9,207.8 87.9,208.0 88.7,208.0 88.7,194.6 89.5,194.6 89.5,195.3 90.3,195.3 90.3,195.6 91.1,195.6 91.1,195.1 91.9,195.1 91.9,195.6 92.8,195.6 92.8,194.6 93.6,194.6 93.6,194.7 94.4,194.7 94.4,195.3 95.2,195.3 95.2,195.1 96.0,195.1 96.0,195.1 96.8,195.1 96.8,195.6 97.6,195.6 97.6,194.6 98.4,194.6 98.4,195.2 99.2,195.2 99.2,195.3 100.1,195.3 100.1,195.6 100.9,195.6 100.9,195.3 101.7,195.3 101.7,195.4 102.5,195.4 102.5,195.2 103.3,195.2 103.3,195.8 104.1,195.8 104.1,195.1 104.9,195.1 104.9,195.3 105.8,195.3 105.8,196.2 106.6,196.2 106.6,195.7 107.4,195.7 107.4,194.5 108.2,194.5 108.2,194.7 109.0,194.7 109.0,195.1 109.8,195.1 109.8,195.6 110.6,195.6 110.6,195.6 111.4,195.6 111.4,195.5 112.2,195.5 112.2,194.6 113.1,194.6 113.1,194.4 113.9,194.4 113.9,195.1 114.7,195.1 114.7,195.4 115.5,195.4 115.5,195.8 116.3,195.8 116.3,194.6 117.1,194.6 117.1,195.0 117.9,195.0 117.9,195.4 118.8,195.4 118.8,195.1 119.6,195.1 119.6,195.5 120.4,195.5 120.4,193.5 121.2,193.5 121.2,194.9 122.0,194.9 122.0,195.1 122.8,195.1 122.8,194.8 123.6,194.8 123.6,194.6 124.4,194.6 124.4,194.7 125.3,194.7 125.3,195.1 126.1,195.1 126.1,195.0 126.9,195.0 126.9,194.7 127.7,194.7 127.7,195.3 128.5,195.3 128.5,194.6 129.3,194.6 129.3,194.7 130.1,194.7 130.1,143.3 130.9,143.3 130.9,143.0 131.8,143.0 131.8,142.2 132.6,142.2 132.6,141.9 133.4,141.9 133.4,143.0 134.2,143.0 134.2,142.6 135.0,142.6 135.0,142.4 135.8,142.4 135.8,142.9 136.6,142.9 136.6,143.1 137.4,143.1 137.4,143.2 138.2,143.2 138.2,142.1 139.1,142.1 139.1,143.1 139.9,143.1 139.9,142.4 140.7,142.4 140.7,143.0 141.5,143.0 141.5,141.8 142.3,141.8 142.3,143.1 143.1,143.1 143.1,141.9 143.9,141.9 143.9,143.1 144.8,143.1 144.8,142.9 145.6,142.9 145.6,142.0 146.4,142.0 146.4,142.5 147.2,142.5 147.2,142.4 148.0,142.4 148.0,143.5 148.8,143.5 148.8,142.9 149.6,142.9 149.6,142.3 150.4,142.3 150.4,143.1 151.2,143.1 151.2,141.9 152.1,141.9 152.1,142.4 152.9,142.4 152.9,141.9 153.7,141.9 153.7,141.8 154.5,141.8 154.5,141.3 155.3,141.3 155.3,142.9 156.1,142.9 156.1,141.2 156.9,141.2 156.9,142.8 157.8,142.8 157.8,142.6 158.6,142.6 158.6,142.3 159.4,142.3 159.4,142.7 160.2,142.7 160.2,142.0 161.0,142.0 161.0,141.5 161.8,141.5 161.8,141.2 162.6,141.2 162.6,141.4 163.4,141.4 163.4,141.9 164.2,141.9 164.2,141.6 165.1,141.6 165.1,141.8 165.9,141.8 165.9,142.0 166.7,142.0 166.7,142.0 167.5,142.0 167.5,141.5 168.3,141.5 168.3,142.4 169.1,142.4 169.1,141.7 169.9,141.7 169.9,142.4 170.8,142.4 170.8,141.9 171.6,141.9 171.6,141.7 172.4,141.7 172.4,141.1 173.2,141.1 173.2,141.5 174.0,141.5 174.0,141.6 174.8,141.6 174.8,141.7 175.6,141.7 175.6,140.3 176.4,140.3 176.4,140.7 177.2,140.7 177.2,140.6 178.1,140.6 178.1,141.0 178.9,141.0 178.9,141.8 179.7,141.8 179.7,141.6 180.5,141.6 180.5,141.5 181.3,141.5 181.3,141.0 182.1,141.0 182.1,141.1 182.9,141.1 182.9,140.7 183.8,140.7 183.8,140.4 184.6,140.4 184.6,142.1 185.4,142.1 185.4,141.7 186.2,141.7 186.2,141.2 187.0,141.2 187.0,141.5 187.8,141.5 187.8,140.4 188.6,140.4 188.6,141.0 189.4,141.0 189.4,141.5 190.2,141.5 190.2,141.2 191.1,141.2 191.1,142.1 191.9,142.1 191.9,140.4 192.7,140.4 192.7,141.1 193.5,141.1 193.5,141.5 194.3,141.5 194.3,140.9 195.1,140.9 195.1,141.7 195.9,141.7 195.9,140.4 196.8,140.4 196.8,141.9 197.6,141.9 197.6,141.1 198.4,141.1 198.4,141.4 199.2,141.4 199.2,140.6 200.0,140.6 200.0,141.4 200.8,141.4 200.8,140.1 201.6,140.1 201.6,141.2 202.4,141.2 202.4,140.8 203.2,140.8 203.2,141.4 204.1,141.4 204.1,141.5 204.9,141.5 204.9,141.2 205.7,141.2 205.7,142.0 206.5,142.0 206.5,142.6 207.3,142.6 207.3,142.3 208.1,142.3 208.1,140.6 208.9,140.6 208.9,140.8 209.8,140.8 209.8,140.9 210.6,140.9 210.6,141.1 211.4,141.1 211.4,141.6 212.2,141.6 212.2,141.0 213.0,141.0 213.0,141.5 213.8,141.5 213.8,141.4 214.6,141.4 214.6,142.0 215.4,142.0 215.4,140.6 216.2,140.6 216.2,1Line truncated
<circle class="nj-charts-json-dot" cx="88.7" cy="194.6" r="3.5"><title>#5234: 1.22&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="88.7" y1="54.0" x2="88.7" y2="189.6"/>
<circle class="nj-theme-dot" cx="88.7" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="88.7" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="130.1" cy="143.3" r="3.5"><title>#5283: 2.6&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="130.1" y1="54.0" x2="130.1" y2="138.3"/>
<circle class="nj-theme-dot" cx="130.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="130.1" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="222.8" cy="135.2" r="3.5"><title>#5592: 2.9&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="222.8" y1="54.0" x2="222.8" y2="130.2"/>
<circle class="nj-theme-dot" cx="222.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="222.8" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="243.1" cy="118.7" r="3.5"><title>#5809: 3.7&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="243.9" cy="112.7" r="3.5"><title>#5810: 4.0&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="243.9" y1="36.0" x2="243.9" y2="107.7"/>
<circle class="nj-theme-dot" cx="234.9" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="234.9" y="32.0" text-anchor="middle">4</text>
<circle class="nj-theme-dot" cx="252.9" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="252.9" y="32.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="273.1" cy="99.2" r="3.5"><title>#5853: 4.9&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="273.1" y1="54.0" x2="273.1" y2="94.2"/>
<circle class="nj-theme-dot" cx="273.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="273.1" 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: 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-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 353 commits, ending at 3.3x. 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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,206.7 48.1,207.5 48.9,207.5 48.9,207.7 49.7,207.7 49.7,207.3 50.5,207.3 50.5,207.9 51.3,207.9 51.3,206.6 52.1,206.6 52.1,207.5 52.9,207.5 52.9,208.0 53.8,208.0 53.8,207.6 54.6,207.6 54.6,207.2 55.4,207.2 55.4,207.5 56.2,207.5 56.2,206.6 57.0,206.6 57.0,207.1 57.8,207.1 57.8,207.1 58.6,207.1 58.6,207.2 59.4,207.2 59.4,206.6 60.2,206.6 60.2,207.5 61.1,207.5 61.1,207.6 61.9,207.6 61.9,207.7 62.7,207.7 62.7,207.2 63.5,207.2 63.5,206.5 64.3,206.5 64.3,206.8 65.1,206.8 65.1,207.1 65.9,207.1 65.9,207.0 66.8,207.0 66.8,207.1 67.6,207.1 67.6,206.7 68.4,206.7 68.4,208.2 69.2,208.2 69.2,207.5 70.0,207.5 70.0,206.6 70.8,206.6 70.8,206.7 71.6,206.7 71.6,206.3 72.4,206.3 72.4,208.4 73.2,208.4 73.2,207.3 74.1,207.3 74.1,206.8 74.9,206.8 74.9,208.0 75.7,208.0 75.7,207.8 76.5,207.8 76.5,207.1 77.3,207.1 77.3,207.5 78.1,207.5 78.1,207.9 78.9,207.9 78.9,206.3 79.8,206.3 79.8,206.8 80.6,206.8 80.6,207.5 81.4,207.5 81.4,208.1 82.2,208.1 82.2,206.6 83.0,206.6 83.0,207.2 83.8,207.2 83.8,207.2 84.6,207.2 84.6,207.4 85.4,207.4 85.4,207.0 86.2,207.0 86.2,206.7 87.1,206.7 87.1,206.5 87.9,206.5 87.9,207.6 88.7,207.6 88.7,207.4 89.5,207.4 89.5,207.2 90.3,207.2 90.3,207.5 91.1,207.5 91.1,207.6 91.9,207.6 91.9,208.0 92.8,208.0 92.8,208.2 93.6,208.2 93.6,206.7 94.4,206.7 94.4,207.4 95.2,207.4 95.2,206.7 96.0,206.7 96.0,206.6 96.8,206.6 96.8,208.0 97.6,208.0 97.6,208.0 98.4,208.0 98.4,206.3 99.2,206.3 99.2,208.3 100.1,208.3 100.1,207.8 100.9,207.8 100.9,207.4 101.7,207.4 101.7,206.3 102.5,206.3 102.5,208.1 103.3,208.1 103.3,207.5 104.1,207.5 104.1,207.4 104.9,207.4 104.9,207.5 105.8,207.5 105.8,207.7 106.6,207.7 106.6,208.0 107.4,208.0 107.4,207.0 108.2,207.0 108.2,207.5 109.0,207.5 109.0,207.2 109.8,207.2 109.8,207.7 110.6,207.7 110.6,207.3 111.4,207.3 111.4,208.0 112.2,208.0 112.2,206.7 113.1,206.7 113.1,206.6 113.9,206.6 113.9,207.2 114.7,207.2 114.7,208.1 115.5,208.1 115.5,208.1 116.3,208.1 116.3,206.7 117.1,206.7 117.1,207.8 117.9,207.8 117.9,207.6 118.8,207.6 118.8,207.4 119.6,207.4 119.6,207.1 120.4,207.1 120.4,207.5 121.2,207.5 121.2,208.8 122.0,208.8 122.0,209.2 122.8,209.2 122.8,208.4 123.6,208.4 123.6,208.3 124.4,208.3 124.4,208.0 125.3,208.0 125.3,209.0 126.1,209.0 126.1,208.5 126.9,208.5 126.9,209.1 127.7,209.1 127.7,209.2 128.5,209.2 128.5,208.6 129.3,208.6 129.3,207.7 130.1,207.7 130.1,207.7 130.9,207.7 130.9,207.5 131.8,207.5 131.8,202.2 132.6,202.2 132.6,202.3 133.4,202.3 133.4,201.7 134.2,201.7 134.2,202.3 135.0,202.3 135.0,201.9 135.8,201.9 135.8,201.2 136.6,201.2 136.6,202.1 137.4,202.1 137.4,202.6 138.2,202.6 138.2,201.5 139.1,201.5 139.1,202.3 139.9,202.3 139.9,202.3 140.7,202.3 140.7,201.7 141.5,201.7 141.5,201.3 142.3,201.3 142.3,202.5 143.1,202.5 143.1,201.1 143.9,201.1 143.9,202.9 144.8,202.9 144.8,202.2 145.6,202.2 145.6,201.7 146.4,201.7 146.4,201.7 147.2,201.7 147.2,201.6 148.0,201.6 148.0,203.0 148.8,203.0 148.8,202.7 149.6,202.7 149.6,202.4 150.4,202.4 150.4,202.8 151.2,202.8 151.2,202.1 152.1,202.1 152.1,203.1 152.9,203.1 152.9,202.3 153.7,202.3 153.7,202.3 154.5,202.3 154.5,201.8 155.3,201.8 155.3,203.1 156.1,203.1 156.1,201.8 156.9,201.8 156.9,202.6 157.8,202.6 157.8,202.6 158.6,202.6 158.6,202.9 159.4,202.9 159.4,202.3 160.2,202.3 160.2,202.3 161.0,202.3 161.0,201.6 161.8,201.6 161.8,201.5 162.6,201.5 162.6,202.4 163.4,202.4 163.4,201.7 164.2,201.7 164.2,201.2 165.1,201.2 165.1,202.2 165.9,202.2 165.9,201.6 166.7,201.6 166.7,201.6 167.5,201.6 167.5,201.8 168.3,201.8 168.3,202.1 169.1,202.1 169.1,201.7 169.9,201.7 169.9,201.4 170.8,201.4 170.8,202.2 171.6,202.2 171.6,202.7 172.4,202.7 172.4,202.4 173.2,202.4 173.2,201.7 174.0,201.7 174.0,201.7 174.8,201.7 174.8,202.3 175.6,202.3 175.6,201.6 176.4,201.6 176.4,201.7 177.2,201.7 177.2,202.2 178.1,202.2 178.1,202.2 178.9,202.2 178.9,202.4 179.7,202.4 179.7,201.7 180.5,201.7 180.5,202.1 181.3,202.1 181.3,201.6 182.1,201.6 182.1,202.2 182.9,202.2 182.9,201.9 183.8,201.9 183.8,201.9 184.6,201.9 184.6,202.5 185.4,202.5 185.4,201.6 186.2,201.6 186.2,202.1 187.0,202.1 187.0,202.3 187.8,202.3 187.8,201.8 188.6,201.8 188.6,201.5 189.4,201.5 189.4,202.3 190.2,202.3 190.2,202.2 191.1,202.2 191.1,202.9 191.9,202.9 191.9,201.3 192.7,201.3 192.7,202.2 193.5,202.2 193.5,203.6 194.3,203.6 194.3,201.9 195.1,201.9 195.1,202.4 195.9,202.4 195.9,201.7 196.8,201.7 196.8,202.7 197.6,202.7 197.6,202.3 198.4,202.3 198.4,202.5 199.2,202.5 199.2,202.1 200.0,202.1 200.0,203.4 200.8,203.4 200.8,202.1 201.6,202.1 201.6,202.3 202.4,202.3 202.4,201.9 203.2,201.9 203.2,202.3 204.1,202.3 204.1,201.7 204.9,201.7 204.9,202.4 205.7,202.4 205.7,202.3 206.5,202.3 206.5,202.9 207.3,202.9 207.3,202.9 208.1,202.9 208.1,202.2 208.9,202.2 208.9,202.4 209.8,202.4 209.8,202.2 210.6,202.2 210.6,202.7 211.4,202.7 211.4,202.5 212.2,202.5 212.2,202.5 213.0,202.5 213.0,201.5 213.8,201.5 213.8,203.1 214.6,203.1 214.6,203.2 215.4,203.2 215.4,201.5 216.2,201.5 216.2,2Line truncated
<circle class="nj-charts-json-dot" cx="131.8" cy="202.2" r="3.5"><title>#5285: 1.09&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="131.8" y1="54.0" x2="131.8" y2="197.2"/>
<circle class="nj-theme-dot" cx="131.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="131.8" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="246.3" cy="130.7" r="3.5"><title>#5634: 3.1&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="246.3" y1="54.0" x2="246.3" y2="125.7"/>
<circle class="nj-theme-dot" cx="246.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="246.3" 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: 10 KiB

@@ -1,37 +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 353 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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,206.8 48.1,208.0 48.9,208.0 48.9,207.4 49.7,207.4 49.7,207.3 50.5,207.3 50.5,208.0 51.3,208.0 51.3,206.8 52.1,206.8 52.1,207.2 52.9,207.2 52.9,208.0 53.8,208.0 53.8,207.2 54.6,207.2 54.6,207.5 55.4,207.5 55.4,206.8 56.2,206.8 56.2,206.9 57.0,206.9 57.0,207.5 57.8,207.5 57.8,207.3 58.6,207.3 58.6,207.8 59.4,207.8 59.4,206.8 60.2,206.8 60.2,207.8 61.1,207.8 61.1,207.4 61.9,207.4 61.9,208.0 62.7,208.0 62.7,207.4 63.5,207.4 63.5,207.3 64.3,207.3 64.3,206.9 65.1,206.9 65.1,207.3 65.9,207.3 65.9,207.4 66.8,207.4 66.8,207.6 67.6,207.6 67.6,207.5 68.4,207.5 68.4,207.6 69.2,207.6 69.2,207.4 70.0,207.4 70.0,207.2 70.8,207.2 70.8,207.1 71.6,207.1 71.6,207.3 72.4,207.3 72.4,207.7 73.2,207.7 73.2,207.8 74.1,207.8 74.1,206.9 74.9,206.9 74.9,207.6 75.7,207.6 75.7,207.0 76.5,207.0 76.5,207.0 77.3,207.0 77.3,207.3 78.1,207.3 78.1,207.6 78.9,207.6 78.9,206.8 79.8,206.8 79.8,207.7 80.6,207.7 80.6,207.4 81.4,207.4 81.4,207.5 82.2,207.5 82.2,207.1 83.0,207.1 83.0,207.3 83.8,207.3 83.8,207.5 84.6,207.5 84.6,207.3 85.4,207.3 85.4,207.3 86.2,207.3 86.2,206.9 87.1,206.9 87.1,207.4 87.9,207.4 87.9,207.9 88.7,207.9 88.7,207.3 89.5,207.3 89.5,206.8 90.3,206.8 90.3,207.6 91.1,207.6 91.1,207.7 91.9,207.7 91.9,208.6 92.8,208.6 92.8,208.5 93.6,208.5 93.6,208.6 94.4,208.6 94.4,209.2 95.2,209.2 95.2,208.5 96.0,208.5 96.0,208.2 96.8,208.2 96.8,209.3 97.6,209.3 97.6,208.4 98.4,208.4 98.4,208.4 99.2,208.4 99.2,209.0 100.1,209.0 100.1,209.0 100.9,209.0 100.9,208.7 101.7,208.7 101.7,208.9 102.5,208.9 102.5,208.7 103.3,208.7 103.3,209.0 104.1,209.0 104.1,208.8 104.9,208.8 104.9,208.7 105.8,208.7 105.8,209.3 106.6,209.3 106.6,208.6 107.4,208.6 107.4,208.5 108.2,208.5 108.2,208.4 109.0,208.4 109.0,208.0 109.8,208.0 109.8,208.9 110.6,208.9 110.6,208.6 111.4,208.6 111.4,208.9 112.2,208.9 112.2,208.1 113.1,208.1 113.1,208.0 113.9,208.0 113.9,208.6 114.7,208.6 114.7,208.5 115.5,208.5 115.5,209.1 116.3,209.1 116.3,208.0 117.1,208.0 117.1,209.1 117.9,209.1 117.9,208.9 118.8,208.9 118.8,208.5 119.6,208.5 119.6,209.1 120.4,209.1 120.4,209.0 121.2,209.0 121.2,208.8 122.0,208.8 122.0,208.6 122.8,208.6 122.8,208.6 123.6,208.6 123.6,208.2 124.4,208.2 124.4,209.0 125.3,209.0 125.3,209.2 126.1,209.2 126.1,209.1 126.9,209.1 126.9,209.2 127.7,209.2 127.7,209.2 128.5,209.2 128.5,208.5 129.3,208.5 129.3,208.7 130.1,208.7 130.1,209.5 130.9,209.5 130.9,208.4 131.8,208.4 131.8,147.4 132.6,147.4 132.6,148.3 133.4,148.3 133.4,148.4 134.2,148.4 134.2,147.5 135.0,147.5 135.0,147.5 135.8,147.5 135.8,147.7 136.6,147.7 136.6,148.2 137.4,148.2 137.4,148.2 138.2,148.2 138.2,147.3 139.1,147.3 139.1,148.1 139.9,148.1 139.9,147.2 140.7,147.2 140.7,147.5 141.5,147.5 141.5,147.3 142.3,147.3 142.3,148.4 143.1,148.4 143.1,147.4 143.9,147.4 143.9,148.3 144.8,148.3 144.8,148.5 145.6,148.5 145.6,147.7 146.4,147.7 146.4,147.8 147.2,147.8 147.2,148.0 148.0,148.0 148.0,148.5 148.8,148.5 148.8,148.0 149.6,148.0 149.6,148.1 150.4,148.1 150.4,148.2 151.2,148.2 151.2,148.3 152.1,148.3 152.1,149.0 152.9,149.0 152.9,148.7 153.7,148.7 153.7,148.2 154.5,148.2 154.5,148.1 155.3,148.1 155.3,148.9 156.1,148.9 156.1,147.7 156.9,147.7 156.9,149.2 157.8,149.2 157.8,149.1 158.6,149.1 158.6,148.8 159.4,148.8 159.4,148.1 160.2,148.1 160.2,148.7 161.0,148.7 161.0,147.7 161.8,147.7 161.8,147.9 162.6,147.9 162.6,147.7 163.4,147.7 163.4,148.3 164.2,148.3 164.2,148.0 165.1,148.0 165.1,148.2 165.9,148.2 165.9,148.4 166.7,148.4 166.7,148.3 167.5,148.3 167.5,148.1 168.3,148.1 168.3,149.0 169.1,149.0 169.1,147.8 169.9,147.8 169.9,148.8 170.8,148.8 170.8,148.3 171.6,148.3 171.6,148.0 172.4,148.0 172.4,147.8 173.2,147.8 173.2,148.0 174.0,148.0 174.0,147.7 174.8,147.7 174.8,148.2 175.6,148.2 175.6,147.1 176.4,147.1 176.4,147.9 177.2,147.9 177.2,147.9 178.1,147.9 178.1,147.9 178.9,147.9 178.9,147.7 179.7,147.7 179.7,148.0 180.5,148.0 180.5,147.4 181.3,147.4 181.3,147.5 182.1,147.5 182.1,147.5 182.9,147.5 182.9,147.0 183.8,147.0 183.8,147.0 184.6,147.0 184.6,148.2 185.4,148.2 185.4,147.7 186.2,147.7 186.2,148.0 187.0,148.0 187.0,148.2 187.8,148.2 187.8,147.7 188.6,147.7 188.6,147.8 189.4,147.8 189.4,148.2 190.2,148.2 190.2,148.3 191.1,148.3 191.1,148.5 191.9,148.5 191.9,148.1 192.7,148.1 192.7,147.9 193.5,147.9 193.5,148.2 194.3,148.2 194.3,147.5 195.1,147.5 195.1,148.1 195.9,148.1 195.9,147.6 196.8,147.6 196.8,148.4 197.6,148.4 197.6,148.2 198.4,148.2 198.4,148.3 199.2,148.3 199.2,148.7 200.0,148.7 200.0,149.4 200.8,149.4 200.8,148.7 201.6,148.7 201.6,149.5 202.4,149.5 202.4,148.2 203.2,148.2 203.2,148.5 204.1,148.5 204.1,149.1 204.9,149.1 204.9,148.8 205.7,148.8 205.7,149.2 206.5,149.2 206.5,149.3 207.3,149.3 207.3,149.1 208.1,149.1 208.1,148.6 208.9,148.6 208.9,148.9 209.8,148.9 209.8,148.5 210.6,148.5 210.6,148.9 211.4,148.9 211.4,149.0 212.2,149.0 212.2,149.0 213.0,149.0 213.0,148.5 213.8,148.5 213.8,149.1 214.6,149.1 214.6,149.2 215.4,149.2 215.4,148.3 216.2,148.3 216.2,1Line truncated
<circle class="nj-charts-json-dot" cx="131.8" cy="147.4" r="3.5"><title>#5285: 3.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="131.8" y1="54.0" x2="131.8" y2="142.4"/>
<circle class="nj-theme-dot" cx="131.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="131.8" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="245.5" cy="139.0" r="3.5"><title>#5738: 3.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="245.5" y1="54.0" x2="245.5" y2="134.0"/>
<circle class="nj-theme-dot" cx="245.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="245.5" y="50.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="275.6" cy="131.0" r="3.5"><title>#5878: 4.5&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="281.2" cy="109.6" r="3.5"><title>#5883: 6.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="281.2" y1="54.0" x2="281.2" y2="104.6"/>
<circle class="nj-theme-dot" cx="281.2" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="281.2" 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,36 +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 353 commits, ending at 2.6x. Labeled steps, by theme: 1, 4, U, U.</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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,208.0 48.1,208.4 48.9,208.4 48.9,208.6 49.7,208.6 49.7,208.3 50.5,208.3 50.5,209.1 51.3,209.1 51.3,207.8 52.1,207.8 52.1,208.5 52.9,208.5 52.9,208.6 53.8,208.6 53.8,208.6 54.6,208.6 54.6,207.7 55.4,207.7 55.4,207.1 56.2,207.1 56.2,207.3 57.0,207.3 57.0,206.9 57.8,206.9 57.8,207.1 58.6,207.1 58.6,207.0 59.4,207.0 59.4,207.1 60.2,207.1 60.2,207.1 61.1,207.1 61.1,207.5 61.9,207.5 61.9,207.5 62.7,207.5 62.7,206.9 63.5,206.9 63.5,207.0 64.3,207.0 64.3,206.2 65.1,206.2 65.1,207.1 65.9,207.1 65.9,208.5 66.8,208.5 66.8,208.0 67.6,208.0 67.6,207.8 68.4,207.8 68.4,208.5 69.2,208.5 69.2,207.8 70.0,207.8 70.0,207.0 70.8,207.0 70.8,208.1 71.6,208.1 71.6,208.2 72.4,208.2 72.4,208.6 73.2,208.6 73.2,208.1 74.1,208.1 74.1,207.2 74.9,207.2 74.9,208.3 75.7,208.3 75.7,207.4 76.5,207.4 76.5,207.9 77.3,207.9 77.3,207.7 78.1,207.7 78.1,208.6 78.9,208.6 78.9,207.3 79.8,207.3 79.8,207.9 80.6,207.9 80.6,208.4 81.4,208.4 81.4,208.5 82.2,208.5 82.2,208.0 83.0,208.0 83.0,207.1 83.8,207.1 83.8,208.1 84.6,208.1 84.6,208.1 85.4,208.1 85.4,207.8 86.2,207.8 86.2,207.9 87.1,207.9 87.1,207.9 87.9,207.9 87.9,208.7 88.7,208.7 88.7,208.1 89.5,208.1 89.5,168.9 90.3,168.9 90.3,170.3 91.1,170.3 91.1,169.9 91.9,169.9 91.9,169.0 92.8,169.0 92.8,169.6 93.6,169.6 93.6,169.1 94.4,169.1 94.4,170.1 95.2,170.1 95.2,168.8 96.0,168.8 96.0,167.9 96.8,167.9 96.8,170.4 97.6,170.4 97.6,169.5 98.4,169.5 98.4,169.7 99.2,169.7 99.2,172.9 100.1,172.9 100.1,170.5 100.9,170.5 100.9,170.4 101.7,170.4 101.7,170.1 102.5,170.1 102.5,170.2 103.3,170.2 103.3,170.7 104.1,170.7 104.1,170.5 104.9,170.5 104.9,170.4 105.8,170.4 105.8,171.1 106.6,171.1 106.6,170.2 107.4,170.2 107.4,168.6 108.2,168.6 108.2,168.9 109.0,168.9 109.0,168.8 109.8,168.8 109.8,170.5 110.6,170.5 110.6,169.2 111.4,169.2 111.4,169.8 112.2,169.8 112.2,168.2 113.1,168.2 113.1,168.3 113.9,168.3 113.9,169.9 114.7,169.9 114.7,170.3 115.5,170.3 115.5,170.5 116.3,170.5 116.3,169.2 117.1,169.2 117.1,170.5 117.9,170.5 117.9,170.1 118.8,170.1 118.8,170.0 119.6,170.0 119.6,170.0 120.4,170.0 120.4,169.7 121.2,169.7 121.2,169.9 122.0,169.9 122.0,169.2 122.8,169.2 122.8,169.6 123.6,169.6 123.6,170.0 124.4,170.0 124.4,170.0 125.3,170.0 125.3,170.5 126.1,170.5 126.1,170.8 126.9,170.8 126.9,170.5 127.7,170.5 127.7,170.8 128.5,170.8 128.5,169.2 129.3,169.2 129.3,128.6 130.1,128.6 130.1,121.0 130.9,121.0 130.9,120.5 131.8,120.5 131.8,120.8 132.6,120.8 132.6,120.9 133.4,120.9 133.4,120.2 134.2,120.2 134.2,116.5 135.0,116.5 135.0,117.5 135.8,117.5 135.8,117.4 136.6,117.4 136.6,118.0 137.4,118.0 137.4,118.3 138.2,118.3 138.2,118.0 139.1,118.0 139.1,120.1 139.9,120.1 139.9,118.9 140.7,118.9 140.7,119.6 141.5,119.6 141.5,119.0 142.3,119.0 142.3,120.9 143.1,120.9 143.1,118.6 143.9,118.6 143.9,121.1 144.8,121.1 144.8,120.1 145.6,120.1 145.6,118.4 146.4,118.4 146.4,119.3 147.2,119.3 147.2,119.0 148.0,119.0 148.0,120.2 148.8,120.2 148.8,119.0 149.6,119.0 149.6,119.4 150.4,119.4 150.4,119.8 151.2,119.8 151.2,120.4 152.1,120.4 152.1,120.6 152.9,120.6 152.9,119.6 153.7,119.6 153.7,118.8 154.5,118.8 154.5,118.4 155.3,118.4 155.3,120.2 156.1,120.2 156.1,119.3 156.9,119.3 156.9,119.9 157.8,119.9 157.8,119.6 158.6,119.6 158.6,119.7 159.4,119.7 159.4,119.2 160.2,119.2 160.2,119.5 161.0,119.5 161.0,118.0 161.8,118.0 161.8,150.3 162.6,150.3 162.6,150.5 163.4,150.5 163.4,150.6 164.2,150.6 164.2,151.3 165.1,151.3 165.1,151.4 165.9,151.4 165.9,150.7 166.7,150.7 166.7,152.1 167.5,152.1 167.5,151.8 168.3,151.8 168.3,152.4 169.1,152.4 169.1,150.6 169.9,150.6 169.9,152.8 170.8,152.8 170.8,154.2 171.6,154.2 171.6,152.8 172.4,152.8 172.4,152.9 173.2,152.9 173.2,153.6 174.0,153.6 174.0,151.7 174.8,151.7 174.8,153.8 175.6,153.8 175.6,151.6 176.4,151.6 176.4,152.6 177.2,152.6 177.2,153.5 178.1,153.5 178.1,151.8 178.9,151.8 178.9,152.7 179.7,152.7 179.7,153.6 180.5,153.6 180.5,152.7 181.3,152.7 181.3,152.5 182.1,152.5 182.1,152.7 182.9,152.7 182.9,151.6 183.8,151.6 183.8,153.2 184.6,153.2 184.6,154.6 185.4,154.6 185.4,152.1 186.2,152.1 186.2,152.9 187.0,152.9 187.0,153.9 187.8,153.9 187.8,153.0 188.6,153.0 188.6,152.6 189.4,152.6 189.4,154.0 190.2,154.0 190.2,154.0 191.1,154.0 191.1,154.3 191.9,154.3 191.9,152.5 192.7,152.5 192.7,154.4 193.5,154.4 193.5,154.2 194.3,154.2 194.3,151.8 195.1,151.8 195.1,154.0 195.9,154.0 195.9,153.0 196.8,153.0 196.8,152.2 197.6,152.2 197.6,153.7 198.4,153.7 198.4,153.8 199.2,153.8 199.2,153.9 200.0,153.9 200.0,155.5 200.8,155.5 200.8,153.4 201.6,153.4 201.6,155.4 202.4,155.4 202.4,152.8 203.2,152.8 203.2,154.0 204.1,154.0 204.1,152.3 204.9,152.3 204.9,153.2 205.7,153.2 205.7,153.5 206.5,153.5 206.5,153.6 207.3,153.6 207.3,154.6 208.1,154.6 208.1,152.7 208.9,152.7 208.9,155.4 209.8,155.4 209.8,152.5 210.6,152.5 210.6,153.3 211.4,153.3 211.4,153.3 212.2,153.3 212.2,154.5 213.0,154.5 213.0,152.6 213.8,152.6 213.8,153.0 214.6,153.0 214.6,154.3 215.4,154.3 215.4,122.0 216.2,122.0 216.2,1Line truncated
<circle class="nj-charts-json-dot" cx="89.5" cy="168.9" r="3.5"><title>#5233: 1.47&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="89.5" y1="54.0" x2="89.5" y2="163.9"/>
<circle class="nj-theme-dot" cx="89.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="89.5" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="129.3" cy="128.6" r="3.5"><title>#5501: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="129.3" y1="54.0" x2="129.3" y2="123.6"/>
<circle class="nj-theme-dot" cx="129.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="129.3" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="161.8" cy="150.3" r="3.5"><title>#5185: 1.76&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="161.8" y1="54.0" x2="161.8" y2="145.3"/>
<circle class="nj-theme-dot nj-theme-dot--other" cx="161.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="161.8" y="50.0" text-anchor="middle">U</text>
<circle class="nj-charts-json-dot" cx="215.4" cy="122.0" r="3.5"><title>#5746: 2.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="215.4" y1="54.0" x2="215.4" y2="117.0"/>
<circle class="nj-theme-dot nj-theme-dot--other" cx="215.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="215.4" y="50.0" text-anchor="middle">U</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,44 +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 353 commits, ending at 2.8x. Labeled steps, by theme: 4, 1, 3, 3, 3, 4.</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="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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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,208.1 46.4,208.1 46.4,207.7 47.2,207.7 47.2,207.2 48.1,207.2 48.1,208.0 48.9,208.0 48.9,208.2 49.7,208.2 49.7,207.8 50.5,207.8 50.5,208.5 51.3,208.5 51.3,207.3 52.1,207.3 52.1,208.0 52.9,208.0 52.9,209.1 53.8,209.1 53.8,208.5 54.6,208.5 54.6,208.1 55.4,208.1 55.4,207.7 56.2,207.7 56.2,209.8 57.0,209.8 57.0,208.6 57.8,208.6 57.8,208.1 58.6,208.1 58.6,208.1 59.4,208.1 59.4,207.0 60.2,207.0 60.2,207.8 61.1,207.8 61.1,207.6 61.9,207.6 61.9,208.1 62.7,208.1 62.7,208.4 63.5,208.4 63.5,207.8 64.3,207.8 64.3,207.4 65.1,207.4 65.1,208.3 65.9,208.3 65.9,207.3 66.8,207.3 66.8,207.8 67.6,207.8 67.6,207.9 68.4,207.9 68.4,207.9 69.2,207.9 69.2,207.5 70.0,207.5 70.0,207.5 70.8,207.5 70.8,208.1 71.6,208.1 71.6,208.1 72.4,208.1 72.4,207.9 73.2,207.9 73.2,207.8 74.1,207.8 74.1,207.1 74.9,207.1 74.9,207.6 75.7,207.6 75.7,207.8 76.5,207.8 76.5,207.3 77.3,207.3 77.3,207.6 78.1,207.6 78.1,208.6 78.9,208.6 78.9,206.5 79.8,206.5 79.8,208.0 80.6,208.0 80.6,208.7 81.4,208.7 81.4,208.0 82.2,208.0 82.2,207.7 83.0,207.7 83.0,208.4 83.8,208.4 83.8,207.9 84.6,207.9 84.6,207.5 85.4,207.5 85.4,207.9 86.2,207.9 86.2,207.4 87.1,207.4 87.1,207.5 87.9,207.5 87.9,208.5 88.7,208.5 88.7,197.5 89.5,197.5 89.5,197.9 90.3,197.9 90.3,196.9 91.1,196.9 91.1,197.0 91.9,197.0 91.9,197.7 92.8,197.7 92.8,196.0 93.6,196.0 93.6,197.3 94.4,197.3 94.4,198.1 95.2,198.1 95.2,197.4 96.0,197.4 96.0,197.0 96.8,197.0 96.8,197.5 97.6,197.5 97.6,197.3 98.4,197.3 98.4,197.7 99.2,197.7 99.2,197.7 100.1,197.7 100.1,197.6 100.9,197.6 100.9,196.9 101.7,196.9 101.7,197.9 102.5,197.9 102.5,197.9 103.3,197.9 103.3,197.6 104.1,197.6 104.1,197.6 104.9,197.6 104.9,197.6 105.8,197.6 105.8,198.1 106.6,198.1 106.6,198.0 107.4,198.0 107.4,195.3 108.2,195.3 108.2,196.6 109.0,196.6 109.0,197.9 109.8,197.9 109.8,197.0 110.6,197.0 110.6,196.3 111.4,196.3 111.4,196.8 112.2,196.8 112.2,196.6 113.1,196.6 113.1,196.6 113.9,196.6 113.9,197.7 114.7,197.7 114.7,197.5 115.5,197.5 115.5,198.1 116.3,198.1 116.3,195.9 117.1,195.9 117.1,197.5 117.9,197.5 117.9,197.6 118.8,197.6 118.8,196.7 119.6,196.7 119.6,197.0 120.4,197.0 120.4,198.0 121.2,198.0 121.2,197.0 122.0,197.0 122.0,197.2 122.8,197.2 122.8,196.6 123.6,196.6 123.6,197.0 124.4,197.0 124.4,197.2 125.3,197.2 125.3,197.6 126.1,197.6 126.1,197.8 126.9,197.8 126.9,197.2 127.7,197.2 127.7,197.6 128.5,197.6 128.5,197.3 129.3,197.3 129.3,197.0 130.1,197.0 130.1,168.6 130.9,168.6 130.9,169.7 131.8,169.7 131.8,170.1 132.6,170.1 132.6,168.9 133.4,168.9 133.4,168.3 134.2,168.3 134.2,169.9 135.0,169.9 135.0,168.7 135.8,168.7 135.8,168.3 136.6,168.3 136.6,169.7 137.4,169.7 137.4,170.9 138.2,170.9 138.2,168.1 139.1,168.1 139.1,170.2 139.9,170.2 139.9,169.1 140.7,169.1 140.7,170.1 141.5,170.1 141.5,168.5 142.3,168.5 142.3,169.7 143.1,169.7 143.1,170.1 143.9,170.1 143.9,169.8 144.8,169.8 144.8,169.1 145.6,169.1 145.6,167.2 146.4,167.2 146.4,169.7 147.2,169.7 147.2,168.6 148.0,168.6 148.0,170.3 148.8,170.3 148.8,169.7 149.6,169.7 149.6,168.7 150.4,168.7 150.4,169.3 151.2,169.3 151.2,172.3 152.1,172.3 152.1,171.2 152.9,171.2 152.9,169.1 153.7,169.1 153.7,167.8 154.5,167.8 154.5,169.3 155.3,169.3 155.3,169.1 156.1,169.1 156.1,168.5 156.9,168.5 156.9,168.7 157.8,168.7 157.8,168.6 158.6,168.6 158.6,169.0 159.4,169.0 159.4,168.5 160.2,168.5 160.2,170.9 161.0,170.9 161.0,169.9 161.8,169.9 161.8,168.0 162.6,168.0 162.6,168.8 163.4,168.8 163.4,168.5 164.2,168.5 164.2,168.5 165.1,168.5 165.1,169.9 165.9,169.9 165.9,169.1 166.7,169.1 166.7,168.6 167.5,168.6 167.5,168.6 168.3,168.6 168.3,169.4 169.1,169.4 169.1,169.1 169.9,169.1 169.9,170.2 170.8,170.2 170.8,178.0 171.6,178.0 171.6,177.3 172.4,177.3 172.4,167.7 173.2,167.7 173.2,168.5 174.0,168.5 174.0,168.7 174.8,168.7 174.8,168.5 175.6,168.5 175.6,168.8 176.4,168.8 176.4,168.0 177.2,168.0 177.2,168.2 178.1,168.2 178.1,167.7 178.9,167.7 178.9,167.5 179.7,167.5 179.7,168.1 180.5,168.1 180.5,168.3 181.3,168.3 181.3,168.1 182.1,168.1 182.1,168.1 182.9,168.1 182.9,167.5 183.8,167.5 183.8,166.5 184.6,166.5 184.6,169.1 185.4,169.1 185.4,168.6 186.2,168.6 186.2,168.5 187.0,168.5 187.0,168.1 187.8,168.1 187.8,167.3 188.6,167.3 188.6,168.0 189.4,168.0 189.4,168.3 190.2,168.3 190.2,168.6 191.1,168.6 191.1,169.0 191.9,169.0 191.9,166.6 192.7,166.6 192.7,169.4 193.5,169.4 193.5,169.3 194.3,169.3 194.3,167.3 195.1,167.3 195.1,168.5 195.9,168.5 195.9,167.1 196.8,167.1 196.8,169.4 197.6,169.4 197.6,168.9 198.4,168.9 198.4,167.4 199.2,167.4 199.2,168.4 200.0,168.4 200.0,168.5 200.8,168.5 200.8,166.9 201.6,166.9 201.6,168.7 202.4,168.7 202.4,165.7 203.2,165.7 203.2,167.0 204.1,167.0 204.1,166.6 204.9,166.6 204.9,167.4 205.7,167.4 205.7,167.6 206.5,167.6 206.5,167.2 207.3,167.2 207.3,167.4 208.1,167.4 208.1,166.6 208.9,166.6 208.9,166.2 209.8,166.2 209.8,168.4 210.6,168.4 210.6,167.2 211.4,167.2 211.4,166.7 212.2,166.7 212.2,166.5 213.0,166.5 213.0,166.0 213.8,166.0 213.8,167.4 214.6,167.4 214.6,167.3 215.4,167.3 215.4,167.3 216.2,167.3 216.2,1Line truncated
<circle class="nj-charts-json-dot" cx="88.7" cy="197.5" r="3.5"><title>#5234: 1.11&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="88.7" y1="54.0" x2="88.7" y2="192.5"/>
<circle class="nj-theme-dot" cx="88.7" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="88.7" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="130.1" cy="168.6" r="3.5"><title>#5283: 1.47&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="130.1" y1="54.0" x2="130.1" y2="163.6"/>
<circle class="nj-theme-dot" cx="130.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="130.1" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="172.4" cy="167.7" r="3.5"><title>#5617: 1.48&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="172.4" y1="54.0" x2="172.4" y2="162.7"/>
<circle class="nj-theme-dot" cx="172.4" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="172.4" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="245.5" cy="139.8" r="3.5"><title>#5738: 1.95&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="245.5" y1="54.0" x2="245.5" y2="134.8"/>
<circle class="nj-theme-dot" cx="245.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="245.5" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="271.5" cy="127.4" r="3.5"><title>#5851: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="271.5" y1="54.0" x2="271.5" y2="122.4"/>
<circle class="nj-theme-dot" cx="271.5" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="271.5" y="50.0" text-anchor="middle">3</text>
<circle class="nj-charts-json-dot" cx="285.3" cy="102.2" r="3.5"><title>#5882: 2.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="285.3" y1="36.0" x2="285.3" y2="97.2"/>
<circle class="nj-theme-dot" cx="285.3" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="285.3" y="32.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,45 +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 353 commits, ending at 3.3x. Labeled steps, by theme: 4, 1, 4, 4, 2, 4.</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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,206.5 48.1,208.3 48.9,208.3 48.9,207.3 49.7,207.3 49.7,206.8 50.5,206.8 50.5,207.8 51.3,207.8 51.3,206.8 52.1,206.8 52.1,207.3 52.9,207.3 52.9,207.6 53.8,207.6 53.8,207.8 54.6,207.8 54.6,207.0 55.4,207.0 55.4,207.3 56.2,207.3 56.2,207.2 57.0,207.2 57.0,207.4 57.8,207.4 57.8,207.5 58.6,207.5 58.6,207.4 59.4,207.4 59.4,206.6 60.2,206.6 60.2,207.6 61.1,207.6 61.1,207.6 61.9,207.6 61.9,207.2 62.7,207.2 62.7,207.0 63.5,207.0 63.5,207.6 64.3,207.6 64.3,206.7 65.1,206.7 65.1,207.4 65.9,207.4 65.9,206.8 66.8,206.8 66.8,207.3 67.6,207.3 67.6,207.7 68.4,207.7 68.4,207.9 69.2,207.9 69.2,207.2 70.0,207.2 70.0,206.4 70.8,206.4 70.8,207.6 71.6,207.6 71.6,206.4 72.4,206.4 72.4,208.0 73.2,208.0 73.2,207.4 74.1,207.4 74.1,206.5 74.9,206.5 74.9,207.5 75.7,207.5 75.7,207.2 76.5,207.2 76.5,206.9 77.3,206.9 77.3,207.6 78.1,207.6 78.1,207.6 78.9,207.6 78.9,207.0 79.8,207.0 79.8,206.9 80.6,206.9 80.6,208.0 81.4,208.0 81.4,207.6 82.2,207.6 82.2,206.6 83.0,206.6 83.0,206.8 83.8,206.8 83.8,207.3 84.6,207.3 84.6,206.9 85.4,206.9 85.4,207.6 86.2,207.6 86.2,207.1 87.1,207.1 87.1,207.6 87.9,207.6 87.9,207.9 88.7,207.9 88.7,178.2 89.5,178.2 89.5,177.5 90.3,177.5 90.3,177.7 91.1,177.7 91.1,177.6 91.9,177.6 91.9,177.7 92.8,177.7 92.8,177.1 93.6,177.1 93.6,176.8 94.4,176.8 94.4,177.7 95.2,177.7 95.2,177.6 96.0,177.6 96.0,176.8 96.8,176.8 96.8,177.8 97.6,177.8 97.6,177.0 98.4,177.0 98.4,176.8 99.2,176.8 99.2,178.0 100.1,178.0 100.1,178.1 100.9,178.1 100.9,177.6 101.7,177.6 101.7,177.6 102.5,177.6 102.5,177.4 103.3,177.4 103.3,177.6 104.1,177.6 104.1,177.8 104.9,177.8 104.9,177.5 105.8,177.5 105.8,177.9 106.6,177.9 106.6,177.7 107.4,177.7 107.4,175.9 108.2,175.9 108.2,177.5 109.0,177.5 109.0,177.6 109.8,177.6 109.8,177.6 110.6,177.6 110.6,176.9 111.4,176.9 111.4,177.5 112.2,177.5 112.2,177.4 113.1,177.4 113.1,177.4 113.9,177.4 113.9,176.9 114.7,176.9 114.7,177.9 115.5,177.9 115.5,177.3 116.3,177.3 116.3,176.6 117.1,176.6 117.1,177.4 117.9,177.4 117.9,177.5 118.8,177.5 118.8,177.5 119.6,177.5 119.6,177.4 120.4,177.4 120.4,177.0 121.2,177.0 121.2,177.7 122.0,177.7 122.0,176.2 122.8,176.2 122.8,176.9 123.6,176.9 123.6,177.5 124.4,177.5 124.4,177.8 125.3,177.8 125.3,177.8 126.1,177.8 126.1,177.9 126.9,177.9 126.9,177.3 127.7,177.3 127.7,177.5 128.5,177.5 128.5,177.4 129.3,177.4 129.3,177.1 130.1,177.1 130.1,162.5 130.9,162.5 130.9,162.2 131.8,162.2 131.8,161.8 132.6,161.8 132.6,162.2 133.4,162.2 133.4,161.2 134.2,161.2 134.2,160.7 135.0,160.7 135.0,159.4 135.8,159.4 135.8,160.3 136.6,160.3 136.6,160.4 137.4,160.4 137.4,160.6 138.2,160.6 138.2,159.5 139.1,159.5 139.1,160.4 139.9,160.4 139.9,159.6 140.7,159.6 140.7,160.0 141.5,160.0 141.5,159.9 142.3,159.9 142.3,160.2 143.1,160.2 143.1,159.6 143.9,159.6 143.9,160.8 144.8,160.8 144.8,160.1 145.6,160.1 145.6,159.1 146.4,159.1 146.4,159.7 147.2,159.7 147.2,159.9 148.0,159.9 148.0,160.5 148.8,160.5 148.8,160.2 149.6,160.2 149.6,159.9 150.4,159.9 150.4,160.5 151.2,160.5 151.2,160.5 152.1,160.5 152.1,160.6 152.9,160.6 152.9,159.7 153.7,159.7 153.7,159.5 154.5,159.5 154.5,160.0 155.3,160.0 155.3,160.2 156.1,160.2 156.1,160.0 156.9,160.0 156.9,160.6 157.8,160.6 157.8,159.9 158.6,159.9 158.6,160.2 159.4,160.2 159.4,160.1 160.2,160.1 160.2,160.8 161.0,160.8 161.0,159.2 161.8,159.2 161.8,159.6 162.6,159.6 162.6,159.2 163.4,159.2 163.4,160.0 164.2,160.0 164.2,159.4 165.1,159.4 165.1,159.6 165.9,159.6 165.9,159.5 166.7,159.5 166.7,160.1 167.5,160.1 167.5,159.0 168.3,159.0 168.3,159.4 169.1,159.4 169.1,160.2 169.9,160.2 169.9,161.4 170.8,161.4 170.8,161.7 171.6,161.7 171.6,161.6 172.4,161.6 172.4,160.3 173.2,160.3 173.2,161.1 174.0,161.1 174.0,161.2 174.8,161.2 174.8,161.7 175.6,161.7 175.6,161.2 176.4,161.2 176.4,160.4 177.2,160.4 177.2,161.6 178.1,161.6 178.1,160.6 178.9,160.6 178.9,161.4 179.7,161.4 179.7,161.3 180.5,161.3 180.5,161.3 181.3,161.3 181.3,161.7 182.1,161.7 182.1,161.2 182.9,161.2 182.9,160.1 183.8,160.1 183.8,160.9 184.6,160.9 184.6,161.5 185.4,161.5 185.4,160.6 186.2,160.6 186.2,161.9 187.0,161.9 187.0,161.4 187.8,161.4 187.8,160.1 188.6,160.1 188.6,160.6 189.4,160.6 189.4,162.0 190.2,162.0 190.2,161.5 191.1,161.5 191.1,162.0 191.9,162.0 191.9,161.3 192.7,161.3 192.7,162.3 193.5,162.3 193.5,162.1 194.3,162.1 194.3,160.8 195.1,160.8 195.1,161.5 195.9,161.5 195.9,161.4 196.8,161.4 196.8,162.2 197.6,162.2 197.6,161.4 198.4,161.4 198.4,161.4 199.2,161.4 199.2,161.8 200.0,161.8 200.0,160.7 200.8,160.7 200.8,160.5 201.6,160.5 201.6,160.5 202.4,160.5 202.4,159.3 203.2,159.3 203.2,159.4 204.1,159.4 204.1,160.4 204.9,160.4 204.9,160.1 205.7,160.1 205.7,160.4 206.5,160.4 206.5,160.4 207.3,160.4 207.3,160.8 208.1,160.8 208.1,159.8 208.9,159.8 208.9,159.4 209.8,159.4 209.8,160.5 210.6,160.5 210.6,160.1 211.4,160.1 211.4,160.7 212.2,160.7 212.2,160.6 213.0,160.6 213.0,159.5 213.8,159.5 213.8,161.1 214.6,161.1 214.6,161.3 215.4,161.3 215.4,161.0 216.2,161.0 216.2,1Line truncated
<circle class="nj-charts-json-dot" cx="88.7" cy="178.2" r="3.5"><title>#5234: 1.55&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="88.7" y1="54.0" x2="88.7" y2="173.2"/>
<circle class="nj-theme-dot" cx="88.7" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="88.7" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="130.1" cy="162.5" r="3.5"><title>#5283: 1.95&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="130.1" y1="54.0" x2="130.1" y2="157.5"/>
<circle class="nj-theme-dot" cx="130.1" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="130.1" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="222.8" cy="155.4" r="3.5"><title>#5592: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="222.8" y1="54.0" x2="222.8" y2="150.4"/>
<circle class="nj-theme-dot" cx="222.8" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="222.8" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="243.1" cy="147.1" r="3.5"><title>#5809: 2.4&#215;</title></circle>
<circle class="nj-charts-json-dot" cx="243.9" cy="138.2" r="3.5"><title>#5810: 2.8&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="243.9" y1="36.0" x2="243.9" y2="133.2"/>
<circle class="nj-theme-dot" cx="234.9" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="234.9" y="32.0" text-anchor="middle">4</text>
<circle class="nj-theme-dot" cx="252.9" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="252.9" y="32.0" text-anchor="middle">2</text>
<circle class="nj-charts-json-dot" cx="285.3" cy="125.7" r="3.5"><title>#5882: 3.3&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="285.3" y1="54.0" x2="285.3" y2="120.7"/>
<circle class="nj-theme-dot" cx="285.3" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="285.3" 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,28 +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 353 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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,205.9 48.1,209.3 48.9,209.3 48.9,208.3 49.7,208.3 49.7,207.9 50.5,207.9 50.5,209.4 51.3,209.4 51.3,205.8 52.1,205.8 52.1,206.7 52.9,206.7 52.9,209.2 53.8,209.2 53.8,208.1 54.6,208.1 54.6,206.9 55.4,206.9 55.4,207.5 56.2,207.5 56.2,207.5 57.0,207.5 57.0,207.6 57.8,207.6 57.8,206.9 58.6,206.9 58.6,206.9 59.4,206.9 59.4,208.4 60.2,208.4 60.2,208.6 61.1,208.6 61.1,209.1 61.9,209.1 61.9,207.7 62.7,207.7 62.7,207.0 63.5,207.0 63.5,206.7 64.3,206.7 64.3,206.1 65.1,206.1 65.1,207.5 65.9,207.5 65.9,206.4 66.8,206.4 66.8,206.7 67.6,206.7 67.6,206.8 68.4,206.8 68.4,209.3 69.2,209.3 69.2,206.7 70.0,206.7 70.0,206.8 70.8,206.8 70.8,206.6 71.6,206.6 71.6,206.8 72.4,206.8 72.4,209.2 73.2,209.2 73.2,207.6 74.1,207.6 74.1,205.9 74.9,205.9 74.9,209.1 75.7,209.1 75.7,206.6 76.5,206.6 76.5,207.4 77.3,207.4 77.3,207.0 78.1,207.0 78.1,209.1 78.9,209.1 78.9,205.8 79.8,205.8 79.8,206.9 80.6,206.9 80.6,208.0 81.4,208.0 81.4,208.5 82.2,208.5 82.2,206.6 83.0,206.6 83.0,206.0 83.8,206.0 83.8,207.9 84.6,207.9 84.6,206.6 85.4,206.6 85.4,206.5 86.2,206.5 86.2,206.6 87.1,206.6 87.1,207.2 87.9,207.2 87.9,208.0 88.7,208.0 88.7,208.1 89.5,208.1 89.5,206.7 90.3,206.7 90.3,207.8 91.1,207.8 91.1,206.7 91.9,206.7 91.9,208.1 92.8,208.1 92.8,205.9 93.6,205.9 93.6,206.8 94.4,206.8 94.4,208.0 95.2,208.0 95.2,207.3 96.0,207.3 96.0,206.7 96.8,206.7 96.8,209.3 97.6,209.3 97.6,206.5 98.4,206.5 98.4,207.2 99.2,207.2 99.2,208.2 100.1,208.2 100.1,209.3 100.9,209.3 100.9,207.8 101.7,207.8 101.7,206.9 102.5,206.9 102.5,206.7 103.3,206.7 103.3,209.0 104.1,209.0 104.1,208.0 104.9,208.0 104.9,208.1 105.8,208.1 105.8,209.1 106.6,209.1 106.6,208.1 107.4,208.1 107.4,205.6 108.2,205.6 108.2,207.0 109.0,207.0 109.0,206.7 109.8,206.7 109.8,207.9 110.6,207.9 110.6,206.7 111.4,206.7 111.4,206.9 112.2,206.9 112.2,206.8 113.1,206.8 113.1,206.4 113.9,206.4 113.9,207.1 114.7,207.1 114.7,208.6 115.5,208.6 115.5,208.7 116.3,208.7 116.3,206.6 117.1,206.6 117.1,209.3 117.9,209.3 117.9,208.0 118.8,208.0 118.8,206.7 119.6,206.7 119.6,207.7 120.4,207.7 120.4,206.9 121.2,206.9 121.2,208.8 122.0,208.8 122.0,208.7 122.8,208.7 122.8,207.7 123.6,207.7 123.6,208.8 124.4,208.8 124.4,207.8 125.3,207.8 125.3,210.3 126.1,210.3 126.1,208.9 126.9,208.9 126.9,208.9 127.7,208.9 127.7,209.0 128.5,209.0 128.5,208.0 129.3,208.0 129.3,207.7 130.1,207.7 130.1,208.3 130.9,208.3 130.9,207.0 131.8,207.0 131.8,207.2 132.6,207.2 132.6,207.5 133.4,207.5 133.4,208.0 134.2,208.0 134.2,207.6 135.0,207.6 135.0,207.9 135.8,207.9 135.8,207.6 136.6,207.6 136.6,208.5 137.4,208.5 137.4,209.2 138.2,209.2 138.2,206.3 139.1,206.3 139.1,208.7 139.9,208.7 139.9,207.6 140.7,207.6 140.7,207.4 141.5,207.4 141.5,207.5 142.3,207.5 142.3,209.0 143.1,209.0 143.1,206.9 143.9,206.9 143.9,209.3 144.8,209.3 144.8,209.9 145.6,209.9 145.6,207.0 146.4,207.0 146.4,207.3 147.2,207.3 147.2,208.1 148.0,208.1 148.0,209.8 148.8,209.8 148.8,208.1 149.6,208.1 149.6,208.1 150.4,208.1 150.4,208.5 151.2,208.5 151.2,208.2 152.1,208.2 152.1,210.4 152.9,210.4 152.9,207.7 153.7,207.7 153.7,207.2 154.5,207.2 154.5,206.7 155.3,206.7 155.3,209.9 156.1,209.9 156.1,206.6 156.9,206.6 156.9,209.9 157.8,209.9 157.8,208.8 158.6,208.8 158.6,208.8 159.4,208.8 159.4,209.5 160.2,209.5 160.2,208.9 161.0,208.9 161.0,206.4 161.8,206.4 161.8,207.2 162.6,207.2 162.6,207.0 163.4,207.0 163.4,207.2 164.2,207.2 164.2,206.6 165.1,206.6 165.1,207.2 165.9,207.2 165.9,208.0 166.7,208.0 166.7,207.6 167.5,207.6 167.5,207.9 168.3,207.9 168.3,207.5 169.1,207.5 169.1,205.6 169.9,205.6 169.9,208.0 170.8,208.0 170.8,209.7 171.6,209.7 171.6,207.9 172.4,207.9 172.4,207.6 173.2,207.6 173.2,208.5 174.0,208.5 174.0,207.9 174.8,207.9 174.8,210.4 175.6,210.4 175.6,206.7 176.4,206.7 176.4,207.7 177.2,207.7 177.2,209.2 178.1,209.2 178.1,206.8 178.9,206.8 178.9,209.3 179.7,209.3 179.7,208.0 180.5,208.0 180.5,208.0 181.3,208.0 181.3,207.9 182.1,207.9 182.1,208.2 182.9,208.2 182.9,207.9 183.8,207.9 183.8,207.0 184.6,207.0 184.6,208.8 185.4,208.8 185.4,208.0 186.2,208.0 186.2,208.0 187.0,208.0 187.0,209.2 187.8,209.2 187.8,206.7 188.6,206.7 188.6,206.7 189.4,206.7 189.4,208.5 190.2,208.5 190.2,208.9 191.1,208.9 191.1,210.1 191.9,210.1 191.9,206.4 192.7,206.4 192.7,209.4 193.5,209.4 193.5,210.1 194.3,210.1 194.3,207.6 195.1,207.6 195.1,209.5 195.9,209.5 195.9,208.7 196.8,208.7 196.8,211.1 197.6,211.1 197.6,210.1 198.4,210.1 198.4,211.7 199.2,211.7 199.2,208.8 200.0,208.8 200.0,209.2 200.8,209.2 200.8,207.7 201.6,207.7 201.6,208.1 202.4,208.1 202.4,206.4 203.2,206.4 203.2,206.7 204.1,206.7 204.1,207.3 204.9,207.3 204.9,207.8 205.7,207.8 205.7,208.7 206.5,208.7 206.5,210.1 207.3,210.1 207.3,210.0 208.1,210.0 208.1,206.9 208.9,206.9 208.9,209.0 209.8,209.0 209.8,208.7 210.6,208.7 210.6,209.1 211.4,209.1 211.4,208.6 212.2,208.6 212.2,208.9 213.0,208.9 213.0,207.3 213.8,207.3 213.8,208.9 214.6,208.9 214.6,209.2 215.4,209.2 215.4,207.3 216.2,207.3 216.2,2Line truncated
<circle class="nj-charts-json-dot" cx="262.6" cy="138.8" r="3.5"><title>#5828: 1.97&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="262.6" y1="54.0" x2="262.6" y2="133.8"/>
<circle class="nj-theme-dot" cx="262.6" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="262.6" y="50.0" text-anchor="middle">1</text>
<circle class="nj-charts-json-dot" cx="279.6" cy="127.0" r="3.5"><title>#5884: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="279.6" y1="36.0" x2="279.6" y2="122.0"/>
<circle class="nj-theme-dot" cx="279.6" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="279.6" 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: 10 KiB

@@ -1,34 +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 353 commits, ending at 5.0x. 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="117.938" y1="208" x2="117.938" y2="212"/>
<text class="nj-charts-tick" x="117.938" y="225">Sep 2026</text>
<line class="nj-charts-axis" x1="198.375" y1="208" x2="198.375" y2="212"/>
<text class="nj-charts-tick" x="198.375" y="225">Oct</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.1,204.7 48.1,205.2 48.9,205.2 48.9,205.0 49.7,205.0 49.7,204.9 50.5,204.9 50.5,205.0 51.3,205.0 51.3,205.0 52.1,205.0 52.1,205.1 52.9,205.1 52.9,205.4 53.8,205.4 53.8,205.0 54.6,205.0 54.6,205.2 55.4,205.2 55.4,211.6 56.2,211.6 56.2,206.8 57.0,206.8 57.0,204.2 57.8,204.2 57.8,207.6 58.6,207.6 58.6,204.1 59.4,204.1 59.4,203.8 60.2,203.8 60.2,204.2 61.1,204.2 61.1,205.1 61.9,205.1 61.9,204.4 62.7,204.4 62.7,204.3 63.5,204.3 63.5,204.0 64.3,204.0 64.3,202.7 65.1,202.7 65.1,204.2 65.9,204.2 65.9,204.2 66.8,204.2 66.8,204.2 67.6,204.2 67.6,204.4 68.4,204.4 68.4,206.2 69.2,206.2 69.2,204.3 70.0,204.3 70.0,204.1 70.8,204.1 70.8,204.3 71.6,204.3 71.6,204.3 72.4,204.3 72.4,204.3 73.2,204.3 73.2,204.3 74.1,204.3 74.1,204.4 74.9,204.4 74.9,204.8 75.7,204.8 75.7,208.4 76.5,208.4 76.5,203.5 77.3,203.5 77.3,206.2 78.1,206.2 78.1,204.4 78.9,204.4 78.9,203.2 79.8,203.2 79.8,204.1 80.6,204.1 80.6,204.2 81.4,204.2 81.4,203.7 82.2,203.7 82.2,204.2 83.0,204.2 83.0,203.2 83.8,203.2 83.8,204.2 84.6,204.2 84.6,204.4 85.4,204.4 85.4,203.8 86.2,203.8 86.2,204.4 87.1,204.4 87.1,204.7 87.9,204.7 87.9,204.6 88.7,204.6 88.7,208.7 89.5,208.7 89.5,205.2 90.3,205.2 90.3,205.5 91.1,205.5 91.1,205.2 91.9,205.2 91.9,205.3 92.8,205.3 92.8,206.8 93.6,206.8 93.6,204.6 94.4,204.6 94.4,205.5 95.2,205.5 95.2,205.1 96.0,205.1 96.0,204.7 96.8,204.7 96.8,205.7 97.6,205.7 97.6,205.0 98.4,205.0 98.4,204.9 99.2,204.9 99.2,206.5 100.1,206.5 100.1,205.6 100.9,205.6 100.9,205.0 101.7,205.0 101.7,209.2 102.5,209.2 102.5,205.9 103.3,205.9 103.3,206.5 104.1,206.5 104.1,205.5 104.9,205.5 104.9,205.3 105.8,205.3 105.8,205.3 106.6,205.3 106.6,205.1 107.4,205.1 107.4,204.4 108.2,204.4 108.2,204.6 109.0,204.6 109.0,204.8 109.8,204.8 109.8,204.2 110.6,204.2 110.6,203.8 111.4,203.8 111.4,204.4 112.2,204.4 112.2,202.8 113.1,202.8 113.1,203.5 113.9,203.5 113.9,204.0 114.7,204.0 114.7,204.3 115.5,204.3 115.5,202.9 116.3,202.9 116.3,203.3 117.1,203.3 117.1,204.4 117.9,204.4 117.9,204.5 118.8,204.5 118.8,204.1 119.6,204.1 119.6,208.3 120.4,208.3 120.4,203.8 121.2,203.8 121.2,207.0 122.0,207.0 122.0,205.9 122.8,205.9 122.8,205.4 123.6,205.4 123.6,205.3 124.4,205.3 124.4,205.8 125.3,205.8 125.3,205.4 126.1,205.4 126.1,205.6 126.9,205.6 126.9,206.3 127.7,206.3 127.7,205.5 128.5,205.5 128.5,204.8 129.3,204.8 129.3,204.6 130.1,204.6 130.1,206.1 130.9,206.1 130.9,204.6 131.8,204.6 131.8,204.1 132.6,204.1 132.6,204.3 133.4,204.3 133.4,205.6 134.2,205.6 134.2,203.9 135.0,203.9 135.0,204.0 135.8,204.0 135.8,203.9 136.6,203.9 136.6,204.6 137.4,204.6 137.4,204.1 138.2,204.1 138.2,203.9 139.1,203.9 139.1,204.8 139.9,204.8 139.9,203.2 140.7,203.2 140.7,203.3 141.5,203.3 141.5,204.7 142.3,204.7 142.3,208.3 143.1,208.3 143.1,204.3 143.9,204.3 143.9,207.4 144.8,207.4 144.8,204.4 145.6,204.4 145.6,208.2 146.4,208.2 146.4,205.0 147.2,205.0 147.2,204.9 148.0,204.9 148.0,208.8 148.8,208.8 148.8,207.9 149.6,207.9 149.6,206.2 150.4,206.2 150.4,204.2 151.2,204.2 151.2,204.1 152.1,204.1 152.1,204.2 152.9,204.2 152.9,202.2 153.7,202.2 153.7,205.6 154.5,205.6 154.5,203.0 155.3,203.0 155.3,203.4 156.1,203.4 156.1,202.7 156.9,202.7 156.9,203.6 157.8,203.6 157.8,203.3 158.6,203.3 158.6,203.2 159.4,203.2 159.4,204.9 160.2,204.9 160.2,202.9 161.0,202.9 161.0,202.2 161.8,202.2 161.8,202.5 162.6,202.5 162.6,202.9 163.4,202.9 163.4,202.9 164.2,202.9 164.2,202.3 165.1,202.3 165.1,202.9 165.9,202.9 165.9,203.7 166.7,203.7 166.7,204.1 167.5,204.1 167.5,203.9 168.3,203.9 168.3,203.7 169.1,203.7 169.1,203.3 169.9,203.3 169.9,203.8 170.8,203.8 170.8,205.0 171.6,205.0 171.6,208.0 172.4,208.0 172.4,205.1 173.2,205.1 173.2,206.5 174.0,206.5 174.0,205.4 174.8,205.4 174.8,205.4 175.6,205.4 175.6,207.0 176.4,207.0 176.4,204.9 177.2,204.9 177.2,205.4 178.1,205.4 178.1,203.6 178.9,203.6 178.9,205.7 179.7,205.7 179.7,204.5 180.5,204.5 180.5,205.0 181.3,205.0 181.3,205.2 182.1,205.2 182.1,204.9 182.9,204.9 182.9,204.5 183.8,204.5 183.8,204.9 184.6,204.9 184.6,205.3 185.4,205.3 185.4,203.9 186.2,203.9 186.2,204.8 187.0,204.8 187.0,204.8 187.8,204.8 187.8,203.6 188.6,203.6 188.6,203.4 189.4,203.4 189.4,203.8 190.2,203.8 190.2,205.1 191.1,205.1 191.1,205.5 191.9,205.5 191.9,204.0 192.7,204.0 192.7,204.9 193.5,204.9 193.5,205.0 194.3,205.0 194.3,206.4 195.1,206.4 195.1,205.1 195.9,205.1 195.9,204.5 196.8,204.5 196.8,204.8 197.6,204.8 197.6,205.2 198.4,205.2 198.4,205.0 199.2,205.0 199.2,204.6 200.0,204.6 200.0,203.9 200.8,203.9 200.8,203.5 201.6,203.5 201.6,203.6 202.4,203.6 202.4,204.2 203.2,204.2 203.2,205.9 204.1,205.9 204.1,205.2 204.9,205.2 204.9,204.8 205.7,204.8 205.7,207.3 206.5,207.3 206.5,205.2 207.3,205.2 207.3,208.6 208.1,208.6 208.1,204.3 208.9,204.3 208.9,203.9 209.8,203.9 209.8,203.2 210.6,203.2 210.6,203.9 211.4,203.9 211.4,205.9 212.2,205.9 212.2,204.8 213.0,204.8 213.0,204.7 213.8,204.7 213.8,203.6 214.6,203.6 214.6,203.7 215.4,203.7 215.4,208.2 216.2,208.2 216.2,2Line truncated
<circle class="nj-charts-json-dot" cx="234.9" cy="153.7" r="3.5"><title>#5328: 2.2&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="234.9" y1="54.0" x2="234.9" y2="148.7"/>
<circle class="nj-theme-dot" cx="234.9" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="234.9" y="50.0" text-anchor="middle">4</text>
<circle class="nj-charts-json-dot" cx="269.9" cy="123.4" r="3.5"><title>#5824: 3.5&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="269.9" y1="54.0" x2="269.9" y2="118.4"/>
<circle class="nj-theme-dot" cx="269.9" cy="46.0" r="7.5"/>
<text class="nj-theme-num" x="269.9" y="50.0" text-anchor="middle">6</text>
<circle class="nj-charts-json-dot" cx="282.1" cy="96.9" r="3.5"><title>#5885: 5.1&#215;</title></circle>
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="282.1" y1="36.0" x2="282.1" y2="91.9"/>
<circle class="nj-theme-dot" cx="282.1" cy="28.0" r="7.5"/>
<text class="nj-theme-num" x="282.1" 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.85 doing less, N); nlohmann/json json_document write: 1.00 (0.71 doing less, N); yyjson validate: 1.37; yyjson sum: 1.11; yyjson select: 1.25; yyjson edit: 1.45; yyjson minify: 1.23 (1.16 doing less, N); yyjson write: 1.26; simdjson validate: 1.52; simdjson sum: 1.20; simdjson select: 1.33 (0.75 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.93; sonic-rs (Rust) sum: 1.53; sonic-rs (Rust) select: 1.83; sonic-rs (Rust) edit: 2.08; sonic-rs (Rust) minify: 1.93; sonic-rs (Rust) write: 2.38; sonic-cpp validate: no fully validating way (2.53 doing less, U); sonic-cpp sum: no fully validating way (1.86 doing less, U); sonic-cpp select: no fully validating way (2.31 doing less, U); sonic-cpp edit: no fully validating way (1.68 doing less, U); sonic-cpp minify: no fully validating way (2.03 doing less, U); sonic-cpp write: 1.59; simd-json (Rust) validate: 2.07; simd-json (Rust) sum: 1.62; simd-json (Rust) select: 2.38; simd-json (Rust) edit: 2.84; simd-json (Rust) minify: 3.40; simd-json (Rust) write: 3.10; Glaze validate: 2.04; Glaze sum: 3.85; Glaze select: 1.79 (0.82 doing less, P); Glaze edit: 4.41; Glaze minify: 5.19 (1.03 doing less, P); Glaze write: 2.23; Boost.J&#8203;SON validate: 2.56; Boost.J&#8203;SON sum: 1.99; Boost.J&#8203;SON select: 3.27; Boost.J&#8203;SON edit: 3.21; Boost.J&#8203;SON minify: 3.87; Boost.J&#8203;SON write: 3.75; serde_json (Rust) validate: 2.46 (2.23 doing less, U); serde_json (Rust) sum: 2.59; serde_json (Rust) select: 2.39 (2.24 doing less, U); serde_json (Rust) edit: 4.99; serde_json (Rust) minify: 5.85; serde_json (Rust) write: 2.95; nlohmann/json json validate: 2.71; nlohmann/json json sum: 1.96; nlohmann/json json select: 6.87; nlohmann/json json edit: 3.73; nlohmann/json json minify: 4.89; nlohmann/json json write: 2.10; RapidJSON validate: 4.72 (3.09 doing less, U); RapidJSON sum: 4.15 (2.85 doing less, U); RapidJSON select: 5.91 (3.82 doing less, U); RapidJSON edit: 4.82 (3.77 doing less, U); RapidJSON minify: 4.86 (3.60 doing less, U N); RapidJSON write: 5.88.</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: 170 µs&#10;citm_catalog.json: 313 µs&#10;canada.json: 886 µs&#10;jeopardy.json: 20,873 µ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: 224 µs&#10;citm_catalog.json: 485 µs&#10;canada.json: 1,816 µs&#10;jeopardy.json: 28,987 µ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: 184 µs&#10;citm_catalog.json: 363 µs&#10;canada.json: 956 µs&#10;jeopardy.json: 24,991 µ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: 291 µs&#10;citm_catalog.json: 560 µs&#10;canada.json: 2,765 µs&#10;jeopardy.json: 58,057 µ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;twitter.json: 283 µs · editable (source numbers) (validates fully)&#10;citm_catalog.json: 560 µs · editable (validates fully)&#10;canada.json: 1,484 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 57,635 µs · editable (source numbers) (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: 259 µs&#10;citm_catalog.json: 493 µs&#10;canada.json: 2,582 µs&#10;jeopardy.json: 37,882 µ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.85× the time of the fastest fully validating library&#10;twitter.json: 252 µs · parse + dump (source numbers) (validates fully)&#10;citm_catalog.json: 493 µs · parse + dump (validates fully)&#10;canada.json: 1,360 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 37,817 µs · parse + 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="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.85</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: 74.3 µs&#10;citm_catalog.json: 134 µs&#10;canada.json: 1,621 µs&#10;jeopardy.json: 14,757 µ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: 74.3 µs · dump (validates fully)&#10;citm_catalog.json: 134 µs · dump (validates fully)&#10;canada.json: 401 µs · dump (source numbers) (validates fully)&#10;jeopardy.json: 14,757 µ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;1.37× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 172 µs&#10;citm_catalog.json: 451 µs&#10;canada.json: 1,457 µs&#10;jeopardy.json: 30,240 µs">
<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.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.11× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 219 µs&#10;citm_catalog.json: 551 µs&#10;canada.json: 1,906 µs&#10;jeopardy.json: 37,512 µs">
<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.11</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.25× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 178 µs&#10;citm_catalog.json: 456 µs&#10;canada.json: 1,461 µs&#10;jeopardy.json: 32,514 µs">
<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.25</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.45× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed) + mut copy&#10;twitter.json: 427 µs&#10;citm_catalog.json: 882 µs&#10;canada.json: 3,642 µs&#10;jeopardy.json: 84,239 µs">
<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.45</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.23× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed) + write&#10;twitter.json: 279 µs&#10;citm_catalog.json: 625 µs&#10;canada.json: 3,196 µs&#10;jeopardy.json: 50,821 µ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.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;1.16× the time of the fastest fully validating library&#10;twitter.json: 279 µs · insitu (copy untimed) + write (validates fully)&#10;citm_catalog.json: 625 µs · insitu (copy untimed) + write (validates fully)&#10;canada.json: 2,550 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 50,821 µs · insitu (copy untimed) + write (validates fully)&#10;copies each number&#x27;s text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)">
<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.16</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.26× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 103 µs&#10;citm_catalog.json: 169 µs&#10;canada.json: 1,731 µs&#10;jeopardy.json: 20,087 µ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.26</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: 212 µs&#10;citm_catalog.json: 452 µs&#10;canada.json: 1,888 µs&#10;jeopardy.json: 28,843 µ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.20× the time of the fastest library (fully validating)&#10;twitter.json: 249 µs · D&#8203;OM&#10;citm_catalog.json: 571 µs · On-Demand&#10;canada.json: 2,374 µs · On-Demand&#10;jeopardy.json: 35,111 µ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.20</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: 196 µs&#10;citm_catalog.json: 450 µs&#10;canada.json: 1,886 µs&#10;jeopardy.json: 30,504 µ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.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.75× the time of the fastest fully validating library&#10;twitter.json: 127 µs · On-Demand structs&#10;citm_catalog.json: 354 µs · On-Demand&#10;canada.json: 566 µs · On-Demand (key selectors)&#10;jeopardy.json: 19,562 µ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.75</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: 423 µs&#10;citm_catalog.json: 848 µs&#10;canada.json: 5,120 µs&#10;jeopardy.json: 61,059 µ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.3 µs&#10;citm_catalog.json: 171 µs&#10;canada.json: 227 µs&#10;jeopardy.json: 5,762 µ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: 199 µs&#10;citm_catalog.json: 385 µs&#10;canada.json: 3,241 µs&#10;jeopardy.json: 32,208 µ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.93× 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.93</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.53× 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.53</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.83× 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.83</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · edit&#10;2.08× 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.08</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.38× 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.38</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.53× 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,578 µs&#10;jeopardy.json: 41,617 µs&#10;trusts U&#8203;TF-8: sonic-cpp 1.0.2 doesn&#x27;t check it">
<rect class="nj-heat-3" x="225" y="189" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="204" text-anchor="middle">2.53</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,087 µs&#10;canada.json: 2,993 µs&#10;jeopardy.json: 48,688 µ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.31× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 385 µs&#10;citm_catalog.json: 990 µs&#10;canada.json: 2,586 µs&#10;jeopardy.json: 45,858 µ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.31</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.68× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 486 µs&#10;citm_catalog.json: 1,224 µs&#10;canada.json: 5,638 µs&#10;jeopardy.json: 62,688 µ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.68</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: 500 µs&#10;citm_catalog.json: 1,220 µs&#10;canada.json: 5,676 µs&#10;jeopardy.json: 61,236 µ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.59× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 108 µs&#10;citm_catalog.json: 230 µs&#10;canada.json: 3,093 µs&#10;jeopardy.json: 19,651 µ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.59</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.07× 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.07</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.62× 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.62</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.38× 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.38</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.84× 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.84</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.10× 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.10</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="282" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.04× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 331 µs&#10;citm_catalog.json: 862 µs&#10;canada.json: 1,326 µs&#10;jeopardy.json: 45,192 µ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">2.04</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;3.85× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 968 µs&#10;citm_catalog.json: 2,049 µs&#10;canada.json: 6,331 µs&#10;jeopardy.json: 99,763 µs">
<rect class="nj-heat-3" x="317" y="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">3.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.79× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 311 µs&#10;citm_catalog.json: 854 µs&#10;canada.json: 1,316 µs&#10;jeopardy.json: 46,924 µs">
<rect class="nj-heat-2" x="409" y="261" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="282" text-anchor="middle">1.79</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.82× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 241 µs&#10;citm_catalog.json: 255 µs&#10;canada.json: 313 µs&#10;jeopardy.json: 37,578 µ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="261" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="276" text-anchor="middle">0.82</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="289" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;4.41× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 1,539 µs&#10;citm_catalog.json: 3,235 µs&#10;canada.json: 11,083 µs&#10;jeopardy.json: 178,333 µs">
<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">4.41</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;5.19× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 1,505 µs&#10;citm_catalog.json: 3,225 µs&#10;canada.json: 11,092 µs&#10;jeopardy.json: 168,855 µs">
<rect class="nj-heat-4" x="593" y="261" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="282" text-anchor="middle">5.19</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;1.03× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 281 µs&#10;citm_catalog.json: 729 µs&#10;canada.json: 1,722 µs&#10;jeopardy.json: 39,976 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="261" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="276" text-anchor="middle">1.03</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="289" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;2.23× the time of the fastest library (fully validating)&#10;twitter.json: 216 µs · generic&#10;citm_catalog.json: 469 µs · generic&#10;canada.json: 1,720 µs · generic (strict)&#10;jeopardy.json: 33,934 µs · generic">
<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.23</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">Boost.J&#8203;SON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · validate&#10;2.56× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 535 µs&#10;citm_catalog.json: 994 µs&#10;canada.json: 1,467 µs&#10;jeopardy.json: 53,939 µs">
<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">2.56</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.99× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 535 µs&#10;citm_catalog.json: 1,010 µs&#10;canada.json: 3,067 µs&#10;jeopardy.json: 53,704 µs">
<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.99</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;3.27× the time of the fastest library (fully validating)&#10;twitter.json: 617 µs · parse_into structs&#10;citm_catalog.json: 1,205 µs · parse_into structs&#10;canada.json: 3,650 µs · parse&#10;jeopardy.json: 67,255 µs · parse_into structs">
<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">3.27</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;3.21× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,368 µs&#10;citm_catalog.json: 1,992 µs&#10;canada.json: 6,573 µs&#10;jeopardy.json: 155,237 µ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">3.21</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;3.87× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,393 µs&#10;citm_catalog.json: 1,986 µs&#10;canada.json: 6,542 µs&#10;jeopardy.json: 154,677 µs">
<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.87</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;3.75× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 507 µs&#10;citm_catalog.json: 508 µs&#10;canada.json: 2,923 µs&#10;jeopardy.json: 62,583 µs">
<rect class="nj-heat-3" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">3.75</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: 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="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.23× 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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="348" text-anchor="middle">2.23</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.59× 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="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">2.59</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;2.39× 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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="354" text-anchor="middle">2.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select, checking less&#10;2.24× 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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="348" text-anchor="middle">2.24</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="361" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.99× 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-3" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">4.99</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="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="354" text-anchor="middle">5.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.95× 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="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="354" text-anchor="middle">2.95</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="390" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;2.71× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 451 µs&#10;citm_catalog.json: 888 µs&#10;canada.json: 2,405 µs&#10;jeopardy.json: 55,286 µs">
<rect class="nj-heat-3" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.96× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 465 µs&#10;citm_catalog.json: 925 µs&#10;canada.json: 3,072 µs&#10;jeopardy.json: 64,089 µs">
<rect class="nj-heat-2" x="317" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="390" text-anchor="middle">1.96</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;6.87× the time of the fastest library (fully validating)&#10;twitter.json: 1,360 µs · structs (from_json)&#10;citm_catalog.json: 2,416 µs · parse&#10;canada.json: 6,047 µs · structs (from_json)&#10;jeopardy.json: 179,533 µs · parse">
<rect class="nj-heat-4" x="409" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="390" text-anchor="middle">6.87</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.73× the time of the fastest library (fully validating)&#10;twitter.json: 1,273 µs · ordered_json&#10;citm_catalog.json: 2,344 µs · ordered_json&#10;canada.json: 8,334 µs · parse&#10;jeopardy.json: 203,232 µs · ordered_json">
<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">3.73</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.89× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 1,600 µs&#10;citm_catalog.json: 2,706 µs&#10;canada.json: 8,389 µs&#10;jeopardy.json: 197,745 µs">
<rect class="nj-heat-3" x="593" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="390" text-anchor="middle">4.89</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;2.10× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 223 µs&#10;citm_catalog.json: 287 µs&#10;canada.json: 2,276 µs&#10;jeopardy.json: 31,825 µ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">2.10</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.72× the time of the fastest library (fully validating)&#10;twitter.json: 1,307 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,397 µs · S&#8203;AX (string stream, default precision)&#10;canada.json: 1,982 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 134,679 µs · S&#8203;AX (string stream, default precision)">
<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.72</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: 686 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,032 µs · S&#8203;AX (string stream, default precision) (no encoding check)&#10;canada.json: 1,982 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 63,589 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.15× the time of the fastest library (fully validating)&#10;twitter.json: 1,329 µs · S&#8203;AX&#10;citm_catalog.json: 1,455 µs · S&#8203;AX (string stream)&#10;canada.json: 6,453 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 136,103 µ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.15</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.85× the time of the fastest fully validating library&#10;twitter.json: 735 µs · S&#8203;AX (string stream) (no encoding check)&#10;citm_catalog.json: 1,136 µs · S&#8203;AX (string stream) (no encoding check)&#10;canada.json: 6,453 µs · S&#8203;AX (string stream) (validates fully)&#10;jeopardy.json: 69,604 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.85</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;5.91× the time of the fastest library (fully validating)&#10;twitter.json: 1,304 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,554 µs · insitu (copy untimed)&#10;canada.json: 6,776 µs · Document (string stream)&#10;jeopardy.json: 141,509 µs · insitu (copy untimed)">
<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">5.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.82× the time of the fastest fully validating library&#10;twitter.json: 679 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,126 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 6,776 µs · Document (string stream) (validates fully)&#10;jeopardy.json: 65,625 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.82</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.82× the time of the fastest library (fully validating)&#10;twitter.json: 1,922 µs · Document&#10;citm_catalog.json: 2,388 µs · insitu (copy untimed)&#10;canada.json: 13,836 µs · Document (string stream)&#10;jeopardy.json: 221,270 µs · insitu (copy untimed)">
<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.82</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;3.77× the time of the fastest fully validating library&#10;way: insitu (copy untimed) (no encoding check)&#10;twitter.json: 1,344 µs&#10;citm_catalog.json: 1,964 µs&#10;canada.json: 13,794 µs&#10;jeopardy.json: 144,741 µs&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.77</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.86× the time of the fastest library (fully validating)&#10;twitter.json: 1,525 µs · S&#8203;AX to Writer&#10;citm_catalog.json: 1,808 µs · S&#8203;AX to Writer (string stream)&#10;canada.json: 14,460 µs · Document + Writer&#10;jeopardy.json: 174,558 µ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.86</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;3.60× the time of the fastest fully validating library&#10;twitter.json: 1,058 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;citm_catalog.json: 1,485 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;canada.json: 10,908 µs · S&#8203;AX to Writer (raw numbers) (no encoding check)&#10;jeopardy.json: 123,119 µ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.60</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.88× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 603 µs&#10;citm_catalog.json: 830 µs&#10;canada.json: 6,995 µs&#10;jeopardy.json: 81,150 µ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.88</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: 45 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.00; 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.69 doing less, N); yyjson validate: 1.87; yyjson sum: 1.00; yyjson select: 1.23; yyjson edit: 1.43; yyjson minify: 1.16 (1.00 doing less, N); yyjson write: 1.14; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.20 doing less, U); sonic-cpp select: no fully validating way (1.53 doing less, U); sonic-cpp edit: no fully validating way (1.24 doing less, U); sonic-cpp minify: no fully validating way (1.38 doing less, U); sonic-cpp write: 1.28; simdjson validate: 2.03; simdjson sum: 1.13; simdjson select: 1.32 (0.57 doing less, P); simdjson edit: n/a; simdjson minify: 1.58 (0.18 doing less, P); simdjson write: 2.00; sonic-rs (Rust) validate: 1.88; sonic-rs (Rust) sum: 1.07; sonic-rs (Rust) select: 1.39; sonic-rs (Rust) edit: 1.90; sonic-rs (Rust) minify: 1.73; sonic-rs (Rust) write: 1.94; Boost.J&#8203;SON validate: 1.79; Boost.J&#8203;SON sum: 1.12; Boost.J&#8203;SON select: 2.24; Boost.J&#8203;SON edit: 2.39; Boost.J&#8203;SON minify: 2.68; Boost.J&#8203;SON write: 2.31; simd-json (Rust) validate: 3.52; simd-json (Rust) sum: 1.80; simd-json (Rust) select: 2.64; simd-json (Rust) edit: 2.88; simd-json (Rust) minify: 3.38; simd-json (Rust) write: 2.21; serde_json (Rust) validate: 2.33 (2.08 doing less, U); serde_json (Rust) sum: 2.22; serde_json (Rust) select: 1.77; serde_json (Rust) edit: 4.54; serde_json (Rust) minify: 4.92; serde_json (Rust) write: 2.15; Glaze validate: 2.23; Glaze sum: 4.03 (3.78 doing less, P); Glaze select: 1.43 (0.62 doing less, P); Glaze edit: 5.53; Glaze minify: 5.77 (0.70 doing less, P); Glaze write: 1.90; nlohmann/json json validate: 2.77; nlohmann/json json sum: 1.44; nlohmann/json json select: 7.56; nlohmann/json json edit: 3.99; nlohmann/json json minify: 4.91; nlohmann/json json write: 1.86; RapidJSON validate: 4.94 (3.76 doing less, U); RapidJSON sum: 2.98 (2.28 doing less, U); RapidJSON select: 4.20 (3.27 doing less, U); RapidJSON edit: 3.06 (2.60 doing less, U); RapidJSON minify: 3.61 (2.65 doing less, U N); RapidJSON write: 2.79.</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: 255 µs&#10;citm_catalog.json: 512 µs&#10;canada.json: 1,055 µs&#10;jeopardy.json: 34,729 µ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: 374 µs&#10;citm_catalog.json: 923 µs&#10;canada.json: 3,846 µs&#10;jeopardy.json: 85,286 µ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;twitter.json: 320 µs · parse&#10;citm_catalog.json: 759 µs · parse&#10;canada.json: 1,390 µs · structs (from_json)&#10;jeopardy.json: 88,083 µ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: 526 µs&#10;citm_catalog.json: 1,127 µs&#10;canada.json: 5,674 µs&#10;jeopardy.json: 196,370 µ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: 526 µs · editable (validates fully)&#10;citm_catalog.json: 1,127 µs · editable (validates fully)&#10;canada.json: 2,443 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 196,370 µ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: 518 µs&#10;citm_catalog.json: 1,040 µs&#10;canada.json: 5,043 µs&#10;jeopardy.json: 146,125 µ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: 518 µs · parse + dump (validates fully)&#10;citm_catalog.json: 1,030 µs · parse + dump (source numbers) (validates fully)&#10;canada.json: 2,456 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 146,125 µ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: 160 µs&#10;citm_catalog.json: 311 µs&#10;canada.json: 3,714 µs&#10;jeopardy.json: 67,038 µ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: 154 µs (validates fully)&#10;citm_catalog.json: 279 µs (validates fully)&#10;canada.json: 989 µs (validates fully)&#10;jeopardy.json: 64,301 µ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.87× the time of the fastest library (fully validating)&#10;twitter.json: 334 µs · insitu (copy untimed)&#10;citm_catalog.json: 811 µs · insitu (copy untimed)&#10;canada.json: 2,580 µs · read (raw numbers)&#10;jeopardy.json: 83,153 µs · insitu (copy untimed)">
<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">1.87</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.00× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 399 µs&#10;citm_catalog.json: 946 µs&#10;canada.json: 3,445 µs&#10;jeopardy.json: 88,447 µs">
<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.00</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.23× the time of the fastest library (fully validating)&#10;twitter.json: 351 µs · insitu (copy untimed)&#10;citm_catalog.json: 788 µs · insitu (copy untimed)&#10;canada.json: 2,632 µs · read (raw numbers)&#10;jeopardy.json: 92,551 µs · insitu (copy untimed)">
<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.23</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: 918 µs · insitu (copy) + mut copy&#10;citm_catalog.json: 1,548 µs · insitu (copy untimed) + mut copy&#10;canada.json: 7,155 µs · insitu (copy untimed) + mut copy&#10;jeopardy.json: 270,654 µs · insitu (copy untimed) + 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.16× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed) + write&#10;twitter.json: 620 µs&#10;citm_catalog.json: 1,189 µs&#10;canada.json: 6,283 µs&#10;jeopardy.json: 154,016 µ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.16</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;1.00× the time of the fastest fully validating library&#10;twitter.json: 620 µs · insitu (copy untimed) + write (validates fully)&#10;citm_catalog.json: 1,189 µs · insitu (copy untimed) + write (validates fully)&#10;canada.json: 3,472 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 154,016 µs · insitu (copy untimed) + 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.00</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.14× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 218 µs&#10;citm_catalog.json: 386 µs&#10;canada.json: 3,476 µs&#10;jeopardy.json: 71,247 µ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.14</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: 448 µs&#10;citm_catalog.json: 1,032 µs&#10;canada.json: 3,143 µs&#10;jeopardy.json: 94,884 µ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.20× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 502 µs&#10;citm_catalog.json: 1,175 µs&#10;canada.json: 3,754 µs&#10;jeopardy.json: 104,583 µ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.20</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.53× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 460 µs&#10;citm_catalog.json: 1,011 µs&#10;canada.json: 3,204 µs&#10;jeopardy.json: 108,245 µ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="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="132" text-anchor="middle">1.53</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.24× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 711 µs&#10;citm_catalog.json: 1,472 µs&#10;canada.json: 7,996 µs&#10;jeopardy.json: 183,852 µ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.24</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.38× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 710 µs&#10;citm_catalog.json: 1,485 µs&#10;canada.json: 8,122 µs&#10;jeopardy.json: 166,935 µ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.38</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.28× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 224 µs&#10;citm_catalog.json: 475 µs&#10;canada.json: 4,850 µs&#10;jeopardy.json: 65,131 µ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.28</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.03× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 306 µs&#10;citm_catalog.json: 732 µs&#10;canada.json: 3,206 µs&#10;jeopardy.json: 113,452 µ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.03</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · sum&#10;1.13× the time of the fastest library (fully validating)&#10;twitter.json: 394 µs · D&#8203;OM&#10;citm_catalog.json: 977 µs · D&#8203;OM&#10;canada.json: 4,117 µs · D&#8203;OM&#10;jeopardy.json: 114,602 µs · On-Demand">
<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.13</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select&#10;1.32× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 316 µs&#10;citm_catalog.json: 731 µs&#10;canada.json: 3,262 µs&#10;jeopardy.json: 120,808 µ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.32</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.57× the time of the fastest fully validating library&#10;twitter.json: 181 µs · On-Demand structs&#10;citm_catalog.json: 495 µs · On-Demand&#10;canada.json: 702 µs · On-Demand&#10;jeopardy.json: 48,823 µ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.57</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.58× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 783 µs&#10;citm_catalog.json: 1,395 µs&#10;canada.json: 8,303 µs&#10;jeopardy.json: 275,007 µ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.58</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: 105 µs&#10;citm_catalog.json: 269 µs&#10;canada.json: 337 µs&#10;jeopardy.json: 45,087 µ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.00× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 389 µs&#10;citm_catalog.json: 656 µs&#10;canada.json: 4,896 µs&#10;jeopardy.json: 157,616 µ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.00</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.88× 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.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.07× 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.07</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · select&#10;1.39× 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.39</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.73× 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.73</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;1.94× 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">1.94</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.79× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 571 µs&#10;citm_catalog.json: 910 µs&#10;canada.json: 1,684 µs&#10;jeopardy.json: 55,498 µ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.79</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.12× 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,809 µs&#10;jeopardy.json: 56,774 µs">
<rect class="nj-heat-0" x="317" y="225" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="246" text-anchor="middle">1.12</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.24× the time of the fastest library (fully validating)&#10;twitter.json: 776 µs · parse_into structs&#10;citm_catalog.json: 1,389 µs · parse_into structs&#10;canada.json: 7,121 µs · parse&#10;jeopardy.json: 97,681 µ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.24</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.39× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,855 µs&#10;citm_catalog.json: 2,596 µs&#10;canada.json: 12,765 µs&#10;jeopardy.json: 350,286 µ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.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;2.68× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 1,924 µs&#10;citm_catalog.json: 2,569 µs&#10;canada.json: 12,622 µs&#10;jeopardy.json: 329,090 µ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.68</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;2.31× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 478 µs&#10;citm_catalog.json: 916 µs&#10;canada.json: 5,615 µs&#10;jeopardy.json: 141,846 µ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.31</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="282" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.52× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">3.52</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.80× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.80</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.64× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">2.64</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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">2.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.38× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">3.38</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.21× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">2.21</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.33× 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="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="318" text-anchor="middle">2.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;2.08× 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="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="312" text-anchor="middle">2.08</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.22× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">2.22</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;1.77× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="318" text-anchor="middle">1.77</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.54× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">4.54</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;4.92× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="318" text-anchor="middle">4.92</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.15× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.15</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="354" text-anchor="end">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.23× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 588 µs&#10;citm_catalog.json: 1,431 µs&#10;canada.json: 1,867 µs&#10;jeopardy.json: 75,571 µs">
<rect class="nj-heat-2" x="225" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="354" text-anchor="middle">2.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.03× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,427 µs&#10;citm_catalog.json: 3,972 µs&#10;canada.json: 12,165 µs&#10;jeopardy.json: 253,385 µs">
<rect class="nj-heat-3" x="317" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="354" text-anchor="middle">4.03</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum, checking less&#10;3.78× the time of the fastest fully validating library&#10;twitter.json: 2,427 µs · generic (double, strict) (validates fully)&#10;citm_catalog.json: 3,972 µs · generic (double, strict) (validates fully)&#10;canada.json: 12,165 µs · generic (double, strict) (validates fully)&#10;jeopardy.json: 196,582 µ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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="348" text-anchor="middle">3.78</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="361" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.43× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 544 µs&#10;citm_catalog.json: 1,368 µs&#10;canada.json: 1,924 µs&#10;jeopardy.json: 85,745 µs">
<rect class="nj-heat-1" x="409" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="354" text-anchor="middle">1.43</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.62× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 345 µs&#10;citm_catalog.json: 419 µs&#10;canada.json: 444 µs&#10;jeopardy.json: 66,442 µ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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="348" text-anchor="middle">0.62</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="361" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;5.53× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 4,341 µs&#10;citm_catalog.json: 7,322 µs&#10;canada.json: 26,786 µs&#10;jeopardy.json: 725,881 µs">
<rect class="nj-heat-4" x="501" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="354" text-anchor="middle">5.53</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;5.77× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 4,132 µs&#10;citm_catalog.json: 7,465 µs&#10;canada.json: 26,962 µs&#10;jeopardy.json: 528,811 µs">
<rect class="nj-heat-4" x="593" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="354" text-anchor="middle">5.77</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: 444 µs&#10;citm_catalog.json: 1,059 µs&#10;canada.json: 2,222 µs&#10;jeopardy.json: 91,153 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="348" text-anchor="middle">0.70</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="361" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;1.90× the time of the fastest library (fully validating)&#10;way: generic&#10;twitter.json: 399 µs&#10;citm_catalog.json: 748 µs&#10;canada.json: 4,220 µs&#10;jeopardy.json: 128,020 µ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">1.90</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="390" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;2.77× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 658 µs&#10;citm_catalog.json: 1,390 µs&#10;canada.json: 4,265 µs&#10;jeopardy.json: 71,982 µs">
<rect class="nj-heat-3" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.77</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.44× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 728 µs&#10;citm_catalog.json: 1,393 µs&#10;canada.json: 5,428 µs&#10;jeopardy.json: 89,481 µs">
<rect class="nj-heat-1" x="317" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="390" text-anchor="middle">1.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;7.56× the time of the fastest library (fully validating)&#10;twitter.json: 3,602 µs · structs (from_json)&#10;citm_catalog.json: 5,124 µs · parse&#10;canada.json: 11,831 µs · parse&#10;jeopardy.json: 444,210 µs · parse">
<rect class="nj-heat-4" x="409" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="390" text-anchor="middle">7.56</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.99× the time of the fastest library (fully validating)&#10;twitter.json: 3,069 µs · ordered_json&#10;citm_catalog.json: 4,905 µs · ordered_json&#10;canada.json: 16,702 µs · parse&#10;jeopardy.json: 666,261 µs · ordered_json">
<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">3.99</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.91× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 4,445 µs&#10;citm_catalog.json: 5,713 µs&#10;canada.json: 16,711 µs&#10;jeopardy.json: 543,033 µs">
<rect class="nj-heat-3" x="593" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="390" text-anchor="middle">4.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.86× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 451 µs&#10;citm_catalog.json: 628 µs&#10;canada.json: 4,506 µs&#10;jeopardy.json: 116,529 µ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.86</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.94× the time of the fastest library (fully validating)&#10;twitter.json: 1,756 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,971 µs · S&#8203;AX (default precision)&#10;canada.json: 4,118 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 198,915 µs · insitu (copy untimed)">
<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.94</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.76× the time of the fastest fully validating library&#10;twitter.json: 1,132 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,572 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 4,083 µs · S&#8203;AX (string stream, default precision) (no encoding check)&#10;jeopardy.json: 131,204 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.76</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.98× the time of the fastest library (fully validating)&#10;twitter.json: 1,816 µs · insitu (copy untimed)&#10;citm_catalog.json: 2,224 µs · S&#8203;AX&#10;canada.json: 10,719 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 206,811 µs · insitu (copy untimed)">
<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.98</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.28× the time of the fastest fully validating library&#10;twitter.json: 1,187 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,765 µs · S&#8203;AX (no encoding check)&#10;canada.json: 10,719 µs · S&#8203;AX (string stream) (validates fully)&#10;jeopardy.json: 135,945 µs · S&#8203;AX (string stream) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.28</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.20× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 1,762 µs&#10;citm_catalog.json: 2,198 µs&#10;canada.json: 11,464 µs&#10;jeopardy.json: 209,290 µs">
<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.20</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.27× the time of the fastest fully validating library&#10;twitter.json: 1,144 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,817 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 11,464 µs · insitu (copy untimed) (validates fully)&#10;jeopardy.json: 142,852 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.27</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.06× the time of the fastest library (fully validating)&#10;twitter.json: 2,635 µs · insitu (copy)&#10;citm_catalog.json: 3,103 µs · insitu (copy untimed)&#10;canada.json: 21,139 µs · insitu (copy untimed)&#10;jeopardy.json: 333,913 µs · insitu (copy untimed)&#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.06</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.60× the time of the fastest fully validating library&#10;twitter.json: 1,952 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 2,728 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 21,139 µs · insitu (copy untimed) (validates fully)&#10;jeopardy.json: 267,081 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.60</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.61× the time of the fastest library (fully validating)&#10;twitter.json: 2,808 µs · S&#8203;AX to Writer&#10;citm_catalog.json: 2,975 µs · S&#8203;AX to Writer&#10;canada.json: 22,589 µs · Document + Writer&#10;jeopardy.json: 358,807 µ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.61</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;2.65× the time of the fastest fully validating library&#10;twitter.json: 2,022 µs · S&#8203;AX to Writer (raw numbers) (no encoding check)&#10;citm_catalog.json: 2,480 µs · S&#8203;AX to Writer (no encoding check)&#10;canada.json: 14,986 µs · S&#8203;AX to Writer (raw numbers) (validates fully)&#10;jeopardy.json: 261,527 µ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.65</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.79× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 627 µs&#10;citm_catalog.json: 1,008 µs&#10;canada.json: 9,596 µs&#10;jeopardy.json: 123,764 µ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.79</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.08; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.79 doing less, N); nlohmann/json json_document minify: 1.00 (0.80 doing less, N); nlohmann/json json_document write: 1.00 (0.64 doing less, N); yyjson validate: 1.94; yyjson sum: 1.14; yyjson select: 1.18; yyjson edit: 1.37; yyjson minify: 1.17 (0.95 doing less, N); yyjson write: 1.11; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.24 doing less, U); sonic-cpp select: no fully validating way (1.45 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.45; simdjson validate: 2.11; simdjson sum: 1.00; simdjson select: 1.27 (0.54 doing less, P); simdjson edit: n/a; simdjson minify: 1.54 (0.17 doing less, P); simdjson write: 2.10; sonic-rs (Rust) validate: 1.93; sonic-rs (Rust) sum: 1.13; sonic-rs (Rust) select: 1.34; sonic-rs (Rust) edit: 1.90; sonic-rs (Rust) minify: 1.71; sonic-rs (Rust) write: 2.04; Boost.J&#8203;SON validate: 1.99; Boost.J&#8203;SON sum: 1.27; Boost.J&#8203;SON select: 2.20; Boost.J&#8203;SON edit: 2.30; Boost.J&#8203;SON minify: 2.65; Boost.J&#8203;SON write: 2.36; simd-json (Rust) validate: 3.62; simd-json (Rust) sum: 1.91; simd-json (Rust) select: 2.56; simd-json (Rust) edit: 2.87; simd-json (Rust) minify: 3.35; simd-json (Rust) write: 2.32; RapidJSON validate: 3.71 (3.41 doing less, U); RapidJSON sum: 2.23 (2.09 doing less, U); RapidJSON select: 2.91 (2.73 doing less, U); RapidJSON edit: 2.41 (2.34 doing less, U); RapidJSON minify: 2.68 (2.42 doing less, U N); RapidJSON write: 2.97; serde_json (Rust) validate: 2.39 (2.14 doing less, U); serde_json (Rust) sum: 2.36; serde_json (Rust) select: 1.71; serde_json (Rust) edit: 4.53; serde_json (Rust) minify: 4.89; serde_json (Rust) write: 2.25; Glaze validate: 2.86; Glaze sum: 4.16; Glaze select: 1.79 (0.58 doing less, P); Glaze edit: 4.47; Glaze minify: 4.81 (0.78 doing less, P); Glaze write: 1.96; nlohmann/json json validate: 2.96; nlohmann/json json sum: 1.70; nlohmann/json json select: 7.12; nlohmann/json json edit: 3.83; nlohmann/json json minify: 4.79; nlohmann/json json write: 1.91.</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: 258 µs&#10;citm_catalog.json: 513 µs&#10;canada.json: 934 µs&#10;jeopardy.json: 34,514 µ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.08× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 398 µs&#10;citm_catalog.json: 972 µs&#10;canada.json: 3,501 µs&#10;jeopardy.json: 89,756 µ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.08</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: 333 µs · structs (from_json)&#10;citm_catalog.json: 828 µs · parse&#10;canada.json: 1,368 µs · parse&#10;jeopardy.json: 89,876 µ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: 536 µs&#10;citm_catalog.json: 1,162 µs&#10;canada.json: 5,567 µs&#10;jeopardy.json: 192,323 µ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.79× the time of the fastest fully validating library&#10;twitter.json: 530 µs · editable (source numbers) (validates fully)&#10;citm_catalog.json: 1,149 µs · editable (source numbers) (validates fully)&#10;canada.json: 2,188 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 192,323 µ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.79</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: 518 µs&#10;citm_catalog.json: 1,045 µs&#10;canada.json: 5,240 µs&#10;jeopardy.json: 143,737 µ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.80× the time of the fastest fully validating library&#10;twitter.json: 496 µs · parse + dump (source numbers) (validates fully)&#10;citm_catalog.json: 1,045 µs · parse + dump (validates fully)&#10;canada.json: 2,196 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 143,206 µs · parse + 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="639" y="45" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="60" text-anchor="middle">0.80</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: 156 µs&#10;citm_catalog.json: 251 µs&#10;canada.json: 3,842 µs&#10;jeopardy.json: 67,769 µ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: 140 µs (validates fully)&#10;citm_catalog.json: 230 µs (validates fully)&#10;canada.json: 823 µs (validates fully)&#10;jeopardy.json: 65,376 µ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;1.94× the time of the fastest library (fully validating)&#10;twitter.json: 352 µs · insitu (copy untimed)&#10;citm_catalog.json: 837 µs · insitu (copy untimed)&#10;canada.json: 2,199 µs · read (raw numbers)&#10;jeopardy.json: 93,043 µs · insitu (copy untimed)">
<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">1.94</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;way: insitu (copy untimed)&#10;twitter.json: 415 µs&#10;citm_catalog.json: 986 µs&#10;canada.json: 3,818 µs&#10;jeopardy.json: 97,586 µs">
<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.18× the time of the fastest library (fully validating)&#10;twitter.json: 366 µs · insitu (copy untimed)&#10;citm_catalog.json: 840 µs · insitu (copy untimed)&#10;canada.json: 2,204 µs · read (raw numbers)&#10;jeopardy.json: 96,172 µs · insitu (copy untimed)">
<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.18</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.37× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed) + mut copy&#10;twitter.json: 746 µs&#10;citm_catalog.json: 1,526 µs&#10;canada.json: 7,479 µs&#10;jeopardy.json: 275,025 µs">
<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.37</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify&#10;1.17× the time of the fastest library (fully validating)&#10;twitter.json: 626 µs · insitu (copy) + write&#10;citm_catalog.json: 1,160 µs · insitu (copy untimed) + write&#10;canada.json: 6,701 µs · insitu (copy untimed) + write&#10;jeopardy.json: 156,605 µs · insitu (copy untimed) + 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.17</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · minify, checking less&#10;0.95× the time of the fastest fully validating library&#10;twitter.json: 626 µs · insitu (copy) + write (validates fully)&#10;citm_catalog.json: 1,160 µs · insitu (copy untimed) + write (validates fully)&#10;canada.json: 2,901 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 156,605 µs · insitu (copy untimed) + 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.95</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.11× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 215 µs&#10;citm_catalog.json: 319 µs&#10;canada.json: 3,360 µs&#10;jeopardy.json: 66,669 µ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.11</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: 403 µs&#10;citm_catalog.json: 932 µs&#10;canada.json: 3,349 µs&#10;jeopardy.json: 98,511 µ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.24× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 456 µs&#10;citm_catalog.json: 1,115 µs&#10;canada.json: 3,980 µs&#10;jeopardy.json: 105,081 µ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.24</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.45× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 407 µs&#10;citm_catalog.json: 948 µs&#10;canada.json: 3,464 µs&#10;jeopardy.json: 110,885 µ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.45</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: 620 µs&#10;citm_catalog.json: 1,438 µs&#10;canada.json: 8,495 µs&#10;jeopardy.json: 186,078 µ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: 675 µs&#10;citm_catalog.json: 1,417 µs&#10;canada.json: 8,958 µs&#10;jeopardy.json: 164,630 µ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.45× the time of the fastest library (fully validating)&#10;way: Serialize&#10;twitter.json: 249 µs&#10;citm_catalog.json: 509 µs&#10;canada.json: 5,074 µs&#10;jeopardy.json: 69,916 µ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.45</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.11× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 301 µs&#10;citm_catalog.json: 695 µs&#10;canada.json: 3,337 µs&#10;jeopardy.json: 120,982 µ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.11</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: 348 µs&#10;citm_catalog.json: 805 µs&#10;canada.json: 3,452 µs&#10;jeopardy.json: 92,769 µ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.27× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 313 µs&#10;citm_catalog.json: 699 µs&#10;canada.json: 3,325 µs&#10;jeopardy.json: 122,556 µ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.27</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.54× the time of the fastest fully validating library&#10;twitter.json: 180 µs · On-Demand&#10;citm_catalog.json: 496 µs · On-Demand (key selectors)&#10;canada.json: 690 µs · On-Demand (key selectors)&#10;jeopardy.json: 48,272 µ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.54</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.54× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 714 µs&#10;citm_catalog.json: 1,318 µs&#10;canada.json: 9,135 µs&#10;jeopardy.json: 269,597 µ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.54</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: 99.9 µs&#10;citm_catalog.json: 278 µs&#10;canada.json: 312 µs&#10;jeopardy.json: 42,644 µ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.10× the time of the fastest library (fully validating)&#10;way: to_string&#10;twitter.json: 361 µs&#10;citm_catalog.json: 614 µs&#10;canada.json: 5,609 µs&#10;jeopardy.json: 158,492 µ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.10</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.93× 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.93</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.34× 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.34</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.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.04× 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.04</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.99× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 690 µs&#10;citm_catalog.json: 917 µs&#10;canada.json: 1,676 µs&#10;jeopardy.json: 62,781 µ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.99</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.27× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 699 µs&#10;citm_catalog.json: 957 µs&#10;canada.json: 5,835 µs&#10;jeopardy.json: 59,656 µ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.27</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.20× the time of the fastest library (fully validating)&#10;twitter.json: 887 µs · parse_into structs&#10;citm_catalog.json: 1,270 µs · parse_into structs&#10;canada.json: 7,292 µs · parse&#10;jeopardy.json: 95,866 µ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.20</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.30× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,767 µs&#10;citm_catalog.json: 2,493 µs&#10;canada.json: 12,767 µs&#10;jeopardy.json: 331,310 µ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.30</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,974 µs&#10;citm_catalog.json: 2,525 µs&#10;canada.json: 12,748 µs&#10;jeopardy.json: 314,299 µ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.36× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 469 µs&#10;citm_catalog.json: 830 µs&#10;canada.json: 5,659 µs&#10;jeopardy.json: 144,174 µ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.36</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="282" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.62× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">3.62</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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · select&#10;2.56× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">2.56</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.87× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">2.87</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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">3.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.32× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">2.32</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">RapidJSON</text>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate&#10;3.71× the time of the fastest library (fully validating)&#10;twitter.json: 1,166 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,553 µs · S&#8203;AX (string stream, default precision)&#10;canada.json: 3,875 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 114,704 µs · insitu (copy untimed)">
<rect class="nj-heat-3" x="225" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="318" text-anchor="middle">3.71</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.41× the time of the fastest fully validating library&#10;twitter.json: 1,012 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,434 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 3,875 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 102,635 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<rect class="nj-heat-3" x="271" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="312" text-anchor="middle">3.41</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum&#10;2.23× the time of the fastest library (fully validating)&#10;twitter.json: 1,221 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,717 µs · S&#8203;AX (string stream)&#10;canada.json: 9,435 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 112,158 µs · insitu (copy untimed)">
<rect class="nj-heat-2" x="317" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="339.5" y="318" text-anchor="middle">2.23</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.09× the time of the fastest fully validating library&#10;twitter.json: 1,063 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,635 µs · S&#8203;AX (string stream) (no encoding check)&#10;canada.json: 9,368 µs · S&#8203;AX (string stream) (no encoding check)&#10;jeopardy.json: 105,845 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<rect class="nj-heat-2" x="363" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="384.5" y="312" text-anchor="middle">2.09</text>
<text class="nj-charts-cell nj-charts-cell--small" x="384.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select&#10;2.91× the time of the fastest library (fully validating)&#10;twitter.json: 1,180 µs · insitu (copy untimed)&#10;citm_catalog.json: 1,693 µs · insitu (copy untimed)&#10;canada.json: 10,390 µs · Document (string stream)&#10;jeopardy.json: 116,394 µs · insitu (copy untimed)">
<rect class="nj-heat-3" x="409" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="318" text-anchor="middle">2.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;2.73× the time of the fastest fully validating library&#10;twitter.json: 1,022 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,648 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 10,390 µs · Document (string stream) (validates fully)&#10;jeopardy.json: 108,290 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<rect class="nj-heat-3" x="455" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="312" text-anchor="middle">2.73</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit&#10;2.41× the time of the fastest library (fully validating)&#10;twitter.json: 1,865 µs · insitu (copy untimed)&#10;citm_catalog.json: 2,616 µs · insitu (copy untimed)&#10;canada.json: 18,812 µs · Document (string stream)&#10;jeopardy.json: 245,724 µs · insitu (copy untimed)">
<rect class="nj-heat-2" x="501" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="523.5" y="318" text-anchor="middle">2.41</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.34× the time of the fastest fully validating library&#10;twitter.json: 1,737 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 2,595 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 18,812 µs · Document (string stream) (validates fully)&#10;jeopardy.json: 234,669 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<rect class="nj-heat-2" x="547" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="568.5" y="312" text-anchor="middle">2.34</text>
<text class="nj-charts-cell nj-charts-cell--small" x="568.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify&#10;2.68× the time of the fastest library (fully validating)&#10;way: S&#8203;AX to Writer (string stream)&#10;twitter.json: 1,949 µs&#10;citm_catalog.json: 2,382 µs&#10;canada.json: 19,548 µs&#10;jeopardy.json: 231,979 µs">
<rect class="nj-heat-3" x="593" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="318" text-anchor="middle">2.68</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · minify, checking less&#10;2.42× the time of the fastest fully validating library&#10;twitter.json: 1,880 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;citm_catalog.json: 2,314 µs · S&#8203;AX to Writer (string stream) (no encoding check)&#10;canada.json: 14,400 µs · S&#8203;AX to Writer (raw numbers) (validates fully)&#10;jeopardy.json: 224,249 µ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-2" x="639" y="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="312" text-anchor="middle">2.42</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="325" text-anchor="middle">U N</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · write&#10;2.97× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 678 µs&#10;citm_catalog.json: 979 µs&#10;canada.json: 9,095 µs&#10;jeopardy.json: 131,408 µs">
<rect class="nj-heat-3" x="685" y="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="318" text-anchor="middle">2.97</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.39× 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.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;2.14× 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.14</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.36× 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.36</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · select&#10;1.71× 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.71</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.89× 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.89</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.25× 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.25</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.86× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 712 µs&#10;citm_catalog.json: 1,983 µs&#10;canada.json: 2,625 µs&#10;jeopardy.json: 76,759 µs">
<rect class="nj-heat-3" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.86</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.16× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,483 µs&#10;citm_catalog.json: 4,413 µs&#10;canada.json: 10,532 µs&#10;jeopardy.json: 231,505 µ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">4.16</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.79× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 606 µs&#10;citm_catalog.json: 2,476 µs&#10;canada.json: 2,557 µs&#10;jeopardy.json: 89,957 µ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">1.79</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: 344 µs&#10;citm_catalog.json: 402 µs&#10;canada.json: 417 µs&#10;jeopardy.json: 67,467 µ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.47× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,389 µs&#10;citm_catalog.json: 6,002 µs&#10;canada.json: 21,598 µs&#10;jeopardy.json: 607,767 µ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.47</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;4.81× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,685 µs&#10;citm_catalog.json: 5,942 µs&#10;canada.json: 22,138 µs&#10;jeopardy.json: 450,322 µ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.81</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;0.78× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 442 µs&#10;citm_catalog.json: 1,292 µs&#10;canada.json: 2,726 µs&#10;jeopardy.json: 97,377 µ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.78</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.96× the time of the fastest library (fully validating)&#10;way: generic&#10;twitter.json: 381 µs&#10;citm_catalog.json: 730 µs&#10;canada.json: 4,071 µs&#10;jeopardy.json: 131,946 µ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.96</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="426" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;2.96× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 683 µs&#10;citm_catalog.json: 1,419 µs&#10;canada.json: 4,559 µs&#10;jeopardy.json: 74,331 µ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.96</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.70× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 814 µs&#10;citm_catalog.json: 1,666 µs&#10;canada.json: 5,690 µs&#10;jeopardy.json: 97,414 µs">
<rect class="nj-heat-2" x="317" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="426" text-anchor="middle">1.70</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;7.12× the time of the fastest library (fully validating)&#10;twitter.json: 3,360 µs · structs (from_json)&#10;citm_catalog.json: 5,268 µs · structs (from_json)&#10;canada.json: 12,006 µs · structs (from_json)&#10;jeopardy.json: 410,221 µs · parse">
<rect class="nj-heat-4" x="409" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="426" text-anchor="middle">7.12</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.83× the time of the fastest library (fully validating)&#10;way: ordered_json&#10;twitter.json: 2,832 µs&#10;citm_catalog.json: 4,970 µs&#10;canada.json: 15,806 µs&#10;jeopardy.json: 647,704 µ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">3.83</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.79× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 4,196 µs&#10;citm_catalog.json: 5,806 µs&#10;canada.json: 16,626 µs&#10;jeopardy.json: 529,560 µs">
<rect class="nj-heat-3" x="593" y="405" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="426" text-anchor="middle">4.79</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.91× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 444 µs&#10;citm_catalog.json: 640 µs&#10;canada.json: 4,089 µs&#10;jeopardy.json: 117,316 µ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.91</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: 45 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-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.08; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.83 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: 1.81; yyjson sum: 1.28; yyjson select: 1.22; yyjson edit: 1.49; yyjson minify: 1.27 (0.97 doing less, N); yyjson write: 1.14; sonic-cpp validate: no fully validating way (2.24 doing less, U); sonic-cpp sum: no fully validating way (1.28 doing less, U); sonic-cpp select: no fully validating way (1.53 doing less, U); sonic-cpp edit: no fully validating way (1.26 doing less, U); sonic-cpp minify: no fully validating way (1.42 doing less, U); sonic-cpp write: 1.50; simdjson validate: 2.01; simdjson sum: 1.00; simdjson select: 1.35 (0.57 doing less, P); simdjson edit: n/a; simdjson minify: 1.58 (0.22 doing less, P); simdjson write: 2.07; sonic-rs (Rust) validate: 1.79; sonic-rs (Rust) sum: 1.11; sonic-rs (Rust) select: 1.37; sonic-rs (Rust) edit: 1.91; sonic-rs (Rust) minify: 1.73; sonic-rs (Rust) write: 2.07; Boost.J&#8203;SON validate: 1.88; Boost.J&#8203;SON sum: 1.33; Boost.J&#8203;SON select: 2.30; Boost.J&#8203;SON edit: 2.55; Boost.J&#8203;SON minify: 2.92; Boost.J&#8203;SON write: 2.56; simd-json (Rust) validate: 3.35; simd-json (Rust) sum: 1.88; simd-json (Rust) select: 2.61; simd-json (Rust) edit: 2.89; simd-json (Rust) minify: 3.39; simd-json (Rust) write: 2.35; serde_json (Rust) validate: 2.22 (1.98 doing less, U); serde_json (Rust) sum: 2.32; serde_json (Rust) select: 1.75; serde_json (Rust) edit: 4.55; serde_json (Rust) minify: 4.94; serde_json (Rust) write: 2.28; Glaze validate: 2.21; Glaze sum: 4.04; Glaze select: 1.44 (0.60 doing less, P); Glaze edit: 4.85; Glaze minify: 5.10 (0.73 doing less, P); Glaze write: 1.84; nlohmann/json json validate: 2.74; nlohmann/json json sum: 1.67; nlohmann/json json select: 7.24; nlohmann/json json edit: 3.81; nlohmann/json json minify: 4.79; nlohmann/json json write: 1.99; RapidJSON validate: 4.50 (3.40 doing less, U); RapidJSON sum: 2.98 (2.29 doing less, U); RapidJSON select: 3.84 (3.06 doing less, U); RapidJSON edit: 2.92 (2.58 doing less, U); RapidJSON minify: 3.64 (2.64 doing less, U N); RapidJSON write: 3.11.</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: 271 µs&#10;citm_catalog.json: 609 µs&#10;canada.json: 1,011 µs&#10;jeopardy.json: 34,722 µ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.08× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 392 µs&#10;citm_catalog.json: 946 µs&#10;canada.json: 3,888 µs&#10;jeopardy.json: 89,044 µ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.08</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: 332 µs&#10;citm_catalog.json: 765 µs&#10;canada.json: 1,390 µs&#10;jeopardy.json: 88,202 µ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: 532 µs&#10;citm_catalog.json: 1,116 µs&#10;canada.json: 5,714 µs&#10;jeopardy.json: 192,363 µ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.83× the time of the fastest fully validating library&#10;twitter.json: 532 µs · editable (validates fully)&#10;citm_catalog.json: 1,116 µs · editable (validates fully)&#10;canada.json: 2,702 µs · editable (source numbers) (validates fully)&#10;jeopardy.json: 192,363 µ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.83</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;twitter.json: 483 µs · parse + dump&#10;citm_catalog.json: 1,014 µs · parse + dump&#10;canada.json: 5,459 µs · parse_copy + dump&#10;jeopardy.json: 146,320 µs · parse + dump">
<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: 483 µs · parse + dump (validates fully)&#10;citm_catalog.json: 1,014 µs · parse + dump (validates fully)&#10;canada.json: 2,620 µs · parse + dump (source numbers) (validates fully)&#10;jeopardy.json: 146,320 µ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: 150 µs&#10;citm_catalog.json: 260 µs&#10;canada.json: 3,861 µs&#10;jeopardy.json: 63,958 µ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: 148 µs · dump (source numbers) (validates fully)&#10;citm_catalog.json: 260 µs · dump (validates fully)&#10;canada.json: 998 µs · dump (source numbers) (validates fully)&#10;jeopardy.json: 63,958 µ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;1.81× the time of the fastest library (fully validating)&#10;twitter.json: 348 µs · insitu (copy untimed)&#10;citm_catalog.json: 878 µs · insitu (copy untimed)&#10;canada.json: 2,256 µs · read (raw numbers)&#10;jeopardy.json: 90,959 µs · insitu (copy untimed)">
<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">1.81</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · sum&#10;1.28× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 407 µs&#10;citm_catalog.json: 1,045 µs&#10;canada.json: 6,021 µs&#10;jeopardy.json: 99,764 µ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.28</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · select&#10;1.22× the time of the fastest library (fully validating)&#10;twitter.json: 361 µs · insitu (copy untimed)&#10;citm_catalog.json: 880 µs · insitu (copy untimed)&#10;canada.json: 2,236 µs · read (raw numbers)&#10;jeopardy.json: 98,637 µs · insitu (copy untimed)">
<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.22</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="yyjson · edit&#10;1.49× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed) + mut copy&#10;twitter.json: 761 µs&#10;citm_catalog.json: 1,590 µs&#10;canada.json: 9,860 µs&#10;jeopardy.json: 271,227 µs">
<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.49</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;twitter.json: 592 µs · insitu (copy untimed) + write&#10;citm_catalog.json: 1,205 µs · insitu (copy untimed) + write&#10;canada.json: 9,008 µs · read + write&#10;jeopardy.json: 158,577 µs · insitu (copy untimed) + write">
<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;0.97× the time of the fastest fully validating library&#10;twitter.json: 592 µs · insitu (copy untimed) + write (validates fully)&#10;citm_catalog.json: 1,205 µs · insitu (copy untimed) + write (validates fully)&#10;canada.json: 3,106 µs · read (raw numbers) + write (validates fully)&#10;jeopardy.json: 158,577 µs · insitu (copy untimed) + 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">0.97</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.14× the time of the fastest library (fully validating)&#10;way: write&#10;twitter.json: 204 µs&#10;citm_catalog.json: 327 µs&#10;canada.json: 3,748 µs&#10;jeopardy.json: 65,989 µ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.14</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.24× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 408 µs&#10;citm_catalog.json: 1,028 µs&#10;canada.json: 3,622 µs&#10;jeopardy.json: 96,080 µ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.24</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: 460 µs&#10;citm_catalog.json: 1,210 µs&#10;canada.json: 4,295 µs&#10;jeopardy.json: 107,092 µ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.53× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 413 µs&#10;citm_catalog.json: 1,043 µs&#10;canada.json: 3,695 µs&#10;jeopardy.json: 108,297 µ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="117" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="132" text-anchor="middle">1.53</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.26× the time of the fastest fully validating library&#10;way: Document&#10;twitter.json: 637 µs&#10;citm_catalog.json: 1,559 µs&#10;canada.json: 8,936 µs&#10;jeopardy.json: 186,232 µ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.26</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.42× the time of the fastest fully validating library&#10;way: Document + Serialize&#10;twitter.json: 695 µs&#10;citm_catalog.json: 1,541 µs&#10;canada.json: 8,838 µs&#10;jeopardy.json: 168,901 µ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.42</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: 256 µs&#10;citm_catalog.json: 541 µs&#10;canada.json: 5,120 µs&#10;jeopardy.json: 69,546 µ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;2.01× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 311 µs&#10;citm_catalog.json: 780 µs&#10;canada.json: 3,351 µs&#10;jeopardy.json: 116,704 µ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.01</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: 812 µs&#10;canada.json: 3,435 µs&#10;jeopardy.json: 96,250 µ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.35× the time of the fastest library (fully validating)&#10;way: D&#8203;OM&#10;twitter.json: 324 µs&#10;citm_catalog.json: 756 µs&#10;canada.json: 3,409 µs&#10;jeopardy.json: 123,214 µ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.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · select, checking less&#10;0.57× the time of the fastest fully validating library&#10;twitter.json: 184 µs · On-Demand (key selectors)&#10;citm_catalog.json: 509 µs · On-Demand&#10;canada.json: 700 µs · On-Demand&#10;jeopardy.json: 48,614 µ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.57</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.58× the time of the fastest library (fully validating)&#10;way: D&#8203;OM + to_string&#10;twitter.json: 742 µs&#10;citm_catalog.json: 1,393 µs&#10;canada.json: 8,808 µs&#10;jeopardy.json: 266,718 µ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.58</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simdjson · minify, checking less&#10;0.22× the time of the fastest fully validating library&#10;way: minify&#10;twitter.json: 123 µs&#10;citm_catalog.json: 337 µs&#10;canada.json: 433 µs&#10;jeopardy.json: 47,040 µ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.22</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: 359 µs&#10;citm_catalog.json: 637 µs&#10;canada.json: 4,999 µs&#10;jeopardy.json: 154,364 µ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.79× 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.79</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · sum&#10;1.11× 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.11</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.91× 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.91</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · minify&#10;1.73× 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.73</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="sonic-rs (Rust) · write&#10;2.07× 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.07</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.88× the time of the fastest library (fully validating)&#10;way: S&#8203;AX (numbers: none)&#10;twitter.json: 710 µs&#10;citm_catalog.json: 969 µs&#10;canada.json: 1,718 µs&#10;jeopardy.json: 61,476 µ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.88</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · sum&#10;1.33× the time of the fastest library (fully validating)&#10;way: S&#8203;AX&#10;twitter.json: 734 µs&#10;citm_catalog.json: 1,030 µs&#10;canada.json: 6,103 µs&#10;jeopardy.json: 64,382 µ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.33</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · select&#10;2.30× the time of the fastest library (fully validating)&#10;twitter.json: 884 µs · parse_into structs&#10;citm_catalog.json: 1,380 µs · parse_into structs&#10;canada.json: 7,217 µs · parse&#10;jeopardy.json: 99,078 µ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.30</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · edit&#10;2.55× the time of the fastest library (fully validating)&#10;way: parse&#10;twitter.json: 1,963 µs&#10;citm_catalog.json: 2,936 µs&#10;canada.json: 13,414 µs&#10;jeopardy.json: 356,244 µs">
<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.55</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · minify&#10;2.92× the time of the fastest library (fully validating)&#10;way: parse + serialize&#10;twitter.json: 2,086 µs&#10;citm_catalog.json: 2,919 µs&#10;canada.json: 13,974 µs&#10;jeopardy.json: 334,468 µ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.92</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Boost.J&#8203;SON · write&#10;2.56× the time of the fastest library (fully validating)&#10;way: serialize&#10;twitter.json: 480 µs&#10;citm_catalog.json: 1,016 µs&#10;canada.json: 6,154 µs&#10;jeopardy.json: 139,022 µ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">2.56</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="282" text-anchor="end">simd-json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · validate&#10;3.35× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="282" text-anchor="middle">3.35</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · sum&#10;1.88× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="282" text-anchor="middle">1.88</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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="282" text-anchor="middle">2.61</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · edit&#10;2.89× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="282" text-anchor="middle">2.89</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · minify&#10;3.39× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="282" text-anchor="middle">3.39</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="simd-json (Rust) · write&#10;2.35× 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="261" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="730" y="282" text-anchor="middle">2.35</text>
</g>
<text class="nj-charts-rowlabel " x="216" y="318" text-anchor="end">serde_json (Rust)</text>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate&#10;2.22× 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="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="247.5" y="318" text-anchor="middle">2.22</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · validate, checking less&#10;1.98× 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="297" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="292.5" y="312" text-anchor="middle">1.98</text>
<text class="nj-charts-cell nj-charts-cell--small" x="292.5" y="325" text-anchor="middle">U</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · sum&#10;2.32× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="318" text-anchor="middle">2.32</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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="318" text-anchor="middle">1.75</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · edit&#10;4.55× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="546" y="318" text-anchor="middle">4.55</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · minify&#10;4.94× 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="297" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="318" text-anchor="middle">4.94</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="serde_json (Rust) · write&#10;2.28× 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="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">Glaze</text>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · validate&#10;2.21× the time of the fastest library (fully validating)&#10;way: validate_json&#10;twitter.json: 590 µs&#10;citm_catalog.json: 1,545 µs&#10;canada.json: 1,980 µs&#10;jeopardy.json: 76,009 µs">
<rect class="nj-heat-2" x="225" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="354" text-anchor="middle">2.21</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · sum&#10;4.04× the time of the fastest library (fully validating)&#10;way: generic (double, strict)&#10;twitter.json: 2,345 µs&#10;citm_catalog.json: 4,080 µs&#10;canada.json: 10,576 µs&#10;jeopardy.json: 250,685 µs">
<rect class="nj-heat-3" x="317" y="333" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="354" text-anchor="middle">4.04</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select&#10;1.44× the time of the fastest library (fully validating)&#10;way: structs (validate_skipped)&#10;twitter.json: 529 µs&#10;citm_catalog.json: 1,435 µs&#10;canada.json: 1,913 µs&#10;jeopardy.json: 91,253 µs">
<rect class="nj-heat-1" x="409" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="431.5" y="354" text-anchor="middle">1.44</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · select, checking less&#10;0.60× the time of the fastest fully validating library&#10;way: structs&#10;twitter.json: 342 µs&#10;citm_catalog.json: 410 µs&#10;canada.json: 431 µs&#10;jeopardy.json: 66,069 µ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="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="476.5" y="348" text-anchor="middle">0.60</text>
<text class="nj-charts-cell nj-charts-cell--small" x="476.5" y="361" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · edit&#10;4.85× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,525 µs&#10;citm_catalog.json: 6,551 µs&#10;canada.json: 23,644 µs&#10;jeopardy.json: 661,941 µ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.85</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify&#10;5.10× the time of the fastest library (fully validating)&#10;way: generic (strict)&#10;twitter.json: 3,780 µs&#10;citm_catalog.json: 6,416 µs&#10;canada.json: 23,765 µs&#10;jeopardy.json: 458,311 µs">
<rect class="nj-heat-4" x="593" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="615.5" y="354" text-anchor="middle">5.10</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · minify, checking less&#10;0.73× the time of the fastest fully validating library&#10;way: minify_json&#10;twitter.json: 422 µs&#10;citm_catalog.json: 1,144 µs&#10;canada.json: 2,350 µs&#10;jeopardy.json: 96,405 µs&#10;minify_json only removes whitespace, without parsing the values">
<rect class="nj-heat-0" x="639" y="333" width="44" height="34" rx="3"/>
<text class="nj-charts-cell" x="660.5" y="348" text-anchor="middle">0.73</text>
<text class="nj-charts-cell nj-charts-cell--small" x="660.5" y="361" text-anchor="middle">P</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="Glaze · write&#10;1.84× the time of the fastest library (fully validating)&#10;twitter.json: 360 µs · generic&#10;citm_catalog.json: 660 µs · generic&#10;canada.json: 3,714 µs · generic (strict)&#10;jeopardy.json: 124,598 µs · generic">
<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">1.84</text>
</g>
<text class="nj-charts-rowlabel nj-charts-name-json" x="216" y="390" text-anchor="end">nlohmann/json json</text>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · validate&#10;2.74× the time of the fastest library (fully validating)&#10;way: accept&#10;twitter.json: 677 µs&#10;citm_catalog.json: 1,433 µs&#10;canada.json: 4,584 µs&#10;jeopardy.json: 73,561 µs">
<rect class="nj-heat-3" x="225" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="270" y="390" text-anchor="middle">2.74</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · sum&#10;1.67× the time of the fastest library (fully validating)&#10;way: sax&#10;twitter.json: 797 µs&#10;citm_catalog.json: 1,548 µs&#10;canada.json: 6,004 µs&#10;jeopardy.json: 101,516 µs">
<rect class="nj-heat-2" x="317" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="362" y="390" text-anchor="middle">1.67</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · select&#10;7.24× the time of the fastest library (fully validating)&#10;way: structs (from_json)&#10;twitter.json: 3,325 µs&#10;citm_catalog.json: 5,126 µs&#10;canada.json: 11,908 µs&#10;jeopardy.json: 423,362 µs">
<rect class="nj-heat-4" x="409" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="454" y="390" text-anchor="middle">7.24</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · edit&#10;3.81× the time of the fastest library (fully validating)&#10;way: ordered_json&#10;twitter.json: 2,912 µs&#10;citm_catalog.json: 4,999 µs&#10;canada.json: 15,603 µs&#10;jeopardy.json: 604,744 µ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">3.81</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · minify&#10;4.79× the time of the fastest library (fully validating)&#10;way: parse + dump&#10;twitter.json: 4,143 µs&#10;citm_catalog.json: 5,702 µs&#10;canada.json: 16,463 µs&#10;jeopardy.json: 528,092 µs">
<rect class="nj-heat-3" x="593" y="369" width="90" height="34" rx="3"/>
<text class="nj-charts-cell" x="638" y="390" text-anchor="middle">4.79</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="nlohmann/json json · write&#10;1.99× the time of the fastest library (fully validating)&#10;way: dump&#10;twitter.json: 471 µs&#10;citm_catalog.json: 644 µs&#10;canada.json: 4,344 µs&#10;jeopardy.json: 114,096 µ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.99</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.50× the time of the fastest library (fully validating)&#10;twitter.json: 1,552 µs · insitu (copy untimed)&#10;citm_catalog.json: 2,210 µs · insitu (copy untimed)&#10;canada.json: 4,104 µs · S&#8203;AX (string stream, default precision)&#10;jeopardy.json: 168,747 µs · insitu (copy untimed)">
<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.50</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · validate, checking less&#10;3.40× the time of the fastest fully validating library&#10;twitter.json: 1,082 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,570 µs · S&#8203;AX (default precision) (no encoding check)&#10;canada.json: 4,104 µs · S&#8203;AX (string stream, default precision) (validates fully)&#10;jeopardy.json: 110,856 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.40</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.98× the time of the fastest library (fully validating)&#10;twitter.json: 1,616 µs · insitu (copy untimed)&#10;citm_catalog.json: 2,290 µs · insitu (copy untimed)&#10;canada.json: 11,183 µs · S&#8203;AX (string stream)&#10;jeopardy.json: 181,500 µs · insitu (copy untimed)">
<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.98</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · sum, checking less&#10;2.29× the time of the fastest fully validating library&#10;twitter.json: 1,130 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,743 µs · S&#8203;AX (no encoding check)&#10;canada.json: 11,109 µs · S&#8203;AX (string stream) (no encoding check)&#10;jeopardy.json: 119,706 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.29</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.84× the time of the fastest library (fully validating)&#10;way: insitu (copy untimed)&#10;twitter.json: 1,560 µs&#10;citm_catalog.json: 2,127 µs&#10;canada.json: 11,547 µs&#10;jeopardy.json: 176,066 µs">
<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.84</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · select, checking less&#10;3.06× the time of the fastest fully validating library&#10;twitter.json: 1,079 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 1,817 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 11,436 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 122,354 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.06</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.92× the time of the fastest library (fully validating)&#10;twitter.json: 2,333 µs · insitu (copy untimed)&#10;citm_catalog.json: 3,133 µs · insitu (copy untimed)&#10;canada.json: 20,518 µs · insitu (copy)&#10;jeopardy.json: 315,892 µs · insitu (copy untimed)&#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.92</text>
</g>
<g class="nj-heat-cell" tabindex="0" data-tip="RapidJSON · edit, checking less&#10;2.58× the time of the fastest fully validating library&#10;twitter.json: 1,838 µs · insitu (copy untimed) (no encoding check)&#10;citm_catalog.json: 2,836 µs · insitu (copy untimed) (no encoding check)&#10;canada.json: 20,320 µs · Document (string stream) (no encoding check)&#10;jeopardy.json: 271,888 µs · insitu (copy untimed) (no encoding check)&#10;trusts U&#8203;TF-8: RapidJSON&#x27;s default (kParseValidateEncodingFlag checks it)">
<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.58</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: 3,015 µs · S&#8203;AX to Writer&#10;citm_catalog.json: 3,012 µs · S&#8203;AX to Writer&#10;canada.json: 21,177 µs · Document + Writer&#10;jeopardy.json: 355,727 µ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.64× the time of the fastest fully validating library&#10;twitter.json: 1,978 µs · S&#8203;AX to Writer (no encoding check)&#10;citm_catalog.json: 2,493 µs · S&#8203;AX to Writer (no encoding check)&#10;canada.json: 15,512 µs · S&#8203;AX to Writer (raw numbers) (no encoding check)&#10;jeopardy.json: 249,235 µ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.64</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;3.11× the time of the fastest library (fully validating)&#10;way: Writer&#10;twitter.json: 717 µs&#10;citm_catalog.json: 1,033 µs&#10;canada.json: 9,017 µs&#10;jeopardy.json: 134,260 µ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">3.11</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: 45 KiB

+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();
}
})();
-6
View File
@@ -8,7 +8,6 @@
*[BDFL]: Benevolent Dictator for Life
*[BJData]: Binary JData
*[BON8]: Binary Object Notation 8
*[BSL]: Boost Software License
*[BSON]: Binary JSON
*[CBOR]: Concise Binary Object Representation
*[CC0]: Creative Commons Zero
@@ -17,7 +16,6 @@
*[CUDA]: Compute Unified Device Architecture
*[CVE]: Common Vulnerabilities and Exposures
*[DOM]: Document Object Model
*[EDG]: Edison Design Group, maker of a C++ compiler front end
*[EOF]: End of File
*[FAQ]: Frequently Asked Questions
*[GCC]: GNU Compiler Collection
@@ -33,11 +31,9 @@
*[JSONC]: JSON with Comments
*[JWCC]: JSON With Commas and Comments
*[LLDB]: LLVM Debugger
*[LTO]: Link-Time Optimization
*[LTS]: Long-Term Support
*[MinGW]: Minimalist GNU for Windows
*[MIT]: Massachusetts Institute of Technology
*[MPL]: Mozilla Public License
*[MsgPack]: MessagePack
*[MSVC]: Microsoft Visual C++
*[NaN]: Not a Number
@@ -46,7 +42,6 @@
*[NEON]: Arm SIMD instruction set extension
*[NUL]: Null character (U+0000, byte value 0)
*[ODR]: One Definition Rule
*[PCH]: Precompiled Header
*[REUSE]: Software licensing specification by the Free Software Foundation Europe
*[RFC]: Request for Comments
*[RTTI]: Runtime Type Information
@@ -65,4 +60,3 @@
*[UDLs]: User-defined literals
*[URL]: Uniform Resource Locator
*[UTF]: Unicode Transformation Format
*[XOR]: Exclusive or
-3
View File
@@ -104,8 +104,6 @@ nav:
- 'v2.0.0': home/releases/v2.0.0.md
- 'v1.1.0': home/releases/v1.1.0.md
- 'v1.0.0': home/releases/v1.0.0.md
- Blog:
- 'How 3.13.0 got faster': home/blog/how_3_13_0_got_faster.md
- home/design_goals.md
- home/architecture.md
- home/customers.md
@@ -611,7 +609,6 @@ plugins:
Home:
- index.md
- home/*.md
- home/blog/*.md
Features:
- features/*.md
- features/binary_formats/*.md
+2 -2
View File
@@ -1,8 +1,8 @@
wheel==0.48.0
mkdocs==1.6.1 # documentation framework
mkdocs-git-revision-date-localized-plugin==1.6.0 # plugin "git-revision-date-localized"
mkdocs-material==9.7.7 # theme for mkdocs
mkdocs-git-revision-date-localized-plugin==1.6.2 # plugin "git-revision-date-localized"
mkdocs-material==9.8.0 # theme for mkdocs
mkdocs-material-extensions==1.3.1 # extensions
mkdocs-minify-plugin==0.8.0 # plugin "minify"
mkdocs-redirects==1.2.3 # plugin "redirects"
File diff suppressed because it is too large. Load diff
@@ -1,183 +0,0 @@
benchmark,unit,3.12.0,3.13.0,speedup
Accept/canada,ns,1.29488e+07,2.3494e+06,5.512
Accept/citm_catalog,ns,6.53091e+06,923408,7.073
Accept/floats,ns,1.15702e+08,2.26771e+07,5.102
Accept/jeopardy,ns,2.20758e+08,5.92935e+07,3.723
Accept/signed_ints,ns,1.17358e+08,2.82947e+07,4.148
Accept/small_signed_ints,ns,5.75113e+07,1.80352e+07,3.189
Accept/twitter,ns,2.51345e+06,483792,5.195
Accept/unsigned_ints,ns,1.16297e+08,2.97181e+07,3.913
BinaryToCbor/1024,ns,298.444,107.095,2.787
BinaryToCbor/128,ns,248.661,116.711,2.131
BinaryToCbor/16,ns,244.687,49.6325,4.930
BinaryToCbor/16384,ns,952.115,413.62,2.302
BinaryToCbor/2048,ns,328.419,125.183,2.624
BinaryToCbor/256,ns,264.678,90.8937,2.912
BinaryToCbor/32,ns,251.632,50.4059,4.992
BinaryToCbor/32768,ns,1541.05,802.721,1.920
BinaryToCbor/4096,ns,406.957,177.412,2.294
BinaryToCbor/512,ns,289.876,102.063,2.840
BinaryToCbor/64,ns,254.928,84.6434,3.012
BinaryToCbor/8,ns,247.618,49.3761,5.015
BinaryToCbor/8192,ns,514.281,256.456,2.005
Copy/canada,ns,3.78116e+06,2.92734e+06,1.292
Copy/citm_catalog,ns,1.7026e+06,1.51108e+06,1.127
Copy/twitter,ns,840201,767400,1.095
CopyAssign/canada,ns,3.86416e+06,2.94449e+06,1.312
CopyAssign/citm_catalog,ns,1.76529e+06,1.58608e+06,1.113
CopyAssign/twitter,ns,884985,790724,1.119
CopyOnly/canada,ns,1.60229e+06,1.57507e+06,1.017
CopyOnly/citm_catalog,ns,786244,817481,0.962
CopyOnly/twitter,ns,423631,420649,1.007
CopyRing/canada,ns,3.86433e+06,2.99657e+06,1.290
CopyRing/citm_catalog,ns,1.84434e+06,1.60579e+06,1.149
CopyRing/twitter,ns,951510,818035,1.163
DestroyOnly/canada,ns,2.22138e+06,1.40157e+06,1.585
DestroyOnly/citm_catalog,ns,926244,711471,1.302
DestroyOnly/twitter,ns,416055,336082,1.238
Diff/canada,ns,3.98055e+07,3.80466e+06,10.462
Diff/citm_catalog,ns,7.1859e+06,1.12351e+06,6.396
Diff/twitter,ns,5.11261e+06,661062,7.734
Dump/canada / -,ns,6.95189e+06,2.33647e+06,2.975
Dump/canada / 4,ns,9.09882e+06,3.10291e+06,2.932
Dump/citm_catalog / -,ns,1.42117e+06,295678,4.806
Dump/citm_catalog / 4,ns,1.98589e+06,422600,4.699
Dump/floats / -,ns,6.4332e+07,2.37747e+07,2.706
Dump/floats / 4,ns,7.25695e+07,2.46207e+07,2.947
Dump/jeopardy / -,ns,2.06771e+08,3.17494e+07,6.513
Dump/jeopardy / 4,ns,2.27967e+08,3.53626e+07,6.447
Dump/signed_ints / -,ns,2.40551e+07,1.0736e+07,2.241
Dump/signed_ints / 4,ns,3.25192e+07,1.1333e+07,2.869
Dump/small_signed_ints / -,ns,1.81398e+07,8.12457e+06,2.233
Dump/small_signed_ints / 4,ns,2.55296e+07,8.80796e+06,2.898
Dump/twitter / -,ns,1.43584e+06,214252,6.702
Dump/twitter / 4,ns,1.63183e+06,253042,6.449
Dump/unsigned_ints / -,ns,2.39512e+07,8.11916e+06,2.950
Dump/unsigned_ints / 4,ns,3.22761e+07,8.58925e+06,3.758
Equal/canada,ns,473767,349284,1.356
Equal/citm_catalog,ns,279548,263329,1.062
Equal/twitter,ns,145555,131450,1.107
Flatten/canada,ns,2.94475e+07,1.11184e+07,2.649
Flatten/citm_catalog,ns,6.7155e+06,3.07325e+06,2.185
Flatten/twitter,ns,3.66077e+06,2.10599e+06,1.738
FlattenOrdered/citm_catalog,ns,2.62026e+08,1.42645e+06,183.691
FlattenOrdered/twitter,ns,5.1275e+07,890275,57.595
FromBinaryBuffer/bjdata / canada,ns,8.81972e+06,4.16727e+06,2.116
FromBinaryBuffer/bjdata / twitter,ns,3.32045e+06,976266,3.401
FromBinaryBuffer/bjdata_optimized / canada,ns,9.2386e+06,2.47996e+06,3.725
FromBinaryBuffer/bjdata_optimized / twitter,ns,3.30526e+06,985625,3.353
FromBinaryBuffer/bson / canada,ns,1.00372e+07,4.31554e+06,2.326
FromBinaryBuffer/bson / citm_catalog,ns,4.07611e+06,1.60647e+06,2.537
FromBinaryBuffer/bson / twitter,ns,3.25635e+06,936933,3.476
FromBinaryBuffer/cbor / canada,ns,8.89562e+06,2.11517e+06,4.206
FromBinaryBuffer/cbor / citm_catalog,ns,3.94234e+06,1.45242e+06,2.714
FromBinaryBuffer/cbor / floats,ns,3.0473e+07,5.47969e+06,5.561
FromBinaryBuffer/cbor / jeopardy,ns,3.73185e+08,1.14934e+08,3.247
FromBinaryBuffer/cbor / signed_ints,ns,3.66673e+07,9.88892e+06,3.708
FromBinaryBuffer/cbor / twitter,ns,3.23196e+06,953415,3.390
FromBinaryBuffer/msgpack / canada,ns,8.85983e+06,2.12215e+06,4.175
FromBinaryBuffer/msgpack / citm_catalog,ns,3.84901e+06,1.4503e+06,2.654
FromBinaryBuffer/msgpack / jeopardy,ns,3.73143e+08,1.11034e+08,3.361
FromBinaryBuffer/msgpack / twitter,ns,3.2397e+06,954811,3.393
FromBinaryBuffer/ubjson / canada,ns,8.84059e+06,4.20402e+06,2.103
FromBinaryBuffer/ubjson / citm_catalog,ns,4.0708e+06,1.78566e+06,2.280
FromBinaryBuffer/ubjson / jeopardy,ns,3.79093e+08,1.17024e+08,3.239
FromBinaryBuffer/ubjson / twitter,ns,3.29948e+06,981057,3.363
FromBinaryBuffer/ubjson_optimized / canada,ns,8.88909e+06,2.42788e+06,3.661
FromBinaryBuffer/ubjson_optimized / twitter,ns,3.29784e+06,974810,3.383
FromBinaryFile/bjdata / twitter,ns,1.09208e+07,1.94678e+06,5.610
FromBinaryFile/bson / twitter,ns,1.07209e+07,1.84971e+06,5.796
FromBinaryFile/cbor / canada,ns,1.49218e+07,4.48832e+06,3.325
FromBinaryFile/cbor / twitter,ns,1.03718e+07,1.57388e+06,6.590
FromBinaryFile/ubjson / canada,ns,1.43414e+07,6.42996e+06,2.230
FromBinaryFile/ubjson / twitter,ns,1.09266e+07,1.97275e+06,5.539
FromBinaryShape/containers / bjdata,ns,1.46977e+07,7.23447e+06,2.032
FromBinaryShape/containers / bson,ns,1.75596e+07,7.88867e+06,2.226
FromBinaryShape/containers / cbor,ns,1.46488e+07,4.15792e+06,3.523
FromBinaryShape/containers / msgpack,ns,1.45853e+07,3.89266e+06,3.747
FromBinaryShape/containers / ubjson,ns,1.49773e+07,7.23987e+06,2.069
FromBinaryShape/containers / ubjson_optimized,ns,1.54989e+07,4.55976e+06,3.399
FromBinaryShape/nested / bjdata,ns,96825.9,38335.1,2.526
FromBinaryShape/nested / bson,ns,101356,42620.2,2.378
FromBinaryShape/nested / cbor,ns,94929.8,35845.6,2.648
FromBinaryShape/nested / msgpack,ns,92610.2,35078.3,2.640
FromBinaryShape/nested / ubjson,ns,96090.6,38285.6,2.510
FromBinaryShape/scalars / bjdata,ns,2.52616e+07,1.15856e+07,2.180
FromBinaryShape/scalars / cbor,ns,2.62118e+07,5.88743e+06,4.452
FromBinaryShape/scalars / msgpack,ns,2.50706e+07,5.65159e+06,4.436
FromBinaryShape/scalars / ubjson,ns,2.53402e+07,1.16191e+07,2.181
FromCborChunkedString/10000 chunks,ns,91845.9,82875.5,1.108
FromMsgpack/canada,ns,1.48853e+07,4.56225e+06,3.263
FromMsgpack/citm_catalog,ns,9.3559e+06,2.26246e+06,4.135
FromMsgpack/floats,ns,6.12575e+07,2.86709e+07,2.137
FromMsgpack/jeopardy,ns,1.16767e+09,1.90153e+08,6.141
FromMsgpack/signed_ints,ns,6.38812e+07,3.28867e+07,1.942
FromMsgpack/small_signed_ints,ns,6.44688e+07,3.44227e+07,1.873
FromMsgpack/twitter,ns,1.02787e+07,1.48541e+06,6.920
FromMsgpack/unsigned_ints,ns,5.7784e+07,2.83078e+07,2.041
"GetArray<std::array<int, 1000>>",ns,2274.63,654.431,3.476
GetArray<std::deque<int>>,ns,8288.3,1175.75,7.049
GetArray<std::set<int>>,ns,60017.4,42504.9,1.412
GetArray<std::vector<int>>,ns,6785.73,681.915,9.951
GetMap/citm_catalog,ns,3.60313e+06,2.48546e+06,1.450
GetVectorDouble/floats,ns,6.83612e+06,656162,10.418
GetVectorInt/signed_ints,ns,8.22365e+06,3.46495e+06,2.373
Iterate/canada,ns,897083,328035,2.735
Iterate/citm_catalog,ns,305421,171245,1.784
Iterate/twitter,ns,89996.6,61975.8,1.452
JsonPointerAt/citm_catalog,ns,1.89898e+06,1.17751e+06,1.613
JsonPointerAt/twitter,ns,817946,611519,1.338
JsonPointerContains/citm_catalog,ns,2.8177e+06,1.26796e+06,2.222
JsonPointerContains/twitter,ns,1.33508e+06,628630,2.124
JsonPointerParse/citm_catalog,ns,5.81355e+06,2.24831e+06,2.586
JsonPointerParse/twitter,ns,2.47971e+06,1.02159e+06,2.427
JsonPointerToString/citm_catalog,ns,6.7858e+06,1.93924e+06,3.499
JsonPointerToString/twitter,ns,2.23096e+06,834416,2.674
ParseFILE/canada,ns,5.41907e+07,1.46942e+07,3.688
ParseFILE/citm_catalog,ns,3.59542e+07,7.58092e+06,4.743
ParseFILE/twitter,ns,1.4087e+07,3.44991e+06,4.083
ParseFile/canada,ns,1.82792e+07,6.46954e+06,2.825
ParseFile/citm_catalog,ns,8.12979e+06,2.52336e+06,3.222
ParseFile/floats,ns,1.31229e+08,4.81407e+07,2.726
ParseFile/jeopardy,ns,3.38017e+08,1.62098e+08,2.085
ParseFile/signed_ints,ns,1.28749e+08,4.62304e+07,2.785
ParseFile/small_signed_ints,ns,6.47398e+07,3.34103e+07,1.938
ParseFile/twitter,ns,3.43041e+06,1.37495e+06,2.495
ParseFile/unsigned_ints,ns,1.24001e+08,4.74365e+07,2.614
ParseIndented/canada / 4,ns,3.4977e+07,5.37149e+06,6.512
ParseIndented/citm_catalog / 4,ns,7.52423e+06,1.81376e+06,4.148
ParseIndented/jeopardy / 4,ns,3.45046e+08,1.33383e+08,2.587
ParseIndented/twitter / 4,ns,3.72283e+06,1.12645e+06,3.305
ParseStreamValues/ndjson,ns,7.15876e+06,3.76965e+06,1.899
ParseStreamValues/numbers,ns,1.92619e+06,383138,5.027
ParseString/canada,ns,1.55213e+07,4.62776e+06,3.354
ParseString/citm_catalog,ns,7.56417e+06,1.77967e+06,4.250
ParseString/floats,ns,1.21779e+08,2.83035e+07,4.303
ParseString/jeopardy,ns,3.16817e+08,1.30897e+08,2.420
ParseString/signed_ints,ns,1.22931e+08,3.19852e+07,3.843
ParseString/small_signed_ints,ns,6.2685e+07,2.49764e+07,2.510
ParseString/twitter,ns,3.2961e+06,1.04867e+06,3.143
ParseString/unsigned_ints,ns,1.21229e+08,3.29241e+07,3.682
ParseStringOrdered/canada,ns,1.5388e+07,4.5275e+06,3.399
ParseStringOrdered/citm_catalog,ns,1.15204e+07,1.68115e+06,6.853
ParseStringOrdered/jeopardy,ns,3.73533e+08,1.13397e+08,3.294
ParseStringOrdered/twitter,ns,4.5979e+06,948606,4.847
Patch/canada,ns,1.03684e+07,3.47719e+06,2.982
Patch/citm_catalog,ns,2.74522e+06,1.74191e+06,1.576
Patch/twitter,ns,1.57928e+06,888657,1.777
SaxParse/canada,ns,1.31023e+07,3.26697e+06,4.011
SaxParse/citm_catalog,ns,6.54642e+06,966806,6.771
SaxParse/twitter,ns,2.53102e+06,483052,5.240
ToCbor/canada,ns,1.41339e+06,556912,2.538
ToCbor/citm_catalog,ns,1.04743e+06,259178,4.041
ToCbor/floats,ns,9.04677e+06,1.90094e+06,4.759
ToCbor/jeopardy,ns,7.39339e+07,2.20678e+07,3.350
ToCbor/signed_ints,ns,1.15333e+07,2.827e+06,4.080
ToCbor/small_signed_ints,ns,1.0394e+07,2.47974e+06,4.192
ToCbor/twitter,ns,658566,143397,4.593
ToCbor/unsigned_ints,ns,8.17966e+06,2.81588e+06,2.905
ToJsonStrings/copy,ns,6.12e+06,5.65303e+06,1.083
ToJsonStrings/move,ns,6.13061e+06,3.13303e+06,1.957
Unflatten/canada,ns,4.25276e+07,1.10995e+07,3.831
Unflatten/citm_catalog,ns,1.01866e+07,3.62185e+06,2.813
Unflatten/twitter,ns,4.74536e+06,2.21103e+06,2.146
1 benchmark unit 3.12.0 3.13.0 speedup
2 Accept/canada ns 1.29488e+07 2.3494e+06 5.512
3 Accept/citm_catalog ns 6.53091e+06 923408 7.073
4 Accept/floats ns 1.15702e+08 2.26771e+07 5.102
5 Accept/jeopardy ns 2.20758e+08 5.92935e+07 3.723
6 Accept/signed_ints ns 1.17358e+08 2.82947e+07 4.148
7 Accept/small_signed_ints ns 5.75113e+07 1.80352e+07 3.189
8 Accept/twitter ns 2.51345e+06 483792 5.195
9 Accept/unsigned_ints ns 1.16297e+08 2.97181e+07 3.913
10 BinaryToCbor/1024 ns 298.444 107.095 2.787
11 BinaryToCbor/128 ns 248.661 116.711 2.131
12 BinaryToCbor/16 ns 244.687 49.6325 4.930
13 BinaryToCbor/16384 ns 952.115 413.62 2.302
14 BinaryToCbor/2048 ns 328.419 125.183 2.624
15 BinaryToCbor/256 ns 264.678 90.8937 2.912
16 BinaryToCbor/32 ns 251.632 50.4059 4.992
17 BinaryToCbor/32768 ns 1541.05 802.721 1.920
18 BinaryToCbor/4096 ns 406.957 177.412 2.294
19 BinaryToCbor/512 ns 289.876 102.063 2.840
20 BinaryToCbor/64 ns 254.928 84.6434 3.012
21 BinaryToCbor/8 ns 247.618 49.3761 5.015
22 BinaryToCbor/8192 ns 514.281 256.456 2.005
23 Copy/canada ns 3.78116e+06 2.92734e+06 1.292
24 Copy/citm_catalog ns 1.7026e+06 1.51108e+06 1.127
25 Copy/twitter ns 840201 767400 1.095
26 CopyAssign/canada ns 3.86416e+06 2.94449e+06 1.312
27 CopyAssign/citm_catalog ns 1.76529e+06 1.58608e+06 1.113
28 CopyAssign/twitter ns 884985 790724 1.119
29 CopyOnly/canada ns 1.60229e+06 1.57507e+06 1.017
30 CopyOnly/citm_catalog ns 786244 817481 0.962
31 CopyOnly/twitter ns 423631 420649 1.007
32 CopyRing/canada ns 3.86433e+06 2.99657e+06 1.290
33 CopyRing/citm_catalog ns 1.84434e+06 1.60579e+06 1.149
34 CopyRing/twitter ns 951510 818035 1.163
35 DestroyOnly/canada ns 2.22138e+06 1.40157e+06 1.585
36 DestroyOnly/citm_catalog ns 926244 711471 1.302
37 DestroyOnly/twitter ns 416055 336082 1.238
38 Diff/canada ns 3.98055e+07 3.80466e+06 10.462
39 Diff/citm_catalog ns 7.1859e+06 1.12351e+06 6.396
40 Diff/twitter ns 5.11261e+06 661062 7.734
41 Dump/canada / - ns 6.95189e+06 2.33647e+06 2.975
42 Dump/canada / 4 ns 9.09882e+06 3.10291e+06 2.932
43 Dump/citm_catalog / - ns 1.42117e+06 295678 4.806
44 Dump/citm_catalog / 4 ns 1.98589e+06 422600 4.699
45 Dump/floats / - ns 6.4332e+07 2.37747e+07 2.706
46 Dump/floats / 4 ns 7.25695e+07 2.46207e+07 2.947
47 Dump/jeopardy / - ns 2.06771e+08 3.17494e+07 6.513
48 Dump/jeopardy / 4 ns 2.27967e+08 3.53626e+07 6.447
49 Dump/signed_ints / - ns 2.40551e+07 1.0736e+07 2.241
50 Dump/signed_ints / 4 ns 3.25192e+07 1.1333e+07 2.869
51 Dump/small_signed_ints / - ns 1.81398e+07 8.12457e+06 2.233
52 Dump/small_signed_ints / 4 ns 2.55296e+07 8.80796e+06 2.898
53 Dump/twitter / - ns 1.43584e+06 214252 6.702
54 Dump/twitter / 4 ns 1.63183e+06 253042 6.449
55 Dump/unsigned_ints / - ns 2.39512e+07 8.11916e+06 2.950
56 Dump/unsigned_ints / 4 ns 3.22761e+07 8.58925e+06 3.758
57 Equal/canada ns 473767 349284 1.356
58 Equal/citm_catalog ns 279548 263329 1.062
59 Equal/twitter ns 145555 131450 1.107
60 Flatten/canada ns 2.94475e+07 1.11184e+07 2.649
61 Flatten/citm_catalog ns 6.7155e+06 3.07325e+06 2.185
62 Flatten/twitter ns 3.66077e+06 2.10599e+06 1.738
63 FlattenOrdered/citm_catalog ns 2.62026e+08 1.42645e+06 183.691
64 FlattenOrdered/twitter ns 5.1275e+07 890275 57.595
65 FromBinaryBuffer/bjdata / canada ns 8.81972e+06 4.16727e+06 2.116
66 FromBinaryBuffer/bjdata / twitter ns 3.32045e+06 976266 3.401
67 FromBinaryBuffer/bjdata_optimized / canada ns 9.2386e+06 2.47996e+06 3.725
68 FromBinaryBuffer/bjdata_optimized / twitter ns 3.30526e+06 985625 3.353
69 FromBinaryBuffer/bson / canada ns 1.00372e+07 4.31554e+06 2.326
70 FromBinaryBuffer/bson / citm_catalog ns 4.07611e+06 1.60647e+06 2.537
71 FromBinaryBuffer/bson / twitter ns 3.25635e+06 936933 3.476
72 FromBinaryBuffer/cbor / canada ns 8.89562e+06 2.11517e+06 4.206
73 FromBinaryBuffer/cbor / citm_catalog ns 3.94234e+06 1.45242e+06 2.714
74 FromBinaryBuffer/cbor / floats ns 3.0473e+07 5.47969e+06 5.561
75 FromBinaryBuffer/cbor / jeopardy ns 3.73185e+08 1.14934e+08 3.247
76 FromBinaryBuffer/cbor / signed_ints ns 3.66673e+07 9.88892e+06 3.708
77 FromBinaryBuffer/cbor / twitter ns 3.23196e+06 953415 3.390
78 FromBinaryBuffer/msgpack / canada ns 8.85983e+06 2.12215e+06 4.175
79 FromBinaryBuffer/msgpack / citm_catalog ns 3.84901e+06 1.4503e+06 2.654
80 FromBinaryBuffer/msgpack / jeopardy ns 3.73143e+08 1.11034e+08 3.361
81 FromBinaryBuffer/msgpack / twitter ns 3.2397e+06 954811 3.393
82 FromBinaryBuffer/ubjson / canada ns 8.84059e+06 4.20402e+06 2.103
83 FromBinaryBuffer/ubjson / citm_catalog ns 4.0708e+06 1.78566e+06 2.280
84 FromBinaryBuffer/ubjson / jeopardy ns 3.79093e+08 1.17024e+08 3.239
85 FromBinaryBuffer/ubjson / twitter ns 3.29948e+06 981057 3.363
86 FromBinaryBuffer/ubjson_optimized / canada ns 8.88909e+06 2.42788e+06 3.661
87 FromBinaryBuffer/ubjson_optimized / twitter ns 3.29784e+06 974810 3.383
88 FromBinaryFile/bjdata / twitter ns 1.09208e+07 1.94678e+06 5.610
89 FromBinaryFile/bson / twitter ns 1.07209e+07 1.84971e+06 5.796
90 FromBinaryFile/cbor / canada ns 1.49218e+07 4.48832e+06 3.325
91 FromBinaryFile/cbor / twitter ns 1.03718e+07 1.57388e+06 6.590
92 FromBinaryFile/ubjson / canada ns 1.43414e+07 6.42996e+06 2.230
93 FromBinaryFile/ubjson / twitter ns 1.09266e+07 1.97275e+06 5.539
94 FromBinaryShape/containers / bjdata ns 1.46977e+07 7.23447e+06 2.032
95 FromBinaryShape/containers / bson ns 1.75596e+07 7.88867e+06 2.226
96 FromBinaryShape/containers / cbor ns 1.46488e+07 4.15792e+06 3.523
97 FromBinaryShape/containers / msgpack ns 1.45853e+07 3.89266e+06 3.747
98 FromBinaryShape/containers / ubjson ns 1.49773e+07 7.23987e+06 2.069
99 FromBinaryShape/containers / ubjson_optimized ns 1.54989e+07 4.55976e+06 3.399
100 FromBinaryShape/nested / bjdata ns 96825.9 38335.1 2.526
101 FromBinaryShape/nested / bson ns 101356 42620.2 2.378
102 FromBinaryShape/nested / cbor ns 94929.8 35845.6 2.648
103 FromBinaryShape/nested / msgpack ns 92610.2 35078.3 2.640
104 FromBinaryShape/nested / ubjson ns 96090.6 38285.6 2.510
105 FromBinaryShape/scalars / bjdata ns 2.52616e+07 1.15856e+07 2.180
106 FromBinaryShape/scalars / cbor ns 2.62118e+07 5.88743e+06 4.452
107 FromBinaryShape/scalars / msgpack ns 2.50706e+07 5.65159e+06 4.436
108 FromBinaryShape/scalars / ubjson ns 2.53402e+07 1.16191e+07 2.181
109 FromCborChunkedString/10000 chunks ns 91845.9 82875.5 1.108
110 FromMsgpack/canada ns 1.48853e+07 4.56225e+06 3.263
111 FromMsgpack/citm_catalog ns 9.3559e+06 2.26246e+06 4.135
112 FromMsgpack/floats ns 6.12575e+07 2.86709e+07 2.137
113 FromMsgpack/jeopardy ns 1.16767e+09 1.90153e+08 6.141
114 FromMsgpack/signed_ints ns 6.38812e+07 3.28867e+07 1.942
115 FromMsgpack/small_signed_ints ns 6.44688e+07 3.44227e+07 1.873
116 FromMsgpack/twitter ns 1.02787e+07 1.48541e+06 6.920
117 FromMsgpack/unsigned_ints ns 5.7784e+07 2.83078e+07 2.041
118 GetArray<std::array<int, 1000>> ns 2274.63 654.431 3.476
119 GetArray<std::deque<int>> ns 8288.3 1175.75 7.049
120 GetArray<std::set<int>> ns 60017.4 42504.9 1.412
121 GetArray<std::vector<int>> ns 6785.73 681.915 9.951
122 GetMap/citm_catalog ns 3.60313e+06 2.48546e+06 1.450
123 GetVectorDouble/floats ns 6.83612e+06 656162 10.418
124 GetVectorInt/signed_ints ns 8.22365e+06 3.46495e+06 2.373
125 Iterate/canada ns 897083 328035 2.735
126 Iterate/citm_catalog ns 305421 171245 1.784
127 Iterate/twitter ns 89996.6 61975.8 1.452
128 JsonPointerAt/citm_catalog ns 1.89898e+06 1.17751e+06 1.613
129 JsonPointerAt/twitter ns 817946 611519 1.338
130 JsonPointerContains/citm_catalog ns 2.8177e+06 1.26796e+06 2.222
131 JsonPointerContains/twitter ns 1.33508e+06 628630 2.124
132 JsonPointerParse/citm_catalog ns 5.81355e+06 2.24831e+06 2.586
133 JsonPointerParse/twitter ns 2.47971e+06 1.02159e+06 2.427
134 JsonPointerToString/citm_catalog ns 6.7858e+06 1.93924e+06 3.499
135 JsonPointerToString/twitter ns 2.23096e+06 834416 2.674
136 ParseFILE/canada ns 5.41907e+07 1.46942e+07 3.688
137 ParseFILE/citm_catalog ns 3.59542e+07 7.58092e+06 4.743
138 ParseFILE/twitter ns 1.4087e+07 3.44991e+06 4.083
139 ParseFile/canada ns 1.82792e+07 6.46954e+06 2.825
140 ParseFile/citm_catalog ns 8.12979e+06 2.52336e+06 3.222
141 ParseFile/floats ns 1.31229e+08 4.81407e+07 2.726
142 ParseFile/jeopardy ns 3.38017e+08 1.62098e+08 2.085
143 ParseFile/signed_ints ns 1.28749e+08 4.62304e+07 2.785
144 ParseFile/small_signed_ints ns 6.47398e+07 3.34103e+07 1.938
145 ParseFile/twitter ns 3.43041e+06 1.37495e+06 2.495
146 ParseFile/unsigned_ints ns 1.24001e+08 4.74365e+07 2.614
147 ParseIndented/canada / 4 ns 3.4977e+07 5.37149e+06 6.512
148 ParseIndented/citm_catalog / 4 ns 7.52423e+06 1.81376e+06 4.148
149 ParseIndented/jeopardy / 4 ns 3.45046e+08 1.33383e+08 2.587
150 ParseIndented/twitter / 4 ns 3.72283e+06 1.12645e+06 3.305
151 ParseStreamValues/ndjson ns 7.15876e+06 3.76965e+06 1.899
152 ParseStreamValues/numbers ns 1.92619e+06 383138 5.027
153 ParseString/canada ns 1.55213e+07 4.62776e+06 3.354
154 ParseString/citm_catalog ns 7.56417e+06 1.77967e+06 4.250
155 ParseString/floats ns 1.21779e+08 2.83035e+07 4.303
156 ParseString/jeopardy ns 3.16817e+08 1.30897e+08 2.420
157 ParseString/signed_ints ns 1.22931e+08 3.19852e+07 3.843
158 ParseString/small_signed_ints ns 6.2685e+07 2.49764e+07 2.510
159 ParseString/twitter ns 3.2961e+06 1.04867e+06 3.143
160 ParseString/unsigned_ints ns 1.21229e+08 3.29241e+07 3.682
161 ParseStringOrdered/canada ns 1.5388e+07 4.5275e+06 3.399
162 ParseStringOrdered/citm_catalog ns 1.15204e+07 1.68115e+06 6.853
163 ParseStringOrdered/jeopardy ns 3.73533e+08 1.13397e+08 3.294
164 ParseStringOrdered/twitter ns 4.5979e+06 948606 4.847
165 Patch/canada ns 1.03684e+07 3.47719e+06 2.982
166 Patch/citm_catalog ns 2.74522e+06 1.74191e+06 1.576
167 Patch/twitter ns 1.57928e+06 888657 1.777
168 SaxParse/canada ns 1.31023e+07 3.26697e+06 4.011
169 SaxParse/citm_catalog ns 6.54642e+06 966806 6.771
170 SaxParse/twitter ns 2.53102e+06 483052 5.240
171 ToCbor/canada ns 1.41339e+06 556912 2.538
172 ToCbor/citm_catalog ns 1.04743e+06 259178 4.041
173 ToCbor/floats ns 9.04677e+06 1.90094e+06 4.759
174 ToCbor/jeopardy ns 7.39339e+07 2.20678e+07 3.350
175 ToCbor/signed_ints ns 1.15333e+07 2.827e+06 4.080
176 ToCbor/small_signed_ints ns 1.0394e+07 2.47974e+06 4.192
177 ToCbor/twitter ns 658566 143397 4.593
178 ToCbor/unsigned_ints ns 8.17966e+06 2.81588e+06 2.905
179 ToJsonStrings/copy ns 6.12e+06 5.65303e+06 1.083
180 ToJsonStrings/move ns 6.13061e+06 3.13303e+06 1.957
181 Unflatten/canada ns 4.25276e+07 1.10995e+07 3.831
182 Unflatten/citm_catalog ns 1.01866e+07 3.62185e+06 2.813
183 Unflatten/twitter ns 4.74536e+06 2.21103e+06 2.146
@@ -1,354 +0,0 @@
index,commit,date,pr,subject,parse_twitter,parse_citm,parse_canada,parse_citm_compact,parse_twitter_ifstream,accept_twitter,dump_twitter,dump_citm,dump_canada,dump4_citm,from_cbor_twitter,to_cbor_twitter,copy_destroy_citm,equal_citm,view_parse_twitter,view_parse_citm,view_parse_canada
0,55f93686c0,2025-04-11,,Merge branch 'release/3.12.0',3571.487,8219.609,17049.073,4366.792,3846.006,2394.213,1441.213,1375.446,7510.989,1917.809,3463.281,695.524,1643.327,1956.891,,,
1,1705bfe914,2025-04-11,4727,:bookmark: set version to 3.12.0 (#4727),3589.331,8245.422,17079.250,4422.711,3894.787,2397.597,1440.546,1377.745,7514.698,1922.371,3498.997,695.559,1655.240,1967.301,,,
2,4cca3b9cb2,2025-04-13,4738,Fix warning and add emscripten CI step (#4738),3559.657,8195.105,17066.291,4373.011,3794.269,2388.900,1419.182,1355.724,7420.703,1912.038,3468.667,664.214,1631.610,1939.475,,,
3,96c1b52f1c,2025-04-15,4742,Fix conversion to std::optional (#4742),3573.838,8157.276,16993.208,4383.656,3858.927,2395.092,1438.169,1372.208,7497.776,1925.481,3482.185,667.895,1633.619,1946.687,,,
4,88c92e605c,2025-04-16,4744,Fix compilation failure and warnings with NVHPC (#4744),3563.149,8039.911,16922.739,4381.927,3768.560,2385.086,1407.564,1345.578,7370.063,1897.474,3462.010,662.955,1623.286,1925.804,,,
5,c67d538274,2025-04-17,4749,Fix C4702 warning and extend MSVC CI job (#4749),3585.422,8251.057,17050.448,4400.542,3896.586,2390.655,1440.391,1371.722,7453.474,1921.277,3478.523,667.911,1636.206,1939.531,,,
6,756ca22ec5,2025-04-23,4736,Provide fallback for missing `char8_t` support (#4736),3559.146,8139.703,17085.114,4387.658,3856.745,2392.849,1424.997,1370.599,7477.537,1907.661,3484.427,665.541,1634.156,1957.401,,,
7,6b9199382b,2025-04-27,4763,Add missing header (#4763),3541.323,8077.761,17011.636,4359.183,3842.380,2396.686,1421.116,1363.737,7431.375,1902.909,3474.250,664.442,1625.644,1934.732,,,
8,3b02afb9d9,2025-04-28,4760,Specialize char_traits for std::byte to fix from_msgpack (fixes #4756) (#4760),3583.070,8198.146,17134.698,4381.743,3899.872,2409.185,1440.233,1380.810,7504.838,1921.781,3500.125,666.078,1657.207,1966.036,,,
9,eef76c200e,2025-04-28,4764,Make library work with C++20 modules (#4764),3528.529,8080.458,16936.656,4330.570,3764.287,2363.848,1407.851,1358.079,7356.239,1897.423,3455.287,665.194,1632.255,1937.675,,,
10,dff2b4756c,2025-04-29,4765,fix: BJData size calculation overflow (#4765),3553.706,8141.375,17047.511,4360.144,3797.070,2389.756,1417.737,1364.718,7454.313,1921.962,3479.878,666.456,1644.760,1944.696,,,
11,9110918cf8,2025-05-04,4748,Fix typos (#4748),3563.682,8176.427,17239.354,4398.055,3891.669,2399.782,1441.669,1387.133,7516.073,1925.323,3483.271,669.348,1647.760,1957.747,,,
12,46e7cd3dc2,2025-05-16,4775,Replace deprecated std::is_trivial in C++26 (#4775),3565.242,8195.396,17135.646,4373.479,3851.604,2392.258,1418.425,1370.958,7464.854,1909.844,3485.046,665.606,1643.155,1952.329,,,
13,828c891427,2025-05-16,4786,Extend type_name() to invalid type (#4786),3549.573,8103.761,17066.198,4359.911,3804.849,2389.121,1428.584,1366.405,7424.838,1914.434,3452.497,667.452,1632.750,1928.324,,,
14,4b17f90f65,2025-05-22,4609,Add `ignore_trailing_commas` option (#4609),3544.662,8132.052,16997.375,4344.592,3825.765,2382.755,1408.435,1367.468,7460.448,1924.522,3434.062,733.089,1631.356,1891.572,,,
15,b19f058465,2025-06-01,4802,Encode infinity and NaN as float for MsgPack and CBOR (#4802),3550.020,8126.438,17350.885,4327.596,3825.419,2389.356,1409.422,1376.649,7363.802,1921.226,3441.081,683.190,1624.144,1886.388,,,
16,cf16c5ab9f,2025-06-02,4805,Use binary_t::value_type (#4805),3551.735,8143.521,17153.291,4309.477,3829.229,2387.640,1428.550,1385.585,7415.271,1932.347,3425.838,657.735,1631.586,1888.954,,,
17,d70e46bc65,2025-06-25,4830,:bug: add missing header to input_adapters.hpp (#4830),3546.448,8157.469,17062.364,4335.300,3805.221,2382.796,1422.863,1382.581,7411.401,1928.676,3433.190,691.842,1632.972,1892.453,,,
18,30d27df61c,2025-07-31,4871,Fix CI (#4871),3570.015,8150.859,17070.625,4330.078,3806.505,2400.329,1434.947,1381.065,7425.718,1931.556,3429.632,656.545,1633.515,1892.916,,,
19,efcf9efb4f,2025-08-02,4873,Fixes #4854 Explicitly handle nullptr in sax_parse (#4873),3520.381,8050.719,16883.042,4331.820,3861.906,2368.069,1408.435,1375.954,7363.651,1898.466,3432.992,653.988,1634.141,1894.948,,,
20,4106af8d92,2025-08-20,4896,":rotating_light: suppress cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator (#4896)",3540.599,8175.265,17010.438,4345.182,3866.833,2393.935,1435.100,1389.496,7453.724,1945.791,3433.169,657.446,1638.434,1900.360,,,
21,a63795caf1,2025-10-22,4791,:rotating_light: avoid deprecation warning (#4791),3550.057,8174.646,16983.177,4363.521,3888.336,2393.305,1423.434,1376.334,7469.407,1936.013,3447.279,666.706,1645.354,1903.707,,,
22,1cc56b2dcd,2025-10-23,4957,Address CWG issue 2521 (#4957),3557.396,8119.651,17072.730,4351.881,3834.739,2386.097,1442.100,1393.245,7474.463,1932.315,3446.883,660.187,1638.983,1896.000,,,
23,54be9b04f0,2025-10-23,4960,:page_facing_up: update REUSE (#4960),3554.625,8098.287,17115.219,4324.578,3809.950,2390.791,1424.488,1376.715,7422.828,1913.208,3424.693,659.030,1623.405,1892.756,,,
24,29913ca760,2025-10-25,4963,Add char8_t* overload for _json and _json_pointer (#4963),3544.899,8169.203,17007.844,4353.594,3797.630,2392.108,1423.032,1375.216,7349.787,1909.897,3428.771,655.625,1635.273,1891.018,,,
25,515d994acb,2026-01-01,5044,:page_facing_up: adjust year (#5044),3524.610,8059.521,16949.416,4313.508,3773.750,2364.742,1410.427,1372.988,7382.438,1915.502,3403.159,643.968,1618.972,1884.213,,,
26,8f75700141,2026-01-11,4958,support types convertible to string_view as JSON keys (#4958),3546.757,8142.599,17103.386,4327.739,3825.990,2388.540,1420.515,1379.309,7413.062,1924.540,3433.677,658.266,1628.079,1890.759,,,
27,457bc283ff,2026-01-12,5039,fix(cbor): reject overflowing negative integers (#5039),3508.883,8077.291,16930.011,4305.982,3785.698,2378.693,1425.526,1366.111,7407.042,1929.142,3478.909,657.722,1636.304,1944.681,,,
28,e3014f162a,2026-01-13,5052,Fix conversion to std::optional (#5052),3547.995,8140.052,17010.031,4321.914,3797.807,2385.856,1430.414,1386.202,7407.260,1930.403,3462.213,657.829,1629.579,1932.066,,,
29,5ed07097fa,2026-01-13,5050,Fix -Wtautological-constant-out-of-range-compare in serializer (#5050),3544.136,8180.208,17033.209,4339.591,3799.779,2391.940,1427.870,1387.871,7368.765,1922.321,3454.938,659.367,1630.707,1959.722,,,
30,25f48639c7,2026-01-23,5016,Reference tuple from json (#5016),3563.180,8209.037,17030.969,4388.675,3895.086,2392.088,1430.666,1393.853,7528.567,1934.347,3481.351,677.234,1645.418,1957.591,,,
31,f8eee1bb79,2026-02-07,5071,Annotate unreachable comment-scanner switch paths to satisfy C26819 (#5071),3508.000,8128.750,16958.959,4315.235,3797.237,2371.963,1425.146,1374.867,7453.381,1930.211,3456.508,658.568,1629.188,1909.736,,,
32,fd17b0889e,2026-05-08,5139,Remove nullptr safety check from sax_parse functions (#5139),3544.101,8033.021,16963.292,4334.102,3800.736,2382.583,1419.050,1361.745,7357.073,1907.153,3429.315,657.041,1618.815,1937.829,,,
33,62f3b41b30,2026-05-08,5090,fix: treat single-element brace-init as copy/move instead of wrapping in array (#5074) (#5090),3550.323,8168.713,17060.031,4349.417,3794.110,2380.583,1416.822,1361.182,7369.651,1897.717,3466.731,659.297,1631.463,1941.905,,,
34,4fad446897,2026-05-10,5162,docs: add IDs to @requirement tags to fix Doxygen autolinking (#5162),3545.440,8031.891,17069.448,4324.698,3802.862,2383.513,1422.768,1384.602,7325.776,1917.606,3469.787,659.011,1631.296,1940.370,,,
35,a0a4e7cc0b,2026-05-13,5152,Add front methods to json_pointers (implements #4889) (#5152),3582.898,8215.010,17034.448,4345.515,3891.513,2396.572,1432.733,1395.714,7554.119,1934.008,3484.859,659.298,1642.314,1957.356,,,
36,93e49decbd,2026-05-14,5167,Fix incomplete-type error in set_parents with ordered_json (#5167),3555.224,8147.771,17017.073,4320.846,3831.318,2386.750,1435.840,1385.578,7436.864,1927.483,3466.508,658.409,1632.724,1939.528,,,
37,7192763f15,2026-05-14,5163,Fix compile error when using nlohmann ordered_map with WITH_DEFAULT macros (#5163),3520.675,8039.145,16892.291,4303.448,3769.198,2363.337,1410.030,1364.679,7380.797,1913.285,3437.278,660.130,1630.738,1943.235,,,
38,5a05627b1f,2026-05-14,5169,:rotating_light: fix warning (#5169),3600.555,8160.854,16979.031,4324.070,3887.823,2389.157,1430.983,1387.106,7509.984,1912.601,3473.713,663.279,1652.982,1958.774,,,
39,bb5404bb86,2026-05-15,5164,Fix GCC C++20 modules compilation #5103 (#5164),3543.823,8120.266,17015.395,4349.300,3794.880,2364.178,1414.408,1374.548,7484.218,1920.495,3444.266,699.326,1626.241,1954.688,,,
40,b1bb9fce0c,2026-05-15,3929,Fix for printing long doubles bug in dump_float (#3929),3549.378,8089.891,16934.927,4313.310,3824.802,2386.958,1412.164,1385.425,7417.869,1930.513,3461.151,651.557,1618.735,1944.450,,,
41,cba5dc0ed8,2026-05-16,4563,New macros for the named JSON convertor generation (#4563),3544.657,8168.182,16990.886,4327.688,3806.963,2370.975,1421.629,1390.206,7454.151,1919.284,3452.456,677.413,1623.622,1941.921,,,
42,47202c804a,2026-05-18,5171,Add missing overload to ordered_map::find (#5171),3527.542,8168.312,17141.989,4409.456,3887.378,2397.007,1428.765,1387.033,7495.604,1935.710,3485.088,660.155,1648.977,1951.430,,,
43,58cfecf7f7,2026-05-18,5151,Serialize enum (#5151),3521.302,8100.104,16805.489,4288.463,3763.971,2381.494,1408.713,1383.059,7328.261,1915.202,3440.372,648.726,1617.661,1922.608,,,
44,584e6b1cfb,2026-05-22,5187,Fix: update() parent pointers not updated after recursive merge with JSON_DIAGNOSTICS (#5187),3550.639,8083.463,17055.198,4326.833,3804.257,2381.519,1432.039,1381.986,7377.844,1915.159,3460.750,656.873,1631.527,1940.953,,,
45,02dfbea39d,2026-06-17,5209,added explicit instantiations of 'has_from_json' and 'has_to_json' for std_fs::path (#5209),3552.209,8215.474,17167.760,4338.404,3845.144,2398.026,1425.012,1387.629,7458.614,1931.388,3475.343,658.183,1644.329,1958.324,,,
46,fc1df0b7db,2026-06-23,5172,:recycle: remove unnecessary if (#5172),3562.088,8175.531,17044.042,4336.583,3863.651,2404.695,1425.872,1389.434,7523.855,1914.128,3481.000,653.259,1639.515,1957.649,,,
47,c5b2b26fdc,2026-06-29,5217,:memo: fix docs (#5217),3526.825,8052.307,17000.011,4343.963,3793.412,2388.194,1416.706,1374.177,7361.646,1904.008,3463.919,658.322,1627.765,1921.887,,,
48,b7566c6293,2026-06-30,5161,Harden JSON_HAS_RANGES detection for incomplete C++20 ranges implementations (#5161),3538.995,8071.787,17120.751,4318.797,3772.445,2384.008,1421.440,1385.239,7419.292,1898.929,3431.466,647.948,1602.258,1928.644,,,
49,adf78d3a76,2026-06-30,5215,Minor: unique_ptr template resolution workaround for MSVC (#5215),3550.380,8138.026,17036.802,4366.062,3842.430,2389.536,1426.658,1385.609,7428.787,1915.233,3467.188,658.332,1636.158,1942.556,,,
50,272411c5e6,2026-06-30,5218,Overwork project infrastructure (#5218),3547.487,8087.250,16962.198,4341.969,3793.831,2387.509,1420.888,1381.072,7450.078,1930.003,3466.193,659.676,1631.329,1943.043,,,
51,730b57775d,2026-07-01,5222,:bug: avoid assertion in patch (#5222),3539.912,8169.771,17027.229,4345.151,3790.753,2376.552,1421.263,1386.717,7399.985,1923.237,3455.722,653.609,1630.914,1934.028,,,
52,ca49ab6123,2026-07-02,5223,Extend value to arrays when using JSON pointers (#5223),3550.341,8113.787,16951.313,4346.805,3793.097,2391.224,1409.695,1380.075,7374.073,1926.401,3458.438,659.382,1629.387,1941.306,,,
53,8d7e0046f4,2026-07-02,5224,Add std::format and fmt support (#5224),3546.935,8170.406,16968.927,4346.906,3814.956,2387.612,1424.861,1386.542,7350.765,1900.376,3461.177,662.476,1633.858,1930.434,,,
54,31dd15b258,2026-07-02,5221,Fix ambiguous static_cast (#5221),3551.945,8213.000,17131.271,4373.620,3845.763,2393.074,1438.633,1385.769,7471.146,1927.804,3486.568,662.015,1631.810,1958.901,,,
55,eed1587000,2026-07-05,5234,Reconstruct lexer diagnostics lazily for seekable input (#120) (#5234),3145.909,5311.094,15381.843,4292.961,3851.260,1966.833,1422.598,1365.461,7443.276,1920.467,3467.060,702.832,1637.587,1905.758,,,
56,83c87cb9e0,2026-07-05,5233,Read binary strings/blobs in bulk chunks with a memcpy fast path (#5233),3141.867,5259.485,15454.959,4326.664,3797.198,1987.623,1406.492,1372.765,7424.729,1899.726,2363.895,667.502,1630.097,1888.392,,,
57,acf076a677,2026-07-06,5238,Fix ADL leak of nlohmann::detail through basic_json's default base class (#5238),3152.153,5277.073,15291.407,4338.828,3839.331,1995.524,1429.960,1365.917,7456.776,1907.928,2398.016,670.257,1627.590,1897.997,,,
58,c05c5e229b,2026-07-07,5241,Add missing copyright notices to SBOM (#5241),3147.485,5268.865,15319.584,4321.823,3796.972,1981.167,1432.689,1371.264,7465.416,1918.083,2388.154,667.119,1630.745,1891.583,,,
59,366f3d26e5,2026-07-08,5235,Replace snprintf with a branch-free writer for \uXXXX escapes (#5235),3127.641,5272.302,15425.239,4340.459,3850.357,1997.957,1459.603,1356.461,7509.703,1899.916,2366.966,668.383,1624.981,1889.145,,,
60,f8e99e856c,2026-07-09,5248,Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907) (#5248),3132.099,5226.375,15164.510,4301.901,3769.651,1967.647,1456.759,1365.810,7530.724,1908.635,2381.610,683.815,1616.699,1879.795,,,
61,855f511db4,2026-07-09,5250,Fix stale Clang -Weverything suppression comments; drop -Wno-missing-noreturn (#5250),3126.792,5208.338,15352.520,4293.596,3800.544,1969.497,1458.601,1329.851,7372.849,1876.404,2368.894,662.173,1603.881,1874.673,,,
62,d0a43141ea,2026-07-09,5253,Fix #3868: Remove operator!= to enable P2468R2 rewritten candidate synthesis (#5253),3165.182,5270.458,15479.031,4302.729,3845.646,1989.231,1474.135,1343.312,7443.282,1887.909,2392.523,670.395,1634.871,1894.474,,,
63,b630f5e9c7,2026-07-10,5260,Fix container input_adapter SFINAE for lvalue-only ADL begin/end (#5260),3128.117,5263.807,15375.677,4330.544,3819.953,1982.196,1454.088,1339.062,7364.683,1877.699,2361.482,666.486,1616.514,1920.626,,,
64,c60217e801,2026-07-11,5205,fix: support constructing json from C++20 range views (#4916) (#5205),3117.539,5206.552,15308.166,4320.513,3798.713,1983.458,1447.072,1350.950,7357.213,1875.632,2340.731,662.905,1633.357,1934.261,,,
65,fe2bcc080f,2026-07-11,5266,Custom BinaryType direct assignment (#5266),3174.528,5284.562,15383.645,4328.120,3895.086,1996.913,1478.427,1355.569,7512.115,1899.236,2398.490,672.118,1642.910,1967.660,,,
66,ca76c37650,2026-07-11,5265,Add iterator+sentinel tests and docs for binary deserializers (#5265),3134.265,5218.021,15352.521,4306.284,3791.612,1967.824,1451.953,1358.685,7508.828,1891.697,2377.848,665.474,1631.495,1934.907,,,
67,c197feff81,2026-07-12,5268,Extend memcpy fast path to sized sentinels (e.g. std::counted_iterator) (#5268),3116.271,5207.146,15415.771,4272.443,3815.851,1984.966,1451.103,1341.093,7328.037,1865.385,2383.169,664.494,1617.967,1915.428,,,
68,1c5a953de5,2026-07-19,5276,reject unpaired UTF-16 surrogates in wide-string input (#5276),3155.360,5299.631,15419.812,4302.089,3853.104,1987.259,1468.653,1349.665,7549.432,1911.365,2457.555,680.311,1653.282,1955.673,,,
69,3565f40229,2026-07-20,5284,reject negative UBJSON/BJData string length (#5284),3170.456,5301.698,15404.416,4351.226,3893.594,1997.034,1470.907,1358.245,7491.480,1909.601,2401.384,671.260,1639.865,1963.899,,,
70,9a3ebb9456,2026-07-23,5287,validate BSON document size against the bytes read (#5287),3157.646,5264.062,15305.271,4338.672,3839.643,1987.196,1461.356,1351.630,7444.791,1890.626,2398.503,665.262,1655.798,1930.268,,,
71,8ec98e2c9e,2026-07-27,5313,adding cleanups to bson writer (#5313),3150.448,5268.948,15445.927,4308.612,3805.005,1989.643,1466.348,1349.591,7326.453,1895.842,2393.278,708.164,1644.025,1946.652,,,
72,2e23687092,2026-07-28,5314,to_bson() silently emits corrupt documents when a length exceeds INT32_MAX (#5314),3146.534,5254.547,15445.250,4304.008,3798.620,1986.260,1459.735,1345.534,7517.651,1903.996,2395.155,674.344,1644.565,1952.682,,,
73,868506dcc0,2026-07-30,5335,Fix CBOR half-float assertion bounds (#5335),3167.086,5267.068,15397.979,4351.011,3883.135,2003.345,1468.939,1360.483,7455.230,1909.055,2406.305,679.942,1643.646,1945.639,,,
74,dd24e2dffd,2026-07-30,5332,check all BSON reads and add an EOF check for booleans (#5332),3138.315,5284.833,15399.166,4310.513,3847.630,1980.682,1464.104,1344.108,7445.146,1901.512,2400.532,670.850,1635.196,1900.946,,,
75,fd72ecfc8c,2026-07-31,5301,validate ndarray element types in write_bjdata_ndarray (#5301),3164.662,5262.141,15399.010,4287.271,3849.318,1988.186,1460.688,1353.767,7458.380,1893.669,2398.485,668.466,1644.018,1921.615,,,
76,bc48951128,2026-07-31,5323,Fix UBJSON high-precision floating-point overflow handling (#5323),3155.628,5289.864,15474.375,4324.253,3888.966,2015.068,1477.846,1354.622,7480.730,1905.566,2415.428,668.997,1641.776,1911.819,,,
77,d94cbd99dc,2026-07-31,5274,reject CBOR array/map length equal to the indefinite-length marker (#5274),3144.041,5272.193,15466.980,4338.735,3848.849,1999.231,1459.129,1358.119,7507.307,1901.807,2394.972,667.016,1635.960,1899.878,,,
78,2222d386c9,2026-07-31,5339,fix: check CBOR tagged subtype reads (#5339),3095.768,5137.792,15064.146,4258.977,3755.229,1965.900,1454.890,1338.066,7399.068,1883.624,2358.193,660.190,1618.172,1939.713,,,
79,585929bff9,2026-08-03,5289,Fix Clang deprecation warning for json_pointer operator== with ordered_json (#5289),3142.341,5259.360,15258.271,4275.479,3807.672,1969.704,1453.688,1337.633,7451.037,1879.447,2364.966,661.560,1635.617,1945.709,,,
80,5f121d8c50,2026-08-03,5336,avoid sign extension in char_traits<signed char>::to_int_type (#5336),3145.000,5264.880,15441.521,4269.632,3796.781,1983.497,1440.810,1325.232,7427.750,1880.047,2361.899,663.772,1621.595,1912.378,,,
81,68f0722a19,2026-08-03,5342,remove discarded array from parent object in end_array (#5342),3161.273,5269.907,15312.469,4335.433,3840.510,1995.965,1465.745,1355.934,7474.901,1895.483,2401.197,657.397,1634.791,1901.902,,,
82,dca9d49a33,2026-08-05,5348,reject out-of-range code points in UTF-32 wide-string input (#5348),3119.753,5210.979,15209.260,4273.984,3799.034,1995.297,1459.456,1342.982,7431.646,1891.478,2370.364,653.618,1633.585,1882.753,,,
83,9a091d2b82,2026-08-05,5362,Do not write BJData ndarrays whose size overflows std::size_t (#5362),3137.381,5257.312,15286.084,4308.500,3805.325,1995.140,1468.138,1354.729,7510.088,1893.036,2384.577,659.394,1628.260,1890.245,,,
84,d5647e6a3b,2026-08-05,5355,Resolve the TODO(niels) in get_ubjson_string (#5355),3121.278,5249.927,15246.011,4292.737,3800.490,1967.087,1443.762,1333.226,7368.953,1862.131,2347.852,644.647,1623.909,1889.958,,,
85,bacdabd176,2026-08-05,5361,Fix start_pos() for strings containing escape sequences (#5361),3114.653,5251.619,15253.907,4331.818,3786.156,1960.676,1442.388,1330.247,7354.724,1863.306,2351.588,650.781,1623.543,1886.671,,,
86,1c136a66c4,2026-08-06,5363,Move the CBOR doc block to the function it describes (#5363),3124.274,5209.615,15411.897,4293.320,3812.156,1982.854,1457.653,1345.680,7422.343,1884.848,2387.050,656.076,1627.620,1878.737,,,
87,6285225fd0,2026-08-12,5211,Fix integer comparison bug (#5211),3159.557,5291.323,15395.395,4329.836,3867.200,1989.476,1456.052,1359.795,7526.860,1879.642,2396.137,659.077,1638.176,1900.416,,,
88,b5378e8deb,2026-08-19,5331,Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 (#5331),3172.476,5239.812,15479.917,4295.539,3871.289,2003.439,1473.447,1343.742,7516.875,1888.412,2400.572,645.588,1641.621,1886.531,,,
89,2f025f401e,2026-08-25,5380,Throw other_error.502 when UBJSON use_type is set without use_size (#5380),3155.873,5190.312,15144.406,4286.388,3793.805,1968.199,1442.240,1340.929,7373.610,1860.543,2370.570,648.906,1631.207,1893.750,,,
90,35705d79d8,2026-08-28,5414,Fix update(merge_objects=true) throwing on primitive-to-object merge (#5414),3169.029,5252.578,15387.292,4340.690,3893.646,1979.616,1472.286,1361.543,7491.302,1903.909,2401.404,659.396,1641.697,1912.409,,,
91,137a40b9aa,2026-09-05,5459,Compare integers with floats exactly instead of widening the integer (#5459),3134.229,5259.349,15404.541,4300.146,3846.646,1992.155,1467.919,1351.774,7467.146,1887.255,2391.467,660.347,1631.735,1891.751,,,
92,3c875683a5,2026-09-05,5461,Make diff() linear when an array shrinks (#5461),3141.068,5259.000,15271.166,4319.659,3797.088,1983.450,1455.354,1354.676,7444.860,1891.687,2389.333,657.163,1632.998,1887.016,,,
93,09b6b6b5ba,2026-09-05,5455,Fix to_bjdata() emitting unparsable output when _ArraySize_ is not an array (#5455),3161.542,5253.047,15311.718,4291.388,3834.264,1992.744,1472.685,1357.680,7409.479,1889.287,2389.501,698.680,1628.237,1888.705,,,
94,faa35cc647,2026-09-09,5484,Skip integer conversion in accept()/SAX validation when the value is unused (#5484),3103.654,5222.453,15458.573,4215.765,3804.320,1935.161,1468.660,1353.499,7452.052,1883.191,2383.524,654.441,1631.700,1885.664,,,
95,6d86cc0f6b,2026-09-09,5490,Speed up whitespace skipping in the lexer (#5490),3181.328,5276.318,15307.312,4262.771,3877.401,1977.062,1465.196,1356.119,7594.177,1906.814,2388.615,684.926,1636.950,1893.526,,,
96,c05347dd54,2026-09-09,5475,Undefine the four JSON_HEDLEY_* macros that leak after including json.hpp (#5475),3147.932,5156.625,15347.990,4217.505,3871.812,1982.807,1458.787,1354.934,7639.328,1879.823,2370.342,674.625,1637.257,1903.903,,,
97,d6660cf718,2026-09-09,5485,Route hand-rolled diagnostic pragmas through Hedley (#5485),3116.151,5215.531,15257.499,4189.979,3835.023,1974.111,1459.363,1342.996,7553.802,1887.698,2379.999,669.934,1635.350,1877.492,,,
98,c9477ccf91,2026-09-09,5496,Throw when JSON Patch remove's target path resolves through a primitive or null parent (#5496),3138.841,5258.401,15315.417,4201.008,3874.682,1967.630,1446.393,1335.060,7542.708,1870.111,2390.141,668.484,1634.138,1886.981,,,
99,8c38e270b5,2026-09-09,5497,Reject JSON Patch move when from is a proper prefix of path (#5497),3183.820,5280.000,15346.969,4222.164,3839.596,1970.753,1470.428,1351.838,7515.344,1895.809,2389.731,673.696,1633.247,1889.546,,,
100,a316738cfa,2026-09-09,5471,Add JSON_HEDLEY_WARN_UNUSED_RESULT to the current accept() overloads (#5471),3175.891,5281.302,15397.062,4240.576,3934.333,1981.765,1475.890,1353.387,7625.104,1896.181,2401.097,669.729,1646.133,1895.638,,,
101,c9f1d2d646,2026-09-09,5477,Broaden JSON_HEDLEY_WARN_UNUSED_RESULT coverage to pure query functions (#5477),3171.706,5286.880,15430.844,4264.242,3880.943,1979.990,1472.289,1357.283,7569.854,1904.026,2407.487,671.673,1641.521,1889.053,,,
102,8e26b9d4b3,2026-09-09,5495,Make contains(json_pointer) return false instead of throwing on unrepresentable array-index tokens (#5495),3163.789,5240.755,15337.698,4226.154,3880.956,1971.912,1475.322,1357.125,7632.281,1904.060,2401.190,678.863,1638.371,1903.385,,,
103,b17c272f46,2026-09-09,5472,Reserve capacity in from_json() object conversion when the target container supports it (#5472),3152.899,5257.645,15401.000,4210.846,3885.123,1989.159,1476.637,1359.851,7639.396,1898.981,2408.243,670.075,1633.528,1894.086,,,
104,3e2de32226,2026-09-10,5516,Remove unused iomanip include (#5516),3141.349,5253.657,15364.074,4203.969,3847.620,1968.422,1455.035,1352.754,7582.494,1882.051,2371.814,663.504,1630.172,1870.223,,,
105,d69fb8654d,2026-09-10,5501,Return the parsed value by move from from_cbor() and friends (#5501),3133.485,5231.662,15309.926,4183.200,3835.662,1971.125,1462.447,1349.563,7479.136,1904.202,1595.991,661.519,1630.278,1883.994,,,
106,4a93aa4e2f,2026-09-10,5283,"Speed up parsing of contiguous input (numbers, strings, UTF-8) (#5283)",1963.879,4221.308,11609.531,3278.497,3857.880,927.779,1483.726,1357.793,7483.343,1906.916,1481.419,676.438,1643.746,1895.551,,,
107,bfb07786cd,2026-09-10,5473,Fix to_bjdata() silently truncating out-of-range _ArrayData_ elements (#5473),1941.894,4204.971,11726.688,3264.055,3808.784,923.797,1453.071,1351.760,7458.125,1891.470,1473.508,662.164,1633.043,1888.548,,,
108,ff80ed3295,2026-09-11,5285,"Speed up dump(), and keep it from overflowing the stack (#5285)",1939.289,4175.541,11781.291,3233.302,3816.101,914.071,441.200,540.473,6895.041,852.214,1478.197,656.635,1632.675,1885.303,,,
109,da42a627dc,2026-09-11,5449,Stop dump() from heap-allocating its output adapter per call (#5449),1937.658,4200.966,11639.198,3235.493,3827.695,909.901,448.948,537.008,6909.036,839.027,1479.968,659.210,1643.621,1878.065,,,
110,1dc1d09fc6,2026-09-11,5457,Do not search a container for the value the callback rejected (#5457),1937.459,4140.078,11576.803,3271.838,3845.193,924.316,450.148,539.031,6848.776,844.624,1470.333,671.563,1645.624,1900.347,,,
111,fae364db24,2026-09-11,5458,Move the scanned string into the value instead of copying it (#5458),1986.146,4110.787,11757.157,3150.932,3830.550,918.517,442.629,539.606,6913.104,843.920,1417.037,655.259,1628.224,1892.991,,,
112,dd50f0eb16,2026-09-11,5502,Stop CBOR indefinite-length strings from recursing per chunk (#5502),1987.853,4033.182,11613.834,3116.378,3841.164,915.943,442.366,539.480,6864.130,836.458,1431.035,656.146,1599.574,1885.858,,,
113,4bb2de8cc5,2026-09-11,5503,Reject a nested BJData ndarray dimension vector where it is read (#5503),1981.298,4086.276,11569.240,3141.539,3829.870,923.087,444.038,539.863,6800.724,835.434,1429.637,655.448,1628.999,1879.300,,,
114,44f8ec30e9,2026-09-11,5504,Bound UBJSON optimized arrays of a valueless type (#5504),2005.265,4092.265,11730.198,3130.635,3863.992,925.033,448.222,542.323,6893.078,849.901,1437.855,662.171,1638.306,1896.324,,,
115,0dd8ca9023,2026-09-11,5505,Read MessagePack containers without recursing per nesting level (#5505),2019.983,4105.305,11862.979,3142.581,3891.601,927.092,447.942,543.936,6939.963,845.634,1442.889,656.578,1637.512,1897.815,,,
116,91ab3e81f5,2026-09-11,5506,Read CBOR containers and tags without recursing per nesting level (#5506),1986.334,4039.961,11554.094,3118.761,3783.101,912.504,440.410,534.894,6831.943,834.661,1439.061,655.287,1615.619,1869.912,,,
117,a14619b354,2026-09-11,5507,Read UBJSON and BJData containers without recursing per nesting level (#5507),2011.959,4095.868,11782.688,3135.264,3873.604,926.014,447.638,541.304,6905.838,846.051,1468.512,664.161,1629.083,1898.772,,,
118,0452641c18,2026-09-11,5508,Read BSON documents without recursing per nesting level (#5508),1974.160,4043.887,11662.938,3095.011,3832.744,916.007,439.914,534.149,6904.453,835.615,1450.792,648.298,1616.917,1874.133,,,
119,aa391dc0a5,2026-09-11,5520,Fix two develop CI regressions: dump() nodiscard warning and binary-reader const-correctness (#5520),2003.010,4068.010,11771.364,3137.266,3825.247,924.668,442.416,539.478,6847.083,841.996,1460.659,649.378,1633.738,1885.897,,,
120,a50c2537eb,2026-09-12,5476,Reserve capped array capacity in json_sax_dom_parser::start_array() for definite-length binary arrays (#5476),1986.488,4063.883,11588.333,3077.995,3827.479,908.419,440.959,539.114,6806.177,833.555,1452.851,662.422,1627.995,1915.388,,,
121,c0b2878a44,2026-09-13,5493,Swap diagnostic positions in basic_json::swap() (#5493),2010.881,4081.057,11734.730,3130.919,3882.258,925.490,450.092,542.953,6925.188,848.486,1480.051,698.636,1643.508,1933.941,,,
122,1da2f68992,2026-09-14,5522,Only reserve array capacity if the array type supports it (#5522),1972.122,4048.622,11775.062,3107.938,3803.528,909.385,441.204,535.885,6793.927,842.843,1446.330,658.787,1619.239,1899.164,,,
123,6487678bc5,2026-09-15,5464,Fix swap(array_t&)/swap(object_t&) to update parent pointers under JSON_DIAGNOSTICS (#5464),2023.028,4116.169,11737.438,3165.172,3893.266,924.912,448.959,541.529,6970.438,852.039,1483.231,689.631,1635.240,1937.356,,,
124,c72f37a40d,2026-09-15,5443,Support custom object/array types and improve template parameter handling (#5443),2001.617,4076.547,11666.583,3109.756,3918.206,923.197,450.592,542.266,6901.703,846.558,1468.284,660.116,1641.586,1905.840,,,
125,502e9d66f6,2026-09-16,5479,Fix to_bjdata() emitting the Draft-3-only 'B' marker in default Draft-2 mode (#5479),1970.935,4018.060,11445.500,3079.409,3809.050,910.459,444.217,539.291,6851.407,833.755,1444.697,698.040,1626.601,1889.024,,,
126,c41152e620,2026-09-16,5494,Fall back to plain-object encoding when to_bjdata()'s _ArrayType_ annotation is not a string (#5494),1979.481,4054.688,11734.292,3085.542,3819.351,916.992,445.126,539.870,6853.005,833.190,1457.166,665.391,1629.586,1888.734,,,
127,e564136c22,2026-09-22,5465,Make diff() account for member order in ordered_json objects (#5465),1970.519,4063.744,11605.198,3087.497,3848.867,915.695,447.051,539.711,6835.172,841.402,1452.004,664.560,1640.751,1890.473,,,
128,e485441123,2026-09-22,5466,Restore a duplicate key's prior value when the callback rejects its new value (#5466),2012.920,4099.265,11796.895,3156.818,3913.812,931.464,451.403,541.419,6981.041,846.536,1469.521,704.138,1633.327,1905.709,,,
129,a2b19d6158,2026-09-22,5467,Honor allow_exceptions=false for excessive array/object size (out_of_range.408) (#5467),1996.478,4084.422,11734.208,3129.099,3850.854,923.499,446.555,539.379,6949.427,842.029,1453.166,694.200,1631.133,1888.865,,,
130,d2c1a6a272,2026-09-22,5468,"Reject array insert(pos, first, last) iterators not pointing into an array (#5468)",1983.767,4066.651,11618.667,3128.505,3848.427,914.900,447.603,541.973,6915.265,844.307,1458.762,677.699,1638.789,1892.443,,,
131,0b20b7e622,2026-09-22,5469,Reject MessagePack/BSON binary subtypes that don't fit their wire format (#5469),2010.548,4097.476,11681.218,3121.010,3866.146,925.619,448.533,540.786,6957.000,843.349,1463.518,658.302,1630.857,1902.522,,,
132,1054b2097e,2026-09-23,5286,Speed up binary writing: value-type output sink + byte-swap number encoding (#5286),1989.739,4101.393,12034.438,3157.240,3853.987,910.115,449.084,555.970,6884.386,864.526,1471.905,656.635,1661.806,1926.233,,,
133,ed513715a8,2026-09-24,5534,Document that a NUL byte in the input is treated as end of input (#5534),2016.236,4104.763,11906.323,3141.138,3936.240,916.611,455.397,562.053,6987.917,871.110,1475.622,657.877,1676.934,1936.557,,,
134,56b3ee566c,2026-09-24,5389,Fix stack overflow when copying a deeply nested value (#5387) (#5389),1998.356,4051.206,11660.865,3101.107,3834.672,910.072,452.943,544.464,6908.974,849.212,1460.691,638.644,1650.749,1914.423,,,
135,918da64657,2026-09-24,5542,Keep BJData ndarray annotations that would not survive a round trip as objects (#5542),2003.009,4042.969,11517.375,3095.122,3815.360,908.444,448.415,539.423,6911.041,840.044,1449.543,671.530,1651.709,1908.408,,,
136,8699de3064,2026-09-24,5555,Stop allocating the BJData excluded-marker list per container (#5555),2001.718,4071.333,11686.427,3122.065,3796.757,900.895,447.123,539.918,6860.765,844.752,1444.435,646.608,1644.943,1879.295,,,
137,2e91641de2,2026-09-24,5544,"Test JSON_BRACE_INIT_COPY_SEMANTICS for real, and fix one-element tuples under it (#5544)",2004.785,4083.914,11662.270,3119.602,3917.914,922.465,454.869,547.631,6987.234,853.010,1469.612,649.946,1672.246,1913.098,,,
138,7c90ec2323,2026-09-24,5546,Hash deeply nested values without recursing per nesting level (#5546),1952.912,4071.159,11594.927,3117.497,3793.052,900.729,444.245,539.787,6854.406,841.264,1457.530,643.139,1638.578,1890.482,,,
139,4daca40d7b,2026-09-24,5547,Merge deeply nested objects without recursing per nesting level (#5547),2008.226,4104.399,11619.542,3148.604,3918.175,921.207,457.191,547.553,6942.265,855.352,1464.974,651.924,1665.232,1915.869,,,
140,01b53c8c15,2026-09-25,5552,Keep JSON_DIAGNOSTICS parent pointers of ordered_json members after erase() and update() (#5552),1979.354,4061.378,11603.480,3098.586,3875.258,919.125,455.911,546.269,6940.026,849.511,1461.751,648.841,1660.978,1917.254,,,
141,abbe52d6de,2026-09-25,5344,Add JSON_PRECISE_STREAM_POSITION to leave the character that terminates a number in the stream (#5344),2001.170,4081.617,11653.531,3131.331,3876.208,915.153,453.436,546.720,6971.864,848.900,1463.182,647.946,1662.943,1906.246,,,
142,02dd3e67f2,2026-09-25,5390,Fix stack overflow and exponential runtime when comparing nested values (#5390),1987.861,4074.039,11596.000,3161.284,3901.497,919.541,447.553,543.948,6910.162,845.668,1455.759,664.224,1652.074,1930.575,,,
143,465407f3ce,2026-09-25,2818,Improve error message for const fields (#2818),1975.274,4118.565,11863.448,3130.541,3880.764,910.767,452.904,545.363,6906.890,843.118,1459.728,645.770,1654.265,1934.900,,,
144,632a5812a8,2026-09-25,5272,Support zero-member types in NLOHMANN_DEFINE_TYPE_* macros (#4041) (#5272),1963.323,4021.526,11747.959,3102.006,3784.896,904.545,444.355,543.748,6840.604,841.416,1438.306,639.223,1649.816,1930.274,,,
145,d19f7f5dce,2026-09-25,5185,Fix BSON conformance issue (#5185),1958.606,4048.536,11541.011,3086.805,3817.875,900.452,446.001,544.071,6824.323,837.078,1971.245,641.271,1651.209,1934.647,,,
146,c60a0bc336,2026-09-25,5573,Allocate the deep copy's key scratch space with the provided allocator (#5573),1965.216,4021.459,11630.855,3074.078,3807.258,902.782,444.394,542.562,6919.969,840.942,1975.668,645.827,1637.429,1918.607,,,
147,1e44262091,2026-09-25,5560,Make JSON_STRICT_NUL_HANDLING part of the ABI tag (#5560),1961.862,4069.617,11594.083,3117.500,3817.758,909.186,448.820,544.420,6845.802,844.016,1977.909,645.864,1651.269,1937.217,,,
148,95e9a5931c,2026-09-25,5553,"Write BSON in linear time, without recursing per nesting level (#5553)",1965.832,4033.394,11589.364,3120.422,3792.091,905.110,446.984,543.328,6794.244,844.943,1991.659,640.188,1647.675,1928.562,,,
149,fe4a544c7e,2026-09-27,5515,handled when size exceed uint32 (#5515),1998.244,4047.208,11755.209,3091.776,3815.000,908.733,447.990,546.295,6903.084,850.946,1993.351,645.487,1654.343,1933.385,,,
150,4fa95d9810,2026-09-27,5583,Remove unreachable branches from the binary writer (#5583),1983.323,4038.331,11666.480,3092.841,3844.935,910.149,449.697,541.110,6840.583,830.604,1979.750,653.542,1650.670,1928.883,,,
151,6178982b8d,2026-09-27,5582,Compare unordered objects by key below the nesting bound (#5582),1971.706,4073.498,11600.646,3132.700,3830.323,910.231,448.982,538.812,6836.770,846.149,2007.607,657.180,1653.089,1934.675,,,
152,f7972970a4,2026-09-27,5584,Throw instead of writing MessagePack lengths beyond UINT32_MAX (#5584),1969.417,4013.021,11602.447,3083.552,3842.495,904.223,447.444,542.170,6862.735,839.628,2000.766,655.034,1653.006,1939.922,,,
153,6bd106893a,2026-09-27,5559,Fix CBOR tag handling in cbor_tag_handler_t::store for non-binary items (#5559),1969.250,4034.693,11691.500,3119.171,3827.860,916.053,455.026,542.577,6886.360,839.718,2012.919,653.031,1651.090,1931.698,,,
154,1e101ecac1,2026-09-27,2998,Add BON8 support (#2998),1975.804,4082.375,11658.542,3192.828,3758.141,907.029,444.920,556.470,6844.698,849.276,1977.153,649.181,1645.306,1920.836,,,
155,9e1a09eec0,2026-09-28,5594,Name the key type when rejecting non-string CBOR/MessagePack map keys (#5594),2006.582,4151.784,11788.532,3156.156,3845.052,915.647,454.027,557.846,6814.282,864.094,2021.072,654.095,1663.051,1947.078,,,
156,fc03b9912e,2026-09-28,5597,"Look up the locale decimal point at conversion time, not lexer construction (#5597)",2020.431,4172.916,12716.958,3196.958,3909.774,910.001,449.314,547.334,6900.968,852.306,2048.019,665.843,1696.937,1982.586,,,
157,5b9ffae8bb,2026-09-30,5616,Move the float conversion chain out of the lexer (#5616),1992.332,4167.328,12638.573,3212.515,3842.885,906.649,446.941,539.674,6952.672,839.042,2021.057,695.813,1684.689,1967.216,,,
158,d268eaa693,2026-09-30,5617,Convert floats with Eisel-Lemire when std::from_chars is unavailable (#5617),1987.608,4086.125,11507.062,3170.013,3830.425,898.856,445.077,542.854,6919.568,839.210,2021.918,666.925,1701.466,1951.211,,,
159,65af260117,2026-09-30,5609,Move instead of deep-copy ordered_json values when an object grows (#5609),1998.981,4134.057,11592.855,3192.779,3863.005,904.702,446.575,539.685,6850.886,840.845,2035.646,680.331,1682.755,1968.744,,,
160,6a8a7735ed,2026-09-30,5614,Do not throw in contains() for an empty array reference token (#5614),2008.447,4144.024,11612.176,3165.468,3842.060,905.045,443.941,539.755,6846.042,846.248,1998.713,669.752,1684.717,1953.487,,,
161,0050d0f7a4,2026-09-30,5637,Share one nesting depth limit between all bounded descents (#5637),2021.078,4170.581,11589.886,3224.963,3937.021,906.411,448.033,541.177,6911.391,848.641,2040.978,670.005,1703.593,1984.639,,,
162,68beba727c,2026-09-30,5679,Fix from_json() for enums with underlying type bool (#5679),1986.468,4139.033,11632.833,3201.351,3798.006,888.464,438.471,535.903,6843.110,836.030,1996.109,685.053,1672.430,1940.598,,,
163,fc4c9c3446,2026-09-30,5680,Fix clear() to also reset the subtype of a binary value (#5680),1972.561,4094.867,11540.157,3155.722,3833.925,893.243,445.764,539.739,6848.562,843.068,2016.293,664.788,1685.759,1965.342,,,
164,678fd3017b,2026-09-30,5681,Fix element path for map/unordered_map JSON_DIAGNOSTICS errors (#5681),2014.783,4164.471,11563.614,3219.865,3891.917,892.727,445.945,542.044,6900.807,844.422,2034.323,669.901,1688.051,1981.601,,,
165,6d7845d207,2026-09-30,5683,Fix deprecated json_pointer/string operator== warning in value() (#5683),1965.197,4105.789,11501.364,3157.544,3800.289,898.122,445.399,539.685,6900.433,834.541,2000.133,652.354,1670.945,1960.876,,,
166,42f89e3130,2026-09-30,5684,Let to_json(std::optional<T>) propagate exceptions from T's to_json (#5684),2016.899,4156.430,11476.489,3216.315,3895.245,908.714,444.300,541.764,6923.422,839.459,2018.934,672.859,1689.306,1987.428,,,
167,6218aa212b,2026-09-30,5687,Throw std::length_error for operator[](SIZE_MAX) instead of corrupting the array (#5687),1989.158,4149.156,11547.229,3193.015,3845.187,905.308,446.389,541.290,6853.266,843.028,2037.245,661.213,1681.390,1966.649,,,
168,1151826508,2026-09-30,5691,Take diff()'s fast path unless the object type reorders members (#5691),1991.280,4147.341,11570.312,3171.182,3847.333,904.510,441.250,539.803,6885.776,836.303,2018.693,665.307,1685.990,1970.057,,,
169,e444a66276,2026-09-30,5693,Copy values before inserting an initializer list into an array (#5693),2000.774,4175.507,11546.979,3189.357,3841.169,897.455,442.384,539.493,6839.688,836.213,2014.519,667.390,1685.418,1968.991,,,
170,bfea6f36d3,2026-09-30,5694,Fix to_msgpack() reading the inactive number union member (#5694),1997.465,4144.279,11549.781,3224.287,3855.120,899.475,441.995,539.924,6903.776,839.550,2019.396,664.487,1688.249,1954.211,,,
171,5b11a0282c,2026-09-30,5697,Exchange the CustomBaseClass subobject in basic_json::swap() (#5697),1987.983,4074.349,11483.114,3174.632,3841.604,893.256,438.279,535.885,6866.641,834.328,1996.396,660.828,1676.300,1936.210,,,
172,44a88d85be,2026-09-30,5698,Fix NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json message (#5698),1972.237,4125.945,11373.917,3158.716,3810.039,890.097,438.075,534.577,6867.432,842.045,2028.150,664.206,1681.353,1936.231,,,
173,bfe0f32d71,2026-09-30,5699,Fix std::terminate and null pointer access in input_stream_adapter (#5699),2014.371,4159.779,11667.416,3200.425,3876.135,911.716,448.788,543.198,6932.657,852.397,2056.197,668.764,1699.573,1984.479,,,
174,4bb1b14b06,2026-09-30,5702,Trim the compiler-appended NUL from wide/UTF string literals too (#5702),1979.723,4105.685,11603.562,3180.932,3846.698,906.188,443.969,534.534,6837.479,840.588,2006.043,654.851,1672.289,1965.408,,,
175,5bd766aa50,2026-09-30,5703,Move to_bson's binary subtype check into calc_bson_sizes (#5703),1999.606,4183.386,11588.646,3192.771,3844.425,900.169,446.795,541.406,6888.114,847.107,2022.637,663.480,1686.702,1974.777,,,
176,6ae17630a4,2026-09-30,5705,"Reject integral keys for contains(), find(), and count() at compile time (#5705)",2000.405,4157.120,11551.656,3197.417,3891.646,903.558,448.544,541.553,6914.203,848.561,2042.578,663.661,1691.910,1974.341,,,
177,7fd6895788,2026-09-30,5706,Hide a discarded container's content from the parser callback (#5706),1971.987,4075.362,11463.219,3164.909,3797.453,889.534,443.974,535.026,6857.323,835.793,2025.343,651.970,1687.670,1951.428,,,
178,66877675b1,2026-09-30,5719,"Check the iterator range for binary values in basic_json(first, last) (#5719)",1970.369,4104.886,11534.635,3168.601,3796.291,897.271,444.655,538.917,6826.990,842.445,2016.962,650.099,1673.940,1953.693,,,
179,2ea6d8c127,2026-09-30,5720,Require the found key to equal the looked-up key when comparing objects (#5720),2015.556,4188.886,11567.125,3251.890,3863.818,903.970,448.691,540.422,6912.255,843.774,2044.479,653.832,1676.634,1951.959,,,
180,67435c9c7e,2026-09-30,5721,Give a deep copy its type only after its container exists (#5721),1994.257,4160.658,11600.553,3218.367,3880.128,900.769,449.260,541.607,6899.448,841.635,2043.909,666.759,1694.646,1974.861,,,
181,6fc0d501f3,2026-09-30,5610,Move the user-defined string literals to <nlohmann/json_literals.hpp> and add JSON_NO_AUTOMATIC_UDLS (#5610),2021.715,4187.888,11647.594,3209.388,3925.060,911.591,450.961,544.303,6975.265,845.109,2049.853,670.295,1697.019,1987.428,,,
182,fdcc569eee,2026-09-30,5692,Use only documented StringType members in json_pointer (#5692),1965.264,4147.273,11378.188,3159.364,3787.758,889.399,447.397,535.062,6809.698,835.116,2015.202,656.241,1689.072,1955.238,,,
183,6a073dbae4,2026-09-30,5695,Give operator>> a strong exception-safety guarantee (#5695),2010.979,4211.982,11698.218,3205.401,3897.172,898.499,445.961,545.225,6898.870,847.042,2051.316,664.716,1706.401,1981.247,,,
184,3b6ae43c53,2026-09-30,5598,Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions (#5598),2025.122,4195.468,11682.199,3204.529,3924.068,904.766,448.209,544.669,7041.276,849.103,2047.488,665.592,1695.987,1984.755,,,
185,7d7055ec50,2026-09-30,5723,Fix stack overflow converting deep values between specializations (#5723),1985.310,4117.099,11457.052,3157.591,3832.175,895.910,442.225,535.237,6864.375,833.653,2001.760,679.826,1674.819,1956.998,,,
186,35802e78d6,2026-09-30,5735,Remove dead Makefile targets; document macro_builder; tidy serve_header (#5735),2004.498,4163.065,11590.594,3184.810,3902.229,906.494,447.394,539.542,6923.969,845.596,2044.457,666.187,1692.019,1977.030,,,
187,c261578431,2026-09-30,5730,Deduplicate binary reader/writer helpers and fix stale comments (#5730),1968.723,4154.789,11441.718,3160.367,3870.578,889.545,443.139,535.314,6850.886,837.281,2024.650,660.842,1691.628,1978.000,,,
188,1d675cdb46,2026-09-30,5733,Fix CI jobs that check less than they claim; move arm64 to GitHub (#5733),1995.704,4206.185,11691.125,3227.622,3966.104,909.748,449.770,541.566,6951.938,852.506,2009.592,663.701,1686.265,1983.285,,,
189,a32f61eb98,2026-09-30,5678,Fix update() and merge_patch() when the argument is *this or one of its members (#5678),2014.810,4157.101,11636.135,3210.326,3924.659,899.344,448.133,541.371,6913.401,841.487,2038.263,667.515,1697.503,1980.686,,,
190,18dd5663b0,2026-10-01,5548,Diff deeply nested values without recursing per nesting level (#5548),1990.931,4152.500,11469.697,3204.740,3985.593,903.248,448.981,540.974,6929.740,847.493,2040.504,665.352,1698.903,1981.438,,,
191,3926fcaac3,2026-10-01,5729,"Deduplicate serializer dump code; fix stale includes, docs, and lint (#5729)",1999.556,4178.489,11581.000,3208.657,3876.755,891.669,452.445,538.525,6893.078,846.721,2042.010,662.154,1689.653,1975.503,,,
192,cff0a61369,2026-10-01,5731,Share DOM SAX position handling; fix stale parser and lexer comments (#5731),2017.231,4112.604,11588.291,3157.047,3890.343,902.329,458.713,539.539,7020.568,847.995,2073.873,654.562,1696.823,1978.381,,,
193,e400780533,2026-10-01,5745,Re-amalgamate single_include (#5745),1980.338,4100.659,11418.854,3166.896,3835.432,885.298,452.886,538.053,6888.203,824.666,2031.410,650.846,1668.952,1949.107,,,
194,6aec1a085f,2026-10-02,5677,Report BON8 input that ends after a UTF-8 lead byte as truncated (#5677),2003.321,4099.066,11614.364,3159.029,3849.857,899.995,459.542,539.436,6904.474,843.221,2071.503,652.303,1685.702,1972.556,,,
195,4d46bce4e1,2026-10-02,5750,Fix CI on develop (#5750),1962.685,4025.677,11277.718,3103.052,3785.213,894.610,448.583,533.887,6870.062,834.856,2020.231,658.339,1674.874,1954.242,,,
196,63c10a51fc,2026-10-02,5638,"Review and extend the documentation, and check it in CI (#5638)",1968.954,4036.851,11425.135,3104.359,3797.852,902.519,451.067,537.668,6910.375,852.438,2043.889,674.938,1701.314,1971.711,,,
197,6d0867a85f,2026-10-02,5751,Make comparisons with scalars noexcept only when the conversion is (#5751),2008.360,4091.453,11376.562,3144.575,3820.110,903.850,455.980,538.035,6851.885,841.549,2010.128,667.182,1690.586,1970.957,,,
198,d11e89471b,2026-10-04,5606,Assert on missing array indices in const operator[] and document the JSON pointer case (#5606),2000.121,4075.695,11475.520,3139.456,3837.211,900.437,453.703,538.895,6921.432,845.064,2027.417,663.969,1679.148,1964.082,,,
199,df27cc3d4c,2026-10-04,5682,Add scalar-on-left overloads for legacy discarded comparisons in C++20 (#5682),2010.838,4092.432,11495.625,3125.726,3873.167,911.281,456.807,538.386,6911.630,844.451,2033.630,688.219,1691.407,1971.697,,,
200,6f2048cd5d,2026-10-04,5685,Accept lvalues in ordered_map::emplace's value parameter (#5685),1999.816,4095.006,11445.740,3136.685,3924.146,918.692,458.336,542.423,6968.520,848.783,2037.096,667.772,1708.274,2002.449,,,
201,0d01d6ae90,2026-10-04,5686,Classify leaves with operator<=> itself past the nesting bound (#5686),1983.320,4116.981,11466.250,3192.969,3923.208,914.596,456.625,539.558,6975.537,849.252,2056.035,701.221,1716.493,1983.908,,,
202,b730946432,2026-10-04,5689,Fix key types convertible to std::string_view breaking lookups (#5689),1990.288,4060.487,11377.709,3107.537,3803.857,892.191,451.727,538.045,6896.480,844.989,2018.884,658.649,1676.566,2023.638,,,
203,49cd427196,2026-10-04,5690,"Copy-construct the base class of a deep copy's elements, not assign it (#5690)",1983.320,4033.156,11333.843,3138.547,3882.878,894.785,454.473,538.337,6918.619,841.205,2072.151,655.193,1693.871,1977.288,,,
204,756b28c2b8,2026-10-04,5696,Keep a NUL byte ending a // comment as the end of input (#5696),1985.931,4099.331,11579.875,3148.560,3872.422,896.276,451.436,536.774,6901.156,845.631,2014.820,648.054,1685.199,1971.762,,,
205,1edf0ef041,2026-10-04,5700,"Fix value(json_pointer, default) aborting under JSON_NOEXCEPTION (#5700)",1987.233,4076.133,11442.625,3124.099,3888.688,898.266,454.349,539.423,6950.140,852.803,2030.279,654.586,1691.751,1978.197,,,
206,a212d3b2e4,2026-10-04,5722,Preserve the object comparator's state in a deep copy past the nesting bound (#5722),2000.138,4113.471,11391.854,3151.006,3866.904,905.695,455.384,539.504,6929.818,842.213,2029.619,674.438,1697.044,1983.856,,,
207,1df1e8a845,2026-10-04,5591,Make cross-string-type basic_json conversion explicit without implicit conversions (#5591),2000.533,4107.994,11370.989,3160.854,3881.635,897.877,455.201,540.307,6927.167,840.130,2053.458,664.118,1697.618,1982.876,,,
208,38a2db260c,2026-10-04,5728,Remove dead metaprogramming and duplicated code in traits and pointers (#5728),1971.450,4040.828,11319.270,3109.521,3819.505,903.606,451.137,538.725,6825.640,843.951,2016.652,663.160,1684.596,1958.896,,,
209,c5650eaa3c,2026-10-04,5704,Reject malformed UTF-16/UTF-32 units in wide-string input (#5704),2006.689,4133.594,11469.209,3180.930,3881.633,902.924,456.572,540.557,6992.385,850.474,2025.267,652.367,1680.025,1957.468,,,
210,40021f38fb,2026-10-04,5589,Add basic_json::as_base_class and document name conflicts with custom base classes (#5589),2012.673,4147.193,11453.250,3167.448,3892.542,910.149,457.238,541.642,6998.084,852.247,2049.759,652.868,1688.229,1972.508,,,
211,73e9eae3c1,2026-10-04,5746,Add an error_handler parameter for UTF-8 to the binary readers and writers (#5746),2013.845,4130.237,11456.041,3135.688,3818.956,892.111,449.408,538.308,6825.213,835.872,1495.468,697.054,1679.760,1970.285,,,
212,d8d47be4a5,2026-10-04,5754,Fix CI on develop after merging the ready-to-merge PRs (#5754),2013.191,4119.948,11573.656,3173.029,3941.703,912.201,459.208,541.264,7013.364,848.908,1514.681,699.273,1685.391,1984.652,,,
213,6b4b825af2,2026-10-04,5607,Handle numbers that do not fit narrow number types in the binary readers (#5607),2009.190,4044.127,11362.677,3127.688,3827.841,892.131,449.386,534.731,6915.360,829.562,1487.640,697.206,1688.237,1952.157,,,
214,8c1f60a45e,2026-10-04,5600,Store maps with enum keys as objects (opt-in) (#5600),2008.560,4128.059,11523.011,3187.763,3843.177,912.520,456.427,537.514,6859.010,839.685,1501.515,696.508,1688.848,1968.910,,,
215,c5a7a4b46d,2026-10-04,5688,"Add deprecated from_bon8/from_bjdata(ptr, len) overloads (#5688)",2030.310,4108.505,11412.907,3141.836,3899.435,904.756,455.298,541.069,6926.151,846.240,1504.193,700.820,1693.983,1987.713,,,
216,23d3b373e1,2026-10-04,5755,Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions (#5755),2018.708,4106.015,11533.729,3134.945,3826.409,899.623,452.833,538.544,6846.443,830.555,1509.060,705.724,1692.819,1971.476,,,
217,8a142bc436,2026-10-06,5764,"Fix CI on develop after #5600, #5607, and #5755 (#5764)",2017.533,4151.854,11526.334,3195.240,3884.953,907.457,456.697,540.114,6891.136,844.145,1517.241,699.051,1690.344,1972.104,,,
218,5379e04ce4,2026-10-06,5761,Throw type_error.321 when serializing discarded values to binary formats (#5761),1999.156,4055.300,11427.521,3153.581,3836.060,891.927,455.413,540.938,6883.093,853.094,1510.099,701.888,1686.695,1982.806,,,
219,0a365865f9,2026-10-06,5762,Make basic_json destruction allocation-free and non-recursive (#5762),2024.289,4081.646,10719.428,3112.958,3900.503,924.900,462.081,540.765,6965.453,850.019,1511.381,669.802,1620.269,1912.078,,,
220,5ecb704f6b,2026-10-06,5592,Speedup; check for the expected separator before the lexer's token switch (#5592),1920.428,3801.979,10139.250,2891.862,3833.159,823.859,451.951,540.310,6885.672,843.570,1512.778,668.793,1608.501,1885.206,,,
221,6d4543e743,2026-10-06,5767,Fix destroy() for ObjectTypes without reverse iteration (#5767),1929.030,3843.266,10232.541,2911.458,3926.867,830.030,450.002,542.043,6938.890,846.589,1515.211,675.264,1622.245,1904.006,,,
222,9b179cee1e,2026-10-06,5770,Handle all value_t enumerators in has_no_children() (#5770),1931.275,3794.497,10155.125,2891.927,3871.831,829.432,446.176,535.126,6909.625,833.114,1498.945,677.571,1615.785,1884.043,,,
223,69874e4544,2026-10-06,5760,Fix NUL bytes in UBJSON/BJData high-precision numbers (#5760),1924.896,3853.081,10247.750,2926.515,3872.041,835.227,453.025,541.002,6919.037,842.240,1521.169,674.487,1607.441,1880.884,,,
224,162e13b86f,2026-10-06,5758,Add with_*_t alias templates to create basic_json types with changed template parameters (#5758),1938.268,3842.126,10289.968,2914.104,3962.414,834.967,455.536,543.630,6969.266,850.082,1530.064,678.054,1635.303,1916.763,,,
225,21a69230bd,2026-10-06,5585,Create a value before giving it its type (#5585),1918.165,3829.354,10247.656,2914.619,3874.909,832.287,451.252,543.791,6873.995,839.514,1521.088,699.604,1615.742,1894.449,,,
226,ff6f3d7d4a,2026-10-07,5766,Reject nested indefinite-length CBOR string chunks (#5766),1926.074,3868.810,10256.823,2919.802,3957.807,832.129,457.241,543.640,7024.745,847.770,1522.612,705.623,1634.212,1918.402,,,
227,1c754cfe31,2026-10-07,5701,Copy a pair-shaped array value under JSON_BRACE_INIT_COPY_SEMANTICS (#5701),1930.652,3828.195,10263.927,2921.570,3901.404,832.628,455.652,541.701,6909.037,843.563,1512.309,704.354,1623.254,1909.917,,,
228,24dd7c63f0,2026-10-07,5777,Re-amalgamate after #5740 (#5777),1908.632,3833.930,10278.146,2905.443,3935.422,838.465,454.491,545.605,6905.047,839.087,1519.816,709.223,1618.643,1886.706,,,
229,30e542e52a,2026-10-07,5776,Declare the namespace-scope constants in to_chars.hpp inline (#5776),1934.934,3823.724,10229.636,2916.698,3929.565,829.102,452.279,543.038,6951.995,837.059,1524.049,720.722,1619.823,1903.938,,,
230,367336c83d,2026-10-07,5779,Fix CI on develop after #5585 (#5779),1928.921,3780.927,10153.395,2883.604,3877.750,824.488,451.999,543.662,6927.395,835.495,1506.387,694.058,1622.903,1907.732,,,
231,069ace74af,2026-10-07,5707,"Round-trip BJData ND-array annotations exactly (single precision, key order) (#5707)",1937.387,3843.716,10184.302,2923.323,3936.570,827.610,456.123,543.169,6907.756,847.020,1515.229,696.202,1626.001,1901.142,,,
232,43fe8928e1,2026-10-07,5781,Stop binary writers overflowing the stack on deep values (#5781),1961.046,3868.274,10300.573,2899.792,3982.526,845.594,461.395,543.298,7059.093,846.696,1522.728,697.717,1623.846,1921.370,,,
233,a5f5d3059b,2026-10-07,5772,Make std::hash<basic_json> consistent with operator== for numbers (#5772),1949.220,3857.159,10170.427,2890.052,3981.349,840.234,459.334,541.947,6953.786,843.495,1509.713,703.339,1627.086,1911.653,,,
234,a269794db7,2026-10-08,5782,Use MSVC intrinsics for full multiplication (#5782),1931.869,3817.742,10159.666,2902.820,3903.263,840.740,455.827,540.621,6884.562,843.272,1513.776,702.028,1614.459,1901.008,,,
235,69a0c1b82c,2026-10-09,5328,Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328),1909.579,3777.560,10065.682,2852.732,3897.659,833.289,459.856,540.631,6882.354,833.998,1498.288,314.059,1609.343,1906.714,,,
236,374dfe4f0f,2026-10-09,5791,Keep converted object keys alive while writing UBJSON and BJData (#5791),1911.274,3827.188,10159.553,2886.568,3890.388,833.632,459.800,542.649,6954.547,838.507,1509.324,314.357,1613.655,1892.838,,,
237,44e8597701,2026-10-09,5792,Flatten deeply nested values without recursing per nesting level (#5792),1940.103,3811.779,10139.396,2865.050,3874.896,835.001,459.686,544.065,6866.943,836.862,1496.298,314.617,1614.837,1891.741,,,
238,2913e96433,2026-10-09,5793,Unflatten in time and memory linear in the pointer depth (#5793),1908.453,3785.099,10262.147,2878.961,3920.657,845.619,459.806,543.998,6874.813,832.659,1486.901,312.175,1589.620,1863.981,,,
239,84ee12a67c,2026-10-09,5797,Make UTF8_ACCEPT/UTF8_REJECT inline variables to avoid TU-local exposure in modules (#5797),1922.691,3792.849,10162.656,2871.562,3887.719,836.308,456.522,542.577,6912.807,840.369,1497.447,313.683,1609.988,1899.591,,,
240,1649d9eda4,2026-10-11,5783,Use and extend the detail helpers to remove duplicated code (#5783),1916.258,3804.242,10297.344,2913.118,3847.662,836.519,453.270,538.750,6953.015,832.774,1506.068,324.715,1596.974,1875.878,,,
241,2cca04ae6f,2026-10-11,5800,Report one-character non-numeric array indices like longer ones (#5800),1932.327,3803.750,10135.438,2881.041,3894.622,840.016,458.569,538.037,6842.948,829.444,1499.722,324.811,1607.194,1875.851,,,
242,74a03dec84,2026-10-11,5802,Throw type_error.321 for discarded values in to_bon8 (#5802),1924.695,3814.854,10084.239,2873.180,3848.498,839.406,450.575,534.181,6893.005,834.300,1503.369,324.389,1607.323,1887.871,,,
243,e8b747e4bc,2026-10-11,5808,Re-amalgamate single_include after #5795 and #5806 (#5808),1937.995,3840.622,10221.990,2896.024,3885.568,834.394,458.874,539.771,6906.182,839.793,1517.689,324.800,1609.838,1890.885,,,
244,40a62947d3,2026-10-12,4965,support JSON Merge Patch (RFC 7396) diff creation (#4965),1932.021,3822.188,10248.416,2924.560,3980.331,842.462,459.010,540.237,6978.526,838.941,1529.508,326.435,1636.153,1917.472,,,
245,f23830b65e,2026-10-13,5809,Derive the lexer position lazily for seekable input (#5809),1814.075,3368.028,9974.755,2807.532,3943.229,647.639,457.018,551.206,6954.166,843.355,1522.762,315.716,1618.953,1903.816,,,
246,aa9620fb15,2026-10-13,5810,Skip the indentation after a newline 8 bytes at a time (#5810),1719.629,2959.344,10139.771,2799.555,3939.292,592.867,465.821,545.858,6968.068,849.167,1519.774,315.385,1629.981,1907.253,,,
247,e839bbd1c0,2026-10-13,5813,"Export client-facing headers from json.hpp for IWYU / include-cleaner, and check clients in CI (#5813)",1725.742,2949.070,10136.603,2821.591,3919.927,589.957,463.642,544.851,6987.427,843.151,1517.562,314.425,1619.671,1903.613,,,
248,5b4c8f9b00,2026-10-14,5738,"Speed up the lexer: own float parser, string scan, and \u table (#5738)",1615.668,2934.565,8763.651,2794.503,3928.286,559.107,374.921,516.391,6937.140,815.776,1513.238,325.043,1625.226,1912.905,,,
249,91a7a94cc6,2026-10-14,5634,"Write doubles with the shortest digits (Żmij), digits in registers (#5634)",1613.126,2929.599,8708.599,2783.954,3874.248,548.449,363.632,468.127,2421.176,745.466,1511.406,323.743,1614.195,1900.392,,,
250,a6e9785ab6,2026-10-15,5831,Look up the key only once in the callback parser's key() (#5831),1589.309,2938.557,8798.823,2767.872,3882.154,547.301,364.257,467.833,2395.851,744.716,1506.830,316.192,1623.771,1899.458,,,
251,0c4e7c103c,2026-10-15,5834,Make flatten() linear for ordered_json (#5834),1625.754,2936.203,8755.088,2793.081,3879.740,557.529,366.745,468.359,2418.388,746.210,1524.325,315.954,1614.677,1898.544,,,
252,0a4b3a84ee,2026-10-15,5836,"Speed up JSON pointer parsing, formatting, comparison and lookup (#5836)",1622.914,2915.901,8819.073,2783.990,3922.758,558.429,366.216,470.019,2427.606,747.168,1526.881,316.972,1625.611,1912.601,,,
253,6ba53e63dd,2026-10-15,5833,Speed up array-to-container from_json (#5833),1626.155,2920.747,8777.989,2782.870,3988.206,560.154,367.695,469.892,2427.262,749.301,1529.474,316.399,1631.810,1915.217,,,
254,ca7740fef2,2026-10-15,5837,Move elements when converting rvalue containers to JSON (#5837),1615.747,2928.778,8765.792,2773.062,3926.456,561.034,367.498,469.807,2424.344,748.423,1523.215,316.339,1624.374,1894.455,,,
255,4530d9681c,2026-10-15,5832,Fix quadratic parent updates for ordered_json with JSON_DIAGNOSTICS (#5832),1618.937,2911.378,8794.094,2763.191,3886.974,555.789,366.475,469.275,2415.231,746.755,1512.590,315.856,1618.226,1899.284,,,
256,91869983a0,2026-10-15,5840,Make the value lifecycle inline-friendly (#5840),1595.075,2832.274,8420.390,2690.050,3876.841,555.209,366.118,469.783,2424.335,747.931,1485.914,314.048,1549.787,1775.823,,,
257,6a27b9acb2,2026-10-15,5838,Construct remaining hot-path exceptions out of line so core functions inline (#5838),1589.535,2824.360,8466.755,2699.690,3888.990,557.917,364.879,471.601,2422.995,746.543,1498.371,314.978,1539.656,1797.752,,,
258,4f11512641,2026-10-15,5835,"Speed up container destruction, iterator access and diff() (#5835)",1515.750,2714.756,8639.213,2574.698,3805.860,561.827,366.793,469.680,2421.769,748.727,1383.744,317.248,1446.525,1705.789,,,
259,ed86019a21,2026-10-15,5839,Move binary reader error construction out of line (#5839),1507.907,2766.774,8597.870,2622.289,3767.638,553.026,362.644,468.482,2408.731,744.936,1362.080,324.833,1445.531,1703.216,,,
260,6261d1e432,2026-10-15,5842,Construct the JSON Patch exceptions out of line (#5842),1532.015,2756.867,8670.677,2617.989,3869.133,558.865,365.834,469.932,2435.279,750.295,1380.628,327.010,1453.340,1705.232,,,
261,ce28c722bc,2026-10-15,5815,Allow the same type for number_integer_t and number_unsigned_t (#5815),1533.045,2775.807,8543.755,2615.412,3776.721,553.127,365.866,471.174,2433.384,745.309,1372.372,328.405,1452.848,1716.649,,,
262,91b9ee2602,2026-10-15,5829,Update cppcheck to 1.5.2 (Cppcheck 2.20) and fix its new findings (#5829),1516.450,2748.961,8571.521,2599.870,3807.744,557.303,367.220,472.209,2421.389,743.889,1379.405,326.087,1451.926,1710.506,,,
263,dcb96e82fb,2026-10-15,5822,Escape characters below 0x60 from a table straight into the write buffer (#5822),1525.777,2734.963,8524.771,2588.289,3790.726,557.907,360.057,463.574,2430.626,743.382,1375.816,325.308,1439.947,1695.307,,,
264,b41228c227,2026-10-15,5843,Fix AppVeyor failures from the Zmij double writer (#5843),1497.922,2690.614,8406.906,2582.482,3726.195,548.374,352.932,459.663,2398.953,737.639,1347.507,322.827,1429.640,1682.775,,,
265,4da73dc5ff,2026-10-15,5858,Fix compiler warnings on develop from the API performance stack (#5858),1523.138,2731.825,8474.073,2593.149,3782.769,553.758,359.180,462.915,2380.246,739.049,1346.755,324.909,1441.408,1698.043,,,
266,5683f5e024,2026-10-15,5859,Define less_general() only without three-way comparison (#5859),1504.689,2739.172,8603.693,2605.159,3797.057,560.213,358.865,464.429,2423.456,742.207,1374.000,326.702,1447.488,1712.379,,,
267,cd6b428ef0,2026-10-16,5860,Fix CI failures on develop from the API performance stack (#5860),1510.160,2732.695,8564.510,2603.242,3810.518,556.015,362.409,466.047,2437.364,745.153,1377.439,325.753,1444.892,1699.255,,,
268,cc8334113c,2026-10-19,5866,Do not use Qt's keyword macros as identifiers (#5866),1498.858,2732.644,8535.328,2587.258,3787.993,548.267,362.607,464.487,2403.147,735.633,1368.831,323.997,1442.709,1686.963,,,
269,4da932f518,2026-10-19,5828,Make parsing from std::istream and FILE* fast (#5828),1499.289,2723.605,8397.787,2597.237,1956.330,553.182,363.501,458.898,2397.342,733.054,1362.816,320.346,1429.314,1698.294,,,
270,122d718330,2026-10-21,5620,"Add json_document and json_view: node index, parser, and document (#5620)",1520.651,2751.099,8527.135,2588.494,1994.466,560.384,362.257,461.917,2393.611,741.198,1362.167,328.620,1441.211,1691.238,230.700,389.375,976.277
271,43e97b629b,2026-10-21,5622,"Add element access, iteration, values, and JSON pointers to json_view (#5622)",1493.875,2687.307,8383.354,2567.078,1986.311,547.934,353.938,462.380,2400.331,737.098,1374.560,322.012,1445.504,1686.421,231.353,386.679,958.441
272,4c3a3eb5b5,2026-10-21,5624,Add dump() and comparisons to json_view (#5624),1502.926,2714.747,8522.161,2608.565,2001.856,552.014,359.510,462.656,2393.110,732.091,1366.524,324.313,1442.119,1682.564,228.836,393.082,976.976
273,3ff37ead75,2026-10-21,5628,Scan json_view strings with SIMD and index large objects (#5628),1514.580,2728.619,8406.562,2609.758,2041.176,556.017,357.330,462.573,2383.158,733.939,1368.057,324.391,1442.711,1700.884,177.833,367.806,950.071
274,823eee3b59,2026-10-21,5630,"Add editable json_documents: set, push_back, insert, and erase (#5630)",1498.134,2754.810,8537.062,2588.474,1994.441,556.670,353.931,463.646,2392.987,740.023,1357.930,324.129,1441.622,1698.022,181.404,376.470,962.253
275,4971200b54,2026-10-21,5632,Add images of json_documents: save() and load() (#5632),1494.231,2681.211,8425.834,2543.276,1984.849,548.146,354.762,460.440,2414.747,734.679,1363.841,321.349,1421.806,1670.134,177.777,368.631,949.292
276,4155e2938f,2026-10-21,5633,Write json_view's dump() without a call or conversion per token (#5633),1500.247,2712.357,8612.193,2597.211,2012.860,558.559,359.889,462.371,2412.896,739.048,1372.456,324.070,1441.546,1697.571,180.320,371.514,954.088
277,08d7fbb0a1,2026-10-21,5874,Read FILE* input with std::fgetc under MemorySanitizer (#5874),1543.124,2758.211,8565.730,2584.453,2046.255,558.522,358.865,464.542,2421.435,743.715,1374.005,324.687,1462.572,1700.819,180.714,372.601,965.361
278,0cbe95ffa2,2026-10-21,5824,"Speed up writing CBOR and MessagePack, above all integer arrays (#5824)",1501.550,2706.534,8707.120,2584.807,2039.728,551.688,360.692,466.024,2397.182,742.777,1361.847,201.488,1429.223,1682.436,178.641,371.038,946.389
279,bd5227c2ec,2026-10-21,5805,Fix silent wrong results for custom number types (#5805),1511.036,2733.325,8786.406,2588.906,2000.483,553.456,360.458,465.989,2398.381,743.338,1370.524,201.168,1444.051,1701.345,179.776,372.557,954.733
280,e13e976801,2026-10-21,5851,Accumulate number digits while scanning them (#5851),1501.737,2667.570,7762.365,2523.289,1987.518,545.368,359.336,462.056,2407.652,739.226,1368.104,200.632,1440.390,1688.117,178.721,374.278,956.353
281,5e13f834c1,2026-10-21,5852,Copy the text of float tokens only when a SAX handler asks for it (#5852),1512.318,2655.312,7314.354,2515.044,2019.288,547.993,362.038,463.788,2410.262,745.839,1364.898,208.969,1450.422,1713.902,179.198,371.996,968.699
282,e9970066c5,2026-10-21,5853,"Scan strings with SSE2, SSSE3, or NEON (#5853)",1488.705,2654.404,7339.589,2551.050,2015.716,486.719,341.381,475.591,2434.369,756.973,1376.754,208.797,1449.981,1706.044,182.358,379.153,968.355
283,fa37b952df,2026-10-21,5854,Match literals without a stack array and keep parser states in bytes (#5854),1471.894,2619.164,7285.000,2485.883,1949.380,471.534,347.785,475.287,2413.552,751.487,1374.254,207.522,1443.177,1699.611,181.643,377.971,977.268
284,52fecc1fab,2026-10-21,5855,Move object keys into the value when parsing (#5855),1392.599,2628.688,7362.562,2485.293,1882.663,471.968,339.711,473.663,2414.903,751.376,1319.857,200.185,1448.057,1705.675,179.410,371.865,963.306
285,6aefd8c662,2026-10-21,5878,Copy short printable-ASCII strings without starting the scanner (#5878),1399.384,2664.401,7232.557,2535.425,1922.431,470.185,320.230,418.440,2446.082,696.786,1317.889,201.955,1447.217,1701.135,180.860,376.217,968.215
286,7c26e99ac5,2026-10-21,5879,Copy ASCII strings in the view's dump with ensure_ascii (#5879),1361.839,2610.182,7187.115,2471.708,1853.592,464.274,313.821,414.316,2388.840,687.851,1318.253,200.399,1434.986,1697.487,178.601,368.595,947.799
287,3e031b06a5,2026-10-21,5876,"Use standard library helpers where available, with C++11 fallbacks (#5876)",1381.599,2592.122,7336.719,2499.994,1848.434,467.895,315.257,415.788,2430.769,692.250,1311.164,200.424,1444.303,1698.311,180.149,374.484,961.091
288,9bf531436f,2026-10-21,5861,"Speed up flatten(), unflatten(), diff() and patch() (#5861)",1379.301,2613.219,7170.433,2472.628,1853.035,467.161,315.217,412.303,2406.597,683.062,1298.512,198.681,1434.089,1682.912,177.511,368.116,947.255
289,9855db81f3,2026-10-22,5881,Silence macro-to-enum for the endianness macros (#5881),1369.150,2613.547,7209.787,2476.232,1841.347,467.780,316.011,416.187,2415.504,686.920,1304.263,200.868,1441.243,1694.603,178.739,368.123,948.579
290,aa0b371f7c,2026-10-23,5884,"Faster std::istream input: inline get-area path, binary reads, unbuffered streambufs (#5884)",1375.030,2569.362,7218.375,2484.425,1743.476,470.240,319.245,403.750,2436.034,679.759,1319.508,201.531,1443.354,1698.057,180.133,372.206,946.488
291,86d5c56c54,2026-10-23,5886,"Speed up flatten(), unflatten(), diff() and patch() further (#5886)",1386.169,2622.331,7281.551,2495.923,1700.794,472.317,317.282,403.416,2409.097,682.507,1320.319,200.963,1444.908,1697.678,179.138,375.751,954.573
292,dec0e9b749,2026-10-23,5883,"Write strings, scalars and indentation in dump() with fewer calls (#5883)",1383.235,2621.847,7151.412,2491.644,1732.469,473.034,211.016,288.685,2276.953,416.068,1318.490,200.574,1452.099,1701.256,180.064,372.324,960.583
293,6fa14d8f95,2026-10-23,5885,Write binary formats through reserved sink space and number runs (#5885),1366.956,2600.914,7176.994,2465.343,1691.333,462.351,210.662,285.259,2301.553,417.589,1324.173,136.601,1429.240,1687.947,179.319,368.881,962.518
294,0b924f5375,2026-10-23,5887,Split and print JSON pointers in one pass (#5887),1377.526,2597.394,7242.688,2464.445,1739.841,466.382,211.716,288.202,2319.771,418.288,1318.592,138.744,1441.983,1706.639,179.684,372.087,976.078
295,e9c4fe3cdf,2026-10-24,5889,json_view: indented and ensure_ascii dumps through the fast writer (#5889),1393.007,2627.226,7248.287,2491.551,1769.642,469.976,211.665,291.327,2305.655,420.168,1319.431,139.577,1457.965,1712.927,182.274,377.741,983.284
296,dd7686a269,2026-10-24,5888,"json_view: faster reading, indexing and C-stream parsing (#5888)",1382.444,2607.026,7161.365,2472.635,1701.277,468.438,209.963,287.564,2276.329,415.511,1311.194,137.875,1439.700,1696.646,177.624,367.131,977.802
297,9c50bdd140,2026-10-24,5882,Make the DOM parser cheaper per container and per member (#5882),1392.673,2461.082,6068.625,2334.706,1696.950,475.550,209.313,291.776,2300.287,416.349,1317.581,138.194,1441.209,1707.720,178.751,367.339,978.031
298,01139dc192,2026-10-24,5905,Silence an Infer false positive in json_view materialize (#5905),1381.470,2463.013,6078.010,2335.216,1709.088,475.718,211.023,291.212,2275.302,418.098,1320.441,137.572,1443.434,1696.436,175.969,365.658,975.272
299,fe5e401870,2026-10-25,5901,Consolidate duplicated detail helpers and bodies (#5891) (#5901),1395.881,2462.765,6066.698,2327.708,1706.745,474.184,212.683,289.321,2283.842,417.657,1314.153,138.084,1442.796,1696.588,177.144,364.092,961.847
300,3eae5680d6,2026-10-25,5902,"from_json: number-first dispatch for arithmetic types, loop for std::array (#5902)",1397.343,2477.060,6080.864,2340.781,1711.774,481.523,213.618,289.360,2289.503,417.517,1313.541,138.271,1440.822,1695.785,178.731,367.293,983.555
301,2a56afc714,2026-10-25,5916,Fix VS 2015 build of the DOM parser (#5882) (#5916),1373.929,2476.139,6056.797,2341.890,1749.167,482.883,215.107,290.053,2292.495,417.441,1320.640,137.868,1445.227,1702.064,177.912,367.669,984.794
302,d6431a9104,2026-10-26,5918,Throw out_of_range.411 for JSON Patch add into a null parent (#5917) (#5918),1371.635,2445.905,6017.636,2314.178,1696.447,478.134,210.996,287.397,2278.718,414.186,1291.197,137.374,1436.212,1682.197,175.790,361.130,962.070
303,81d66291c5,2026-10-26,5358,Create objects for pointer tokens that cannot be array indices (#5358),1382.909,2465.649,6052.114,2332.556,1711.721,479.927,213.359,289.913,2289.412,417.201,1311.695,137.572,1437.168,1696.302,177.495,367.526,963.924
304,d5da84249f,2026-10-26,5927,"Skip CBOR tags in front of map keys, validate indefinite text chunks, fix CBOR docs (#5927)",1374.553,2476.464,6076.834,2346.075,1744.224,483.375,211.423,291.148,2287.800,420.247,1320.015,137.369,1449.068,1704.785,177.459,365.004,963.908
305,0c3570d44a,2026-10-26,5929,Validate the UBJSON/BJData container type marker for count 0; fix UBJSON docs (#5929),1381.462,2462.578,6055.183,2329.970,1713.086,484.962,210.683,290.024,2260.371,416.895,1319.093,137.782,1453.495,1706.801,177.031,361.025,962.952
306,dc768a7d5d,2026-10-26,5930,Fix BSON binary subtype 0x02 and check the declared document size earlier (#5930),1386.856,2463.400,6054.255,2337.105,1746.441,485.425,214.508,290.954,2314.702,418.769,1325.164,139.255,1452.125,1718.313,179.005,367.327,977.054
307,60107eda3f,2026-10-26,5931,"Read BJData ND-arrays of float16, restrict ND-array char to 0..127, correct BJData docs (#5931)",1389.051,2464.457,6049.084,2336.727,1710.473,483.159,213.007,288.990,2285.073,417.663,1317.537,137.893,1443.301,1697.126,178.706,364.051,962.202
308,731f1b5bfb,2026-10-26,5919,"json_view: view_mode enum instead of bool Editable, node_kind for node::kind (#5919)",1381.664,2428.529,5978.713,2333.485,1746.571,479.163,211.036,288.957,2281.592,416.990,1308.904,137.486,1447.665,1691.427,175.453,363.704,963.371
309,4cdfa6d0f4,2026-10-26,5920,json_view: no save() and load() on big-endian targets (#5920),1390.901,2477.841,6102.474,2337.925,1777.003,485.382,214.373,290.946,2303.147,421.178,1321.976,139.942,1446.726,1704.816,179.928,367.825,976.532
310,5a2819c940,2026-10-26,5921,json_view: one SIMD macro set with the library (#5921),1393.409,2479.841,6073.011,2350.336,1785.087,485.658,214.651,292.044,2304.448,418.026,1326.212,138.942,1468.981,1719.505,179.174,368.704,982.764
311,e5fe4ebdd2,2026-10-26,5922,json_view: from_json() of the macros reads views directly (#5922),1384.612,2467.078,6056.328,2337.309,1742.751,482.554,213.389,289.543,2299.118,417.521,1309.673,138.237,1448.628,1704.550,177.925,365.163,984.351
312,9e67bfa115,2026-10-26,5923,json_view: the library's std conversions read views directly (#5923),1395.103,2482.517,6066.604,2350.538,1751.603,482.504,213.399,290.185,2306.188,420.406,1317.415,138.730,1444.367,1708.720,178.016,369.111,975.875
313,21ec9bd801,2026-10-27,5915,json_view: fewer allocations when parsing small documents (#5915),1388.282,2469.118,6066.495,2340.391,1744.901,478.745,214.934,292.970,2309.264,422.842,1323.237,138.541,1454.151,1707.314,178.058,366.514,958.110
314,2bb2feeef4,2026-10-27,5942,"Fix the red CI on develop (json_view pointer tokens, bson, from_json tests, Infer, IWYU) (#5942)",1391.981,2468.266,6068.495,2335.707,1751.527,482.908,214.285,291.291,2300.453,417.876,1328.089,138.010,1454.934,1701.845,178.250,367.182,964.917
315,78a0687147,2026-10-27,5940,Strong exception guarantee for operator[](json_pointer) (#5940),1379.414,2467.492,6109.136,2335.309,1723.090,480.260,216.197,292.075,2313.798,415.444,1314.530,138.314,1449.629,1698.792,177.628,364.844,965.314
316,091c10d4a5,2026-10-28,5936,Fix self-aliasing in json_pointer::operator/= and patch_inplace (#5936),1389.195,2462.409,6052.125,2321.091,1722.944,473.064,214.421,290.952,2279.997,416.589,1315.370,138.531,1437.996,1683.844,176.596,363.105,952.473
317,54f6b3ef06,2026-10-28,5945,json_view: source positions in materialize() with JSON_DIAGNOSTIC_POSITIONS (#5945),1417.895,2496.591,6325.787,2377.105,1737.749,478.133,213.209,293.150,2304.971,422.648,1348.357,139.793,1490.556,1735.758,178.445,368.380,990.587
318,0115bb47b3,2026-10-30,5965,Name the source and license of adapted code in the file comments (#5965),1378.289,2456.731,6043.011,2330.780,1711.965,470.960,212.371,290.798,2298.443,419.433,1323.072,137.982,1441.316,1690.457,176.197,363.182,977.928
319,0b91f9ddd8,2026-10-30,5926,json_view: check_utf8 skips well-formed runs with the parser's string scan (#5926),1400.777,2488.449,6137.021,2359.856,1747.026,473.449,213.226,290.736,2320.524,420.950,1325.039,139.324,1452.907,1703.426,177.699,364.500,988.981
320,ea03d601af,2026-10-30,5890,json_view: comparison without temporaries and a faster image float check (#5890),1388.958,2477.531,6127.547,2357.032,1781.238,477.111,216.144,293.938,2340.267,424.058,1337.149,139.387,1459.923,1723.919,,,
321,755bb16d7a,2026-10-30,5966,Fix the red CI on develop: remove the duplicate is_editable in basic_json_view (#5966),1411.867,2497.560,6085.938,2326.880,1726.740,480.376,212.294,292.134,2312.521,420.608,1325.345,138.544,1465.640,1744.928,177.785,367.385,992.034
322,4fe670b5f4,2026-10-31,5969,json_view: decode chains of unicode escapes in a loop (#5969),1390.866,2466.769,6026.817,2328.995,1736.168,475.935,212.530,291.166,2284.708,418.661,1323.436,137.513,1495.099,1736.832,176.566,365.541,963.794
323,9c349b1d7c,2026-10-31,5964,Write integers of 17 to 20 digits eight digits at a time in dump() (#5964),1390.500,2469.332,6079.698,2359.276,1718.121,470.647,209.615,289.143,2300.836,419.976,1331.637,138.488,1450.106,1703.483,176.731,365.394,953.483
324,3fd3e0fdaa,2026-11-01,5908,json_view: dump and read canada.json-style floats faster (batched float decisions) (#5908),1366.359,2456.409,6058.422,2329.066,1713.347,470.784,209.895,289.318,2294.111,417.490,1319.403,138.100,1435.053,1698.647,176.006,363.191,954.196
325,76001c6b4c,2026-11-01,5968,"BSON reader: find C-string terminators 8 bytes at a time, skip array element names (#5968)",1408.222,2488.159,6124.287,2363.039,1759.751,477.558,216.880,294.011,2317.898,420.892,1345.718,138.602,1460.432,1713.978,179.721,370.205,970.525
326,1a018577cc,2026-11-01,5970,json_view: accept() checks the text without writing an index (#5970),1427.279,2506.345,6160.916,2368.009,1765.595,480.552,214.060,293.093,2341.368,419.303,1330.990,138.625,1463.731,1724.021,181.150,373.171,964.666
327,162eda2574,2026-11-01,5971,json_view: skip the digits of a fraction 16 bytes at a time (SSE2) (#5971),1404.191,2474.144,6049.006,2363.726,1711.013,471.608,211.613,289.736,2290.230,418.673,1322.822,138.556,1441.219,1697.559,178.814,370.881,956.959
328,6c3ab966d3,2026-11-01,5975,CBOR reader: read runs of scalar array elements in one loop (#5975),1385.800,2466.923,6050.480,2325.901,1725.552,474.248,210.034,289.350,2296.399,418.689,1327.626,137.722,1440.577,1698.622,178.627,367.797,953.174
329,aecbef3949,2026-11-01,5976,Binary readers: swap the bytes of floats with a single byteswap (#5976),1393.659,2479.298,6092.110,2337.421,1718.218,472.539,211.337,289.638,2307.378,417.589,1324.038,137.341,1447.860,1701.387,179.160,369.448,956.324
330,edf8d17601,2026-11-01,5980,MessagePack reader: read runs of scalar array elements in one loop (#5980),1422.081,2486.171,6157.302,2360.678,1733.503,477.472,211.189,289.309,2307.724,419.448,1334.857,138.914,1449.345,1721.126,180.127,369.693,967.370
331,fb515ddc34,2026-11-01,5981,UBJSON/BJData readers: read optimized arrays of numbers in one loop (#5981),1387.633,2470.528,6067.657,2345.342,1721.303,476.141,212.198,288.466,2292.649,416.597,1324.486,139.598,1441.019,1705.957,179.190,367.903,959.677
332,517444b504,2026-11-01,5978,accept() checks strings without copying them (#5978),1385.026,2453.809,5975.744,2322.357,1711.222,475.186,210.256,288.348,2282.444,415.256,1321.012,138.726,1434.772,1698.120,178.106,365.411,976.135
333,9742edc294,2026-11-01,5979,"BSON writer: write to_bson(j) in one pass, with sizes written afterwards (#5979)",1418.816,2514.802,6091.854,2380.269,1772.646,474.067,211.598,290.653,2316.886,421.043,1346.324,139.213,1469.659,1754.493,180.269,372.201,982.753
334,f022e3c59c,2026-11-01,5982,Binary readers and writers: faster UTF-8 checks of strings (#5982),1399.836,2474.703,6060.781,2341.409,1707.583,468.692,209.824,290.357,2290.034,418.739,1312.448,138.360,1458.779,1707.575,178.911,369.303,968.200
335,ddc34f546a,2026-11-01,5974,json_view: exceptions name the path and the bytes of the value (#5974),1394.263,2489.906,6017.599,2345.632,1728.593,473.672,210.364,289.980,2306.608,420.394,1327.301,138.827,1448.846,1707.037,177.406,368.436,978.755
336,b2674a4a2f,2026-11-01,5984,BSON reader: check array element names in place in strict mode (#5984),1392.028,2460.989,5975.355,2357.154,1726.291,472.389,209.872,289.219,2301.092,417.632,1309.441,138.779,1438.270,1709.943,177.580,366.368,973.214
337,76dbe8f9c9,2026-11-02,6009,"Fix the red CI on develop: Visual Studio 2017 build of the BSON writer, Valgrind timeouts (#6009)",1387.812,2461.244,5975.843,2323.693,1713.572,469.489,209.863,289.058,2291.892,415.935,1306.729,138.322,1447.714,1694.220,177.698,363.994,972.289
338,03d408aafa,2026-11-02,6003,JSON_DIAGNOSTIC_POSITIONS: comparing a value-initialized iterator throws instead of crashing (#6003),1385.014,2455.146,5981.995,2380.493,1732.039,466.575,209.272,289.474,2295.226,416.844,1301.454,138.016,1445.840,1703.494,176.691,365.416,967.929
339,66e2eeeec0,2026-11-02,6000,Do not construct the base class when destroying a container (#6000),1403.795,2457.426,6001.495,2323.510,1718.268,471.022,210.474,288.385,2308.462,417.187,1313.263,138.770,1437.867,1705.586,179.168,363.523,966.701
340,bdc737db6d,2026-11-02,5999,json_view: dump() without StringType::capacity() (#5999),1378.656,2452.954,6020.464,2339.908,1724.630,470.774,211.638,288.939,2303.773,418.311,1312.024,139.010,1446.709,1704.406,177.291,363.859,966.602
341,494a74c242,2026-11-02,5996,"insert(): strong guarantee for single elements, basic guarantee for the rest (#5996)",1390.153,2478.991,6032.084,2342.171,1727.040,469.799,213.660,291.104,2307.193,419.623,1329.285,139.000,1461.294,1718.750,178.995,366.898,974.652
342,bfe69c73c2,2026-11-02,5992,"json_view: get<T>() of a boolean throws for the exact number types, as basic_json does (#5992)",1387.497,2452.207,6023.042,2335.261,1720.938,471.966,212.162,288.851,2310.949,417.260,1315.155,137.821,1448.762,1710.153,175.990,366.239,970.052
343,ff0bdfdef3,2026-11-02,5990,Keep the byte range in exceptions about the root value (#5990),1386.358,2469.197,6037.812,2344.775,1768.382,479.285,214.375,290.939,2329.486,421.838,1332.654,138.666,1455.905,1720.376,178.637,368.500,972.955
344,1d69ef9ab4,2026-11-02,5997,"Raise line coverage to 99.9 %: fix the measurement, remove unreachable code, add tests (#5997)",1404.481,2456.447,6166.942,2338.226,1749.981,478.338,211.609,289.387,2304.532,419.095,1321.195,140.055,1460.574,1706.842,179.067,369.688,982.029
345,5c4f585ac2,2026-11-02,6004,"Lexer, parser, stream adapter, SAX: remove checks that invariants make dead (#6004)",1386.586,2468.772,6188.662,2373.328,1775.098,483.139,211.476,291.250,2315.874,420.854,1321.718,138.268,1464.254,1709.146,180.316,367.994,965.010
346,100f676b3e,2026-11-02,6012,Restore the two commits of #6005 that the stack merge dropped (fixes the build of develop) (#6012),1369.597,2437.356,6122.282,2305.291,1691.485,472.217,208.716,288.666,2291.034,416.120,1300.906,137.896,1439.300,1688.769,176.641,366.389,972.368
347,590b622d48,2026-11-02,5991,parse(): propagate std::bad_alloc instead of crashing on a half-constructed member (#5991),1377.480,2425.219,6113.438,2306.435,1716.697,474.315,209.052,288.883,2292.776,417.291,1305.336,137.989,1453.044,1704.638,179.096,368.072,978.198
348,6d5581c4e8,2026-11-02,6008,CBOR/MessagePack readers: leave one-element arrays to the general path (#6008),1400.456,2439.163,6140.448,2328.635,1743.039,480.725,212.470,295.268,2348.332,427.202,1340.319,139.121,1489.584,1736.380,184.949,371.567,995.731
349,b18b6fc7e6,2026-11-02,6013,Build the parser's syntax error prefix with one concat() (#6013),1370.175,2435.337,6098.834,2320.728,1726.256,472.914,210.817,289.786,2292.841,419.186,1306.593,139.277,1481.709,1714.543,177.065,366.270,971.330
350,07876e2292,2026-11-02,6015,json_view: a value that is not found has no bytes in its exception context (#6015),1361.297,2435.980,6080.718,2305.853,1707.733,474.621,210.382,291.568,2337.276,424.783,1329.556,139.590,1450.506,1690.804,178.472,366.370,977.807
351,baba5db36f,2026-11-02,6016,"Fix the MSVC and GCC builds of develop (C4127, -Weffc++) (#6016)",1381.280,2440.908,6116.068,2303.611,1713.472,476.121,210.492,290.105,2319.878,420.598,1318.037,139.554,1471.388,1729.097,177.078,369.621,959.145
352,candidate,,,develop + open pull requests,1392.967,2469.204,6110.380,2348.760,1730.819,474.089,212.339,290.760,2284.428,420.179,1320.938,137.755,1441.341,1697.486,176.758,364.547,955.117
1 index commit date pr subject parse_twitter parse_citm parse_canada parse_citm_compact parse_twitter_ifstream accept_twitter dump_twitter dump_citm dump_canada dump4_citm from_cbor_twitter to_cbor_twitter copy_destroy_citm equal_citm view_parse_twitter view_parse_citm view_parse_canada
2 0 55f93686c0 2025-04-11 Merge branch 'release/3.12.0' 3571.487 8219.609 17049.073 4366.792 3846.006 2394.213 1441.213 1375.446 7510.989 1917.809 3463.281 695.524 1643.327 1956.891
3 1 1705bfe914 2025-04-11 4727 :bookmark: set version to 3.12.0 (#4727) 3589.331 8245.422 17079.250 4422.711 3894.787 2397.597 1440.546 1377.745 7514.698 1922.371 3498.997 695.559 1655.240 1967.301
4 2 4cca3b9cb2 2025-04-13 4738 Fix warning and add emscripten CI step (#4738) 3559.657 8195.105 17066.291 4373.011 3794.269 2388.900 1419.182 1355.724 7420.703 1912.038 3468.667 664.214 1631.610 1939.475
5 3 96c1b52f1c 2025-04-15 4742 Fix conversion to std::optional (#4742) 3573.838 8157.276 16993.208 4383.656 3858.927 2395.092 1438.169 1372.208 7497.776 1925.481 3482.185 667.895 1633.619 1946.687
6 4 88c92e605c 2025-04-16 4744 Fix compilation failure and warnings with NVHPC (#4744) 3563.149 8039.911 16922.739 4381.927 3768.560 2385.086 1407.564 1345.578 7370.063 1897.474 3462.010 662.955 1623.286 1925.804
7 5 c67d538274 2025-04-17 4749 Fix C4702 warning and extend MSVC CI job (#4749) 3585.422 8251.057 17050.448 4400.542 3896.586 2390.655 1440.391 1371.722 7453.474 1921.277 3478.523 667.911 1636.206 1939.531
8 6 756ca22ec5 2025-04-23 4736 Provide fallback for missing `char8_t` support (#4736) 3559.146 8139.703 17085.114 4387.658 3856.745 2392.849 1424.997 1370.599 7477.537 1907.661 3484.427 665.541 1634.156 1957.401
9 7 6b9199382b 2025-04-27 4763 Add missing header (#4763) 3541.323 8077.761 17011.636 4359.183 3842.380 2396.686 1421.116 1363.737 7431.375 1902.909 3474.250 664.442 1625.644 1934.732
10 8 3b02afb9d9 2025-04-28 4760 Specialize char_traits for std::byte to fix from_msgpack (fixes #4756) (#4760) 3583.070 8198.146 17134.698 4381.743 3899.872 2409.185 1440.233 1380.810 7504.838 1921.781 3500.125 666.078 1657.207 1966.036
11 9 eef76c200e 2025-04-28 4764 Make library work with C++20 modules (#4764) 3528.529 8080.458 16936.656 4330.570 3764.287 2363.848 1407.851 1358.079 7356.239 1897.423 3455.287 665.194 1632.255 1937.675
12 10 dff2b4756c 2025-04-29 4765 fix: BJData size calculation overflow (#4765) 3553.706 8141.375 17047.511 4360.144 3797.070 2389.756 1417.737 1364.718 7454.313 1921.962 3479.878 666.456 1644.760 1944.696
13 11 9110918cf8 2025-05-04 4748 Fix typos (#4748) 3563.682 8176.427 17239.354 4398.055 3891.669 2399.782 1441.669 1387.133 7516.073 1925.323 3483.271 669.348 1647.760 1957.747
14 12 46e7cd3dc2 2025-05-16 4775 Replace deprecated std::is_trivial in C++26 (#4775) 3565.242 8195.396 17135.646 4373.479 3851.604 2392.258 1418.425 1370.958 7464.854 1909.844 3485.046 665.606 1643.155 1952.329
15 13 828c891427 2025-05-16 4786 Extend type_name() to invalid type (#4786) 3549.573 8103.761 17066.198 4359.911 3804.849 2389.121 1428.584 1366.405 7424.838 1914.434 3452.497 667.452 1632.750 1928.324
16 14 4b17f90f65 2025-05-22 4609 Add `ignore_trailing_commas` option (#4609) 3544.662 8132.052 16997.375 4344.592 3825.765 2382.755 1408.435 1367.468 7460.448 1924.522 3434.062 733.089 1631.356 1891.572
17 15 b19f058465 2025-06-01 4802 Encode infinity and NaN as float for MsgPack and CBOR (#4802) 3550.020 8126.438 17350.885 4327.596 3825.419 2389.356 1409.422 1376.649 7363.802 1921.226 3441.081 683.190 1624.144 1886.388
18 16 cf16c5ab9f 2025-06-02 4805 Use binary_t::value_type (#4805) 3551.735 8143.521 17153.291 4309.477 3829.229 2387.640 1428.550 1385.585 7415.271 1932.347 3425.838 657.735 1631.586 1888.954
19 17 d70e46bc65 2025-06-25 4830 :bug: add missing header to input_adapters.hpp (#4830) 3546.448 8157.469 17062.364 4335.300 3805.221 2382.796 1422.863 1382.581 7411.401 1928.676 3433.190 691.842 1632.972 1892.453
20 18 30d27df61c 2025-07-31 4871 Fix CI (#4871) 3570.015 8150.859 17070.625 4330.078 3806.505 2400.329 1434.947 1381.065 7425.718 1931.556 3429.632 656.545 1633.515 1892.916
21 19 efcf9efb4f 2025-08-02 4873 Fixes #4854 Explicitly handle nullptr in sax_parse (#4873) 3520.381 8050.719 16883.042 4331.820 3861.906 2368.069 1408.435 1375.954 7363.651 1898.466 3432.992 653.988 1634.141 1894.948
22 20 4106af8d92 2025-08-20 4896 :rotating_light: suppress cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator (#4896) 3540.599 8175.265 17010.438 4345.182 3866.833 2393.935 1435.100 1389.496 7453.724 1945.791 3433.169 657.446 1638.434 1900.360
23 21 a63795caf1 2025-10-22 4791 :rotating_light: avoid deprecation warning (#4791) 3550.057 8174.646 16983.177 4363.521 3888.336 2393.305 1423.434 1376.334 7469.407 1936.013 3447.279 666.706 1645.354 1903.707
24 22 1cc56b2dcd 2025-10-23 4957 Address CWG issue 2521 (#4957) 3557.396 8119.651 17072.730 4351.881 3834.739 2386.097 1442.100 1393.245 7474.463 1932.315 3446.883 660.187 1638.983 1896.000
25 23 54be9b04f0 2025-10-23 4960 :page_facing_up: update REUSE (#4960) 3554.625 8098.287 17115.219 4324.578 3809.950 2390.791 1424.488 1376.715 7422.828 1913.208 3424.693 659.030 1623.405 1892.756
26 24 29913ca760 2025-10-25 4963 Add char8_t* overload for _json and _json_pointer (#4963) 3544.899 8169.203 17007.844 4353.594 3797.630 2392.108 1423.032 1375.216 7349.787 1909.897 3428.771 655.625 1635.273 1891.018
27 25 515d994acb 2026-01-01 5044 :page_facing_up: adjust year (#5044) 3524.610 8059.521 16949.416 4313.508 3773.750 2364.742 1410.427 1372.988 7382.438 1915.502 3403.159 643.968 1618.972 1884.213
28 26 8f75700141 2026-01-11 4958 support types convertible to string_view as JSON keys (#4958) 3546.757 8142.599 17103.386 4327.739 3825.990 2388.540 1420.515 1379.309 7413.062 1924.540 3433.677 658.266 1628.079 1890.759
29 27 457bc283ff 2026-01-12 5039 fix(cbor): reject overflowing negative integers (#5039) 3508.883 8077.291 16930.011 4305.982 3785.698 2378.693 1425.526 1366.111 7407.042 1929.142 3478.909 657.722 1636.304 1944.681
30 28 e3014f162a 2026-01-13 5052 Fix conversion to std::optional (#5052) 3547.995 8140.052 17010.031 4321.914 3797.807 2385.856 1430.414 1386.202 7407.260 1930.403 3462.213 657.829 1629.579 1932.066
31 29 5ed07097fa 2026-01-13 5050 Fix -Wtautological-constant-out-of-range-compare in serializer (#5050) 3544.136 8180.208 17033.209 4339.591 3799.779 2391.940 1427.870 1387.871 7368.765 1922.321 3454.938 659.367 1630.707 1959.722
32 30 25f48639c7 2026-01-23 5016 Reference tuple from json (#5016) 3563.180 8209.037 17030.969 4388.675 3895.086 2392.088 1430.666 1393.853 7528.567 1934.347 3481.351 677.234 1645.418 1957.591
33 31 f8eee1bb79 2026-02-07 5071 Annotate unreachable comment-scanner switch paths to satisfy C26819 (#5071) 3508.000 8128.750 16958.959 4315.235 3797.237 2371.963 1425.146 1374.867 7453.381 1930.211 3456.508 658.568 1629.188 1909.736
34 32 fd17b0889e 2026-05-08 5139 Remove nullptr safety check from sax_parse functions (#5139) 3544.101 8033.021 16963.292 4334.102 3800.736 2382.583 1419.050 1361.745 7357.073 1907.153 3429.315 657.041 1618.815 1937.829
35 33 62f3b41b30 2026-05-08 5090 fix: treat single-element brace-init as copy/move instead of wrapping in array (#5074) (#5090) 3550.323 8168.713 17060.031 4349.417 3794.110 2380.583 1416.822 1361.182 7369.651 1897.717 3466.731 659.297 1631.463 1941.905
36 34 4fad446897 2026-05-10 5162 docs: add IDs to @requirement tags to fix Doxygen autolinking (#5162) 3545.440 8031.891 17069.448 4324.698 3802.862 2383.513 1422.768 1384.602 7325.776 1917.606 3469.787 659.011 1631.296 1940.370
37 35 a0a4e7cc0b 2026-05-13 5152 Add front methods to json_pointers (implements #4889) (#5152) 3582.898 8215.010 17034.448 4345.515 3891.513 2396.572 1432.733 1395.714 7554.119 1934.008 3484.859 659.298 1642.314 1957.356
38 36 93e49decbd 2026-05-14 5167 Fix incomplete-type error in set_parents with ordered_json (#5167) 3555.224 8147.771 17017.073 4320.846 3831.318 2386.750 1435.840 1385.578 7436.864 1927.483 3466.508 658.409 1632.724 1939.528
39 37 7192763f15 2026-05-14 5163 Fix compile error when using nlohmann ordered_map with WITH_DEFAULT macros (#5163) 3520.675 8039.145 16892.291 4303.448 3769.198 2363.337 1410.030 1364.679 7380.797 1913.285 3437.278 660.130 1630.738 1943.235
40 38 5a05627b1f 2026-05-14 5169 :rotating_light: fix warning (#5169) 3600.555 8160.854 16979.031 4324.070 3887.823 2389.157 1430.983 1387.106 7509.984 1912.601 3473.713 663.279 1652.982 1958.774
41 39 bb5404bb86 2026-05-15 5164 Fix GCC C++20 modules compilation #5103 (#5164) 3543.823 8120.266 17015.395 4349.300 3794.880 2364.178 1414.408 1374.548 7484.218 1920.495 3444.266 699.326 1626.241 1954.688
42 40 b1bb9fce0c 2026-05-15 3929 Fix for printing long doubles bug in dump_float (#3929) 3549.378 8089.891 16934.927 4313.310 3824.802 2386.958 1412.164 1385.425 7417.869 1930.513 3461.151 651.557 1618.735 1944.450
43 41 cba5dc0ed8 2026-05-16 4563 New macros for the named JSON convertor generation (#4563) 3544.657 8168.182 16990.886 4327.688 3806.963 2370.975 1421.629 1390.206 7454.151 1919.284 3452.456 677.413 1623.622 1941.921
44 42 47202c804a 2026-05-18 5171 Add missing overload to ordered_map::find (#5171) 3527.542 8168.312 17141.989 4409.456 3887.378 2397.007 1428.765 1387.033 7495.604 1935.710 3485.088 660.155 1648.977 1951.430
45 43 58cfecf7f7 2026-05-18 5151 Serialize enum (#5151) 3521.302 8100.104 16805.489 4288.463 3763.971 2381.494 1408.713 1383.059 7328.261 1915.202 3440.372 648.726 1617.661 1922.608
46 44 584e6b1cfb 2026-05-22 5187 Fix: update() parent pointers not updated after recursive merge with JSON_DIAGNOSTICS (#5187) 3550.639 8083.463 17055.198 4326.833 3804.257 2381.519 1432.039 1381.986 7377.844 1915.159 3460.750 656.873 1631.527 1940.953
47 45 02dfbea39d 2026-06-17 5209 added explicit instantiations of 'has_from_json' and 'has_to_json' for std_fs::path (#5209) 3552.209 8215.474 17167.760 4338.404 3845.144 2398.026 1425.012 1387.629 7458.614 1931.388 3475.343 658.183 1644.329 1958.324
48 46 fc1df0b7db 2026-06-23 5172 :recycle: remove unnecessary if (#5172) 3562.088 8175.531 17044.042 4336.583 3863.651 2404.695 1425.872 1389.434 7523.855 1914.128 3481.000 653.259 1639.515 1957.649
49 47 c5b2b26fdc 2026-06-29 5217 :memo: fix docs (#5217) 3526.825 8052.307 17000.011 4343.963 3793.412 2388.194 1416.706 1374.177 7361.646 1904.008 3463.919 658.322 1627.765 1921.887
50 48 b7566c6293 2026-06-30 5161 Harden JSON_HAS_RANGES detection for incomplete C++20 ranges implementations (#5161) 3538.995 8071.787 17120.751 4318.797 3772.445 2384.008 1421.440 1385.239 7419.292 1898.929 3431.466 647.948 1602.258 1928.644
51 49 adf78d3a76 2026-06-30 5215 Minor: unique_ptr template resolution workaround for MSVC (#5215) 3550.380 8138.026 17036.802 4366.062 3842.430 2389.536 1426.658 1385.609 7428.787 1915.233 3467.188 658.332 1636.158 1942.556
52 50 272411c5e6 2026-06-30 5218 Overwork project infrastructure (#5218) 3547.487 8087.250 16962.198 4341.969 3793.831 2387.509 1420.888 1381.072 7450.078 1930.003 3466.193 659.676 1631.329 1943.043
53 51 730b57775d 2026-07-01 5222 :bug: avoid assertion in patch (#5222) 3539.912 8169.771 17027.229 4345.151 3790.753 2376.552 1421.263 1386.717 7399.985 1923.237 3455.722 653.609 1630.914 1934.028
54 52 ca49ab6123 2026-07-02 5223 Extend value to arrays when using JSON pointers (#5223) 3550.341 8113.787 16951.313 4346.805 3793.097 2391.224 1409.695 1380.075 7374.073 1926.401 3458.438 659.382 1629.387 1941.306
55 53 8d7e0046f4 2026-07-02 5224 Add std::format and fmt support (#5224) 3546.935 8170.406 16968.927 4346.906 3814.956 2387.612 1424.861 1386.542 7350.765 1900.376 3461.177 662.476 1633.858 1930.434
56 54 31dd15b258 2026-07-02 5221 Fix ambiguous static_cast (#5221) 3551.945 8213.000 17131.271 4373.620 3845.763 2393.074 1438.633 1385.769 7471.146 1927.804 3486.568 662.015 1631.810 1958.901
57 55 eed1587000 2026-07-05 5234 Reconstruct lexer diagnostics lazily for seekable input (#120) (#5234) 3145.909 5311.094 15381.843 4292.961 3851.260 1966.833 1422.598 1365.461 7443.276 1920.467 3467.060 702.832 1637.587 1905.758
58 56 83c87cb9e0 2026-07-05 5233 Read binary strings/blobs in bulk chunks with a memcpy fast path (#5233) 3141.867 5259.485 15454.959 4326.664 3797.198 1987.623 1406.492 1372.765 7424.729 1899.726 2363.895 667.502 1630.097 1888.392
59 57 acf076a677 2026-07-06 5238 Fix ADL leak of nlohmann::detail through basic_json's default base class (#5238) 3152.153 5277.073 15291.407 4338.828 3839.331 1995.524 1429.960 1365.917 7456.776 1907.928 2398.016 670.257 1627.590 1897.997
60 58 c05c5e229b 2026-07-07 5241 Add missing copyright notices to SBOM (#5241) 3147.485 5268.865 15319.584 4321.823 3796.972 1981.167 1432.689 1371.264 7465.416 1918.083 2388.154 667.119 1630.745 1891.583
61 59 366f3d26e5 2026-07-08 5235 Replace snprintf with a branch-free writer for \uXXXX escapes (#5235) 3127.641 5272.302 15425.239 4340.459 3850.357 1997.957 1459.603 1356.461 7509.703 1899.916 2366.966 668.383 1624.981 1889.145
62 60 f8e99e856c 2026-07-09 5248 Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907) (#5248) 3132.099 5226.375 15164.510 4301.901 3769.651 1967.647 1456.759 1365.810 7530.724 1908.635 2381.610 683.815 1616.699 1879.795
63 61 855f511db4 2026-07-09 5250 Fix stale Clang -Weverything suppression comments; drop -Wno-missing-noreturn (#5250) 3126.792 5208.338 15352.520 4293.596 3800.544 1969.497 1458.601 1329.851 7372.849 1876.404 2368.894 662.173 1603.881 1874.673
64 62 d0a43141ea 2026-07-09 5253 Fix #3868: Remove operator!= to enable P2468R2 rewritten candidate synthesis (#5253) 3165.182 5270.458 15479.031 4302.729 3845.646 1989.231 1474.135 1343.312 7443.282 1887.909 2392.523 670.395 1634.871 1894.474
65 63 b630f5e9c7 2026-07-10 5260 Fix container input_adapter SFINAE for lvalue-only ADL begin/end (#5260) 3128.117 5263.807 15375.677 4330.544 3819.953 1982.196 1454.088 1339.062 7364.683 1877.699 2361.482 666.486 1616.514 1920.626
66 64 c60217e801 2026-07-11 5205 fix: support constructing json from C++20 range views (#4916) (#5205) 3117.539 5206.552 15308.166 4320.513 3798.713 1983.458 1447.072 1350.950 7357.213 1875.632 2340.731 662.905 1633.357 1934.261
67 65 fe2bcc080f 2026-07-11 5266 Custom BinaryType direct assignment (#5266) 3174.528 5284.562 15383.645 4328.120 3895.086 1996.913 1478.427 1355.569 7512.115 1899.236 2398.490 672.118 1642.910 1967.660
68 66 ca76c37650 2026-07-11 5265 Add iterator+sentinel tests and docs for binary deserializers (#5265) 3134.265 5218.021 15352.521 4306.284 3791.612 1967.824 1451.953 1358.685 7508.828 1891.697 2377.848 665.474 1631.495 1934.907
69 67 c197feff81 2026-07-12 5268 Extend memcpy fast path to sized sentinels (e.g. std::counted_iterator) (#5268) 3116.271 5207.146 15415.771 4272.443 3815.851 1984.966 1451.103 1341.093 7328.037 1865.385 2383.169 664.494 1617.967 1915.428
70 68 1c5a953de5 2026-07-19 5276 reject unpaired UTF-16 surrogates in wide-string input (#5276) 3155.360 5299.631 15419.812 4302.089 3853.104 1987.259 1468.653 1349.665 7549.432 1911.365 2457.555 680.311 1653.282 1955.673
71 69 3565f40229 2026-07-20 5284 reject negative UBJSON/BJData string length (#5284) 3170.456 5301.698 15404.416 4351.226 3893.594 1997.034 1470.907 1358.245 7491.480 1909.601 2401.384 671.260 1639.865 1963.899
72 70 9a3ebb9456 2026-07-23 5287 validate BSON document size against the bytes read (#5287) 3157.646 5264.062 15305.271 4338.672 3839.643 1987.196 1461.356 1351.630 7444.791 1890.626 2398.503 665.262 1655.798 1930.268
73 71 8ec98e2c9e 2026-07-27 5313 adding cleanups to bson writer (#5313) 3150.448 5268.948 15445.927 4308.612 3805.005 1989.643 1466.348 1349.591 7326.453 1895.842 2393.278 708.164 1644.025 1946.652
74 72 2e23687092 2026-07-28 5314 to_bson() silently emits corrupt documents when a length exceeds INT32_MAX (#5314) 3146.534 5254.547 15445.250 4304.008 3798.620 1986.260 1459.735 1345.534 7517.651 1903.996 2395.155 674.344 1644.565 1952.682
75 73 868506dcc0 2026-07-30 5335 Fix CBOR half-float assertion bounds (#5335) 3167.086 5267.068 15397.979 4351.011 3883.135 2003.345 1468.939 1360.483 7455.230 1909.055 2406.305 679.942 1643.646 1945.639
76 74 dd24e2dffd 2026-07-30 5332 check all BSON reads and add an EOF check for booleans (#5332) 3138.315 5284.833 15399.166 4310.513 3847.630 1980.682 1464.104 1344.108 7445.146 1901.512 2400.532 670.850 1635.196 1900.946
77 75 fd72ecfc8c 2026-07-31 5301 validate ndarray element types in write_bjdata_ndarray (#5301) 3164.662 5262.141 15399.010 4287.271 3849.318 1988.186 1460.688 1353.767 7458.380 1893.669 2398.485 668.466 1644.018 1921.615
78 76 bc48951128 2026-07-31 5323 Fix UBJSON high-precision floating-point overflow handling (#5323) 3155.628 5289.864 15474.375 4324.253 3888.966 2015.068 1477.846 1354.622 7480.730 1905.566 2415.428 668.997 1641.776 1911.819
79 77 d94cbd99dc 2026-07-31 5274 reject CBOR array/map length equal to the indefinite-length marker (#5274) 3144.041 5272.193 15466.980 4338.735 3848.849 1999.231 1459.129 1358.119 7507.307 1901.807 2394.972 667.016 1635.960 1899.878
80 78 2222d386c9 2026-07-31 5339 fix: check CBOR tagged subtype reads (#5339) 3095.768 5137.792 15064.146 4258.977 3755.229 1965.900 1454.890 1338.066 7399.068 1883.624 2358.193 660.190 1618.172 1939.713
81 79 585929bff9 2026-08-03 5289 Fix Clang deprecation warning for json_pointer operator== with ordered_json (#5289) 3142.341 5259.360 15258.271 4275.479 3807.672 1969.704 1453.688 1337.633 7451.037 1879.447 2364.966 661.560 1635.617 1945.709
82 80 5f121d8c50 2026-08-03 5336 avoid sign extension in char_traits<signed char>::to_int_type (#5336) 3145.000 5264.880 15441.521 4269.632 3796.781 1983.497 1440.810 1325.232 7427.750 1880.047 2361.899 663.772 1621.595 1912.378
83 81 68f0722a19 2026-08-03 5342 remove discarded array from parent object in end_array (#5342) 3161.273 5269.907 15312.469 4335.433 3840.510 1995.965 1465.745 1355.934 7474.901 1895.483 2401.197 657.397 1634.791 1901.902
84 82 dca9d49a33 2026-08-05 5348 reject out-of-range code points in UTF-32 wide-string input (#5348) 3119.753 5210.979 15209.260 4273.984 3799.034 1995.297 1459.456 1342.982 7431.646 1891.478 2370.364 653.618 1633.585 1882.753
85 83 9a091d2b82 2026-08-05 5362 Do not write BJData ndarrays whose size overflows std::size_t (#5362) 3137.381 5257.312 15286.084 4308.500 3805.325 1995.140 1468.138 1354.729 7510.088 1893.036 2384.577 659.394 1628.260 1890.245
86 84 d5647e6a3b 2026-08-05 5355 Resolve the TODO(niels) in get_ubjson_string (#5355) 3121.278 5249.927 15246.011 4292.737 3800.490 1967.087 1443.762 1333.226 7368.953 1862.131 2347.852 644.647 1623.909 1889.958
87 85 bacdabd176 2026-08-05 5361 Fix start_pos() for strings containing escape sequences (#5361) 3114.653 5251.619 15253.907 4331.818 3786.156 1960.676 1442.388 1330.247 7354.724 1863.306 2351.588 650.781 1623.543 1886.671
88 86 1c136a66c4 2026-08-06 5363 Move the CBOR doc block to the function it describes (#5363) 3124.274 5209.615 15411.897 4293.320 3812.156 1982.854 1457.653 1345.680 7422.343 1884.848 2387.050 656.076 1627.620 1878.737
89 87 6285225fd0 2026-08-12 5211 Fix integer comparison bug (#5211) 3159.557 5291.323 15395.395 4329.836 3867.200 1989.476 1456.052 1359.795 7526.860 1879.642 2396.137 659.077 1638.176 1900.416
90 88 b5378e8deb 2026-08-19 5331 Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 (#5331) 3172.476 5239.812 15479.917 4295.539 3871.289 2003.439 1473.447 1343.742 7516.875 1888.412 2400.572 645.588 1641.621 1886.531
91 89 2f025f401e 2026-08-25 5380 Throw other_error.502 when UBJSON use_type is set without use_size (#5380) 3155.873 5190.312 15144.406 4286.388 3793.805 1968.199 1442.240 1340.929 7373.610 1860.543 2370.570 648.906 1631.207 1893.750
92 90 35705d79d8 2026-08-28 5414 Fix update(merge_objects=true) throwing on primitive-to-object merge (#5414) 3169.029 5252.578 15387.292 4340.690 3893.646 1979.616 1472.286 1361.543 7491.302 1903.909 2401.404 659.396 1641.697 1912.409
93 91 137a40b9aa 2026-09-05 5459 Compare integers with floats exactly instead of widening the integer (#5459) 3134.229 5259.349 15404.541 4300.146 3846.646 1992.155 1467.919 1351.774 7467.146 1887.255 2391.467 660.347 1631.735 1891.751
94 92 3c875683a5 2026-09-05 5461 Make diff() linear when an array shrinks (#5461) 3141.068 5259.000 15271.166 4319.659 3797.088 1983.450 1455.354 1354.676 7444.860 1891.687 2389.333 657.163 1632.998 1887.016
95 93 09b6b6b5ba 2026-09-05 5455 Fix to_bjdata() emitting unparsable output when _ArraySize_ is not an array (#5455) 3161.542 5253.047 15311.718 4291.388 3834.264 1992.744 1472.685 1357.680 7409.479 1889.287 2389.501 698.680 1628.237 1888.705
96 94 faa35cc647 2026-09-09 5484 Skip integer conversion in accept()/SAX validation when the value is unused (#5484) 3103.654 5222.453 15458.573 4215.765 3804.320 1935.161 1468.660 1353.499 7452.052 1883.191 2383.524 654.441 1631.700 1885.664
97 95 6d86cc0f6b 2026-09-09 5490 Speed up whitespace skipping in the lexer (#5490) 3181.328 5276.318 15307.312 4262.771 3877.401 1977.062 1465.196 1356.119 7594.177 1906.814 2388.615 684.926 1636.950 1893.526
98 96 c05347dd54 2026-09-09 5475 Undefine the four JSON_HEDLEY_* macros that leak after including json.hpp (#5475) 3147.932 5156.625 15347.990 4217.505 3871.812 1982.807 1458.787 1354.934 7639.328 1879.823 2370.342 674.625 1637.257 1903.903
99 97 d6660cf718 2026-09-09 5485 Route hand-rolled diagnostic pragmas through Hedley (#5485) 3116.151 5215.531 15257.499 4189.979 3835.023 1974.111 1459.363 1342.996 7553.802 1887.698 2379.999 669.934 1635.350 1877.492
100 98 c9477ccf91 2026-09-09 5496 Throw when JSON Patch remove's target path resolves through a primitive or null parent (#5496) 3138.841 5258.401 15315.417 4201.008 3874.682 1967.630 1446.393 1335.060 7542.708 1870.111 2390.141 668.484 1634.138 1886.981
101 99 8c38e270b5 2026-09-09 5497 Reject JSON Patch move when from is a proper prefix of path (#5497) 3183.820 5280.000 15346.969 4222.164 3839.596 1970.753 1470.428 1351.838 7515.344 1895.809 2389.731 673.696 1633.247 1889.546
102 100 a316738cfa 2026-09-09 5471 Add JSON_HEDLEY_WARN_UNUSED_RESULT to the current accept() overloads (#5471) 3175.891 5281.302 15397.062 4240.576 3934.333 1981.765 1475.890 1353.387 7625.104 1896.181 2401.097 669.729 1646.133 1895.638
103 101 c9f1d2d646 2026-09-09 5477 Broaden JSON_HEDLEY_WARN_UNUSED_RESULT coverage to pure query functions (#5477) 3171.706 5286.880 15430.844 4264.242 3880.943 1979.990 1472.289 1357.283 7569.854 1904.026 2407.487 671.673 1641.521 1889.053
104 102 8e26b9d4b3 2026-09-09 5495 Make contains(json_pointer) return false instead of throwing on unrepresentable array-index tokens (#5495) 3163.789 5240.755 15337.698 4226.154 3880.956 1971.912 1475.322 1357.125 7632.281 1904.060 2401.190 678.863 1638.371 1903.385
105 103 b17c272f46 2026-09-09 5472 Reserve capacity in from_json() object conversion when the target container supports it (#5472) 3152.899 5257.645 15401.000 4210.846 3885.123 1989.159 1476.637 1359.851 7639.396 1898.981 2408.243 670.075 1633.528 1894.086
106 104 3e2de32226 2026-09-10 5516 Remove unused iomanip include (#5516) 3141.349 5253.657 15364.074 4203.969 3847.620 1968.422 1455.035 1352.754 7582.494 1882.051 2371.814 663.504 1630.172 1870.223
107 105 d69fb8654d 2026-09-10 5501 Return the parsed value by move from from_cbor() and friends (#5501) 3133.485 5231.662 15309.926 4183.200 3835.662 1971.125 1462.447 1349.563 7479.136 1904.202 1595.991 661.519 1630.278 1883.994
108 106 4a93aa4e2f 2026-09-10 5283 Speed up parsing of contiguous input (numbers, strings, UTF-8) (#5283) 1963.879 4221.308 11609.531 3278.497 3857.880 927.779 1483.726 1357.793 7483.343 1906.916 1481.419 676.438 1643.746 1895.551
109 107 bfb07786cd 2026-09-10 5473 Fix to_bjdata() silently truncating out-of-range _ArrayData_ elements (#5473) 1941.894 4204.971 11726.688 3264.055 3808.784 923.797 1453.071 1351.760 7458.125 1891.470 1473.508 662.164 1633.043 1888.548
110 108 ff80ed3295 2026-09-11 5285 Speed up dump(), and keep it from overflowing the stack (#5285) 1939.289 4175.541 11781.291 3233.302 3816.101 914.071 441.200 540.473 6895.041 852.214 1478.197 656.635 1632.675 1885.303
111 109 da42a627dc 2026-09-11 5449 Stop dump() from heap-allocating its output adapter per call (#5449) 1937.658 4200.966 11639.198 3235.493 3827.695 909.901 448.948 537.008 6909.036 839.027 1479.968 659.210 1643.621 1878.065
112 110 1dc1d09fc6 2026-09-11 5457 Do not search a container for the value the callback rejected (#5457) 1937.459 4140.078 11576.803 3271.838 3845.193 924.316 450.148 539.031 6848.776 844.624 1470.333 671.563 1645.624 1900.347
113 111 fae364db24 2026-09-11 5458 Move the scanned string into the value instead of copying it (#5458) 1986.146 4110.787 11757.157 3150.932 3830.550 918.517 442.629 539.606 6913.104 843.920 1417.037 655.259 1628.224 1892.991
114 112 dd50f0eb16 2026-09-11 5502 Stop CBOR indefinite-length strings from recursing per chunk (#5502) 1987.853 4033.182 11613.834 3116.378 3841.164 915.943 442.366 539.480 6864.130 836.458 1431.035 656.146 1599.574 1885.858
115 113 4bb2de8cc5 2026-09-11 5503 Reject a nested BJData ndarray dimension vector where it is read (#5503) 1981.298 4086.276 11569.240 3141.539 3829.870 923.087 444.038 539.863 6800.724 835.434 1429.637 655.448 1628.999 1879.300
116 114 44f8ec30e9 2026-09-11 5504 Bound UBJSON optimized arrays of a valueless type (#5504) 2005.265 4092.265 11730.198 3130.635 3863.992 925.033 448.222 542.323 6893.078 849.901 1437.855 662.171 1638.306 1896.324
117 115 0dd8ca9023 2026-09-11 5505 Read MessagePack containers without recursing per nesting level (#5505) 2019.983 4105.305 11862.979 3142.581 3891.601 927.092 447.942 543.936 6939.963 845.634 1442.889 656.578 1637.512 1897.815
118 116 91ab3e81f5 2026-09-11 5506 Read CBOR containers and tags without recursing per nesting level (#5506) 1986.334 4039.961 11554.094 3118.761 3783.101 912.504 440.410 534.894 6831.943 834.661 1439.061 655.287 1615.619 1869.912
119 117 a14619b354 2026-09-11 5507 Read UBJSON and BJData containers without recursing per nesting level (#5507) 2011.959 4095.868 11782.688 3135.264 3873.604 926.014 447.638 541.304 6905.838 846.051 1468.512 664.161 1629.083 1898.772
120 118 0452641c18 2026-09-11 5508 Read BSON documents without recursing per nesting level (#5508) 1974.160 4043.887 11662.938 3095.011 3832.744 916.007 439.914 534.149 6904.453 835.615 1450.792 648.298 1616.917 1874.133
121 119 aa391dc0a5 2026-09-11 5520 Fix two develop CI regressions: dump() nodiscard warning and binary-reader const-correctness (#5520) 2003.010 4068.010 11771.364 3137.266 3825.247 924.668 442.416 539.478 6847.083 841.996 1460.659 649.378 1633.738 1885.897
122 120 a50c2537eb 2026-09-12 5476 Reserve capped array capacity in json_sax_dom_parser::start_array() for definite-length binary arrays (#5476) 1986.488 4063.883 11588.333 3077.995 3827.479 908.419 440.959 539.114 6806.177 833.555 1452.851 662.422 1627.995 1915.388
123 121 c0b2878a44 2026-09-13 5493 Swap diagnostic positions in basic_json::swap() (#5493) 2010.881 4081.057 11734.730 3130.919 3882.258 925.490 450.092 542.953 6925.188 848.486 1480.051 698.636 1643.508 1933.941
124 122 1da2f68992 2026-09-14 5522 Only reserve array capacity if the array type supports it (#5522) 1972.122 4048.622 11775.062 3107.938 3803.528 909.385 441.204 535.885 6793.927 842.843 1446.330 658.787 1619.239 1899.164
125 123 6487678bc5 2026-09-15 5464 Fix swap(array_t&)/swap(object_t&) to update parent pointers under JSON_DIAGNOSTICS (#5464) 2023.028 4116.169 11737.438 3165.172 3893.266 924.912 448.959 541.529 6970.438 852.039 1483.231 689.631 1635.240 1937.356
126 124 c72f37a40d 2026-09-15 5443 Support custom object/array types and improve template parameter handling (#5443) 2001.617 4076.547 11666.583 3109.756 3918.206 923.197 450.592 542.266 6901.703 846.558 1468.284 660.116 1641.586 1905.840
127 125 502e9d66f6 2026-09-16 5479 Fix to_bjdata() emitting the Draft-3-only 'B' marker in default Draft-2 mode (#5479) 1970.935 4018.060 11445.500 3079.409 3809.050 910.459 444.217 539.291 6851.407 833.755 1444.697 698.040 1626.601 1889.024
128 126 c41152e620 2026-09-16 5494 Fall back to plain-object encoding when to_bjdata()'s _ArrayType_ annotation is not a string (#5494) 1979.481 4054.688 11734.292 3085.542 3819.351 916.992 445.126 539.870 6853.005 833.190 1457.166 665.391 1629.586 1888.734
129 127 e564136c22 2026-09-22 5465 Make diff() account for member order in ordered_json objects (#5465) 1970.519 4063.744 11605.198 3087.497 3848.867 915.695 447.051 539.711 6835.172 841.402 1452.004 664.560 1640.751 1890.473
130 128 e485441123 2026-09-22 5466 Restore a duplicate key's prior value when the callback rejects its new value (#5466) 2012.920 4099.265 11796.895 3156.818 3913.812 931.464 451.403 541.419 6981.041 846.536 1469.521 704.138 1633.327 1905.709
131 129 a2b19d6158 2026-09-22 5467 Honor allow_exceptions=false for excessive array/object size (out_of_range.408) (#5467) 1996.478 4084.422 11734.208 3129.099 3850.854 923.499 446.555 539.379 6949.427 842.029 1453.166 694.200 1631.133 1888.865
132 130 d2c1a6a272 2026-09-22 5468 Reject array insert(pos, first, last) iterators not pointing into an array (#5468) 1983.767 4066.651 11618.667 3128.505 3848.427 914.900 447.603 541.973 6915.265 844.307 1458.762 677.699 1638.789 1892.443
133 131 0b20b7e622 2026-09-22 5469 Reject MessagePack/BSON binary subtypes that don't fit their wire format (#5469) 2010.548 4097.476 11681.218 3121.010 3866.146 925.619 448.533 540.786 6957.000 843.349 1463.518 658.302 1630.857 1902.522
134 132 1054b2097e 2026-09-23 5286 Speed up binary writing: value-type output sink + byte-swap number encoding (#5286) 1989.739 4101.393 12034.438 3157.240 3853.987 910.115 449.084 555.970 6884.386 864.526 1471.905 656.635 1661.806 1926.233
135 133 ed513715a8 2026-09-24 5534 Document that a NUL byte in the input is treated as end of input (#5534) 2016.236 4104.763 11906.323 3141.138 3936.240 916.611 455.397 562.053 6987.917 871.110 1475.622 657.877 1676.934 1936.557
136 134 56b3ee566c 2026-09-24 5389 Fix stack overflow when copying a deeply nested value (#5387) (#5389) 1998.356 4051.206 11660.865 3101.107 3834.672 910.072 452.943 544.464 6908.974 849.212 1460.691 638.644 1650.749 1914.423
137 135 918da64657 2026-09-24 5542 Keep BJData ndarray annotations that would not survive a round trip as objects (#5542) 2003.009 4042.969 11517.375 3095.122 3815.360 908.444 448.415 539.423 6911.041 840.044 1449.543 671.530 1651.709 1908.408
138 136 8699de3064 2026-09-24 5555 Stop allocating the BJData excluded-marker list per container (#5555) 2001.718 4071.333 11686.427 3122.065 3796.757 900.895 447.123 539.918 6860.765 844.752 1444.435 646.608 1644.943 1879.295
139 137 2e91641de2 2026-09-24 5544 Test JSON_BRACE_INIT_COPY_SEMANTICS for real, and fix one-element tuples under it (#5544) 2004.785 4083.914 11662.270 3119.602 3917.914 922.465 454.869 547.631 6987.234 853.010 1469.612 649.946 1672.246 1913.098
140 138 7c90ec2323 2026-09-24 5546 Hash deeply nested values without recursing per nesting level (#5546) 1952.912 4071.159 11594.927 3117.497 3793.052 900.729 444.245 539.787 6854.406 841.264 1457.530 643.139 1638.578 1890.482
141 139 4daca40d7b 2026-09-24 5547 Merge deeply nested objects without recursing per nesting level (#5547) 2008.226 4104.399 11619.542 3148.604 3918.175 921.207 457.191 547.553 6942.265 855.352 1464.974 651.924 1665.232 1915.869
142 140 01b53c8c15 2026-09-25 5552 Keep JSON_DIAGNOSTICS parent pointers of ordered_json members after erase() and update() (#5552) 1979.354 4061.378 11603.480 3098.586 3875.258 919.125 455.911 546.269 6940.026 849.511 1461.751 648.841 1660.978 1917.254
143 141 abbe52d6de 2026-09-25 5344 Add JSON_PRECISE_STREAM_POSITION to leave the character that terminates a number in the stream (#5344) 2001.170 4081.617 11653.531 3131.331 3876.208 915.153 453.436 546.720 6971.864 848.900 1463.182 647.946 1662.943 1906.246
144 142 02dd3e67f2 2026-09-25 5390 Fix stack overflow and exponential runtime when comparing nested values (#5390) 1987.861 4074.039 11596.000 3161.284 3901.497 919.541 447.553 543.948 6910.162 845.668 1455.759 664.224 1652.074 1930.575
145 143 465407f3ce 2026-09-25 2818 Improve error message for const fields (#2818) 1975.274 4118.565 11863.448 3130.541 3880.764 910.767 452.904 545.363 6906.890 843.118 1459.728 645.770 1654.265 1934.900
146 144 632a5812a8 2026-09-25 5272 Support zero-member types in NLOHMANN_DEFINE_TYPE_* macros (#4041) (#5272) 1963.323 4021.526 11747.959 3102.006 3784.896 904.545 444.355 543.748 6840.604 841.416 1438.306 639.223 1649.816 1930.274
147 145 d19f7f5dce 2026-09-25 5185 Fix BSON conformance issue (#5185) 1958.606 4048.536 11541.011 3086.805 3817.875 900.452 446.001 544.071 6824.323 837.078 1971.245 641.271 1651.209 1934.647
148 146 c60a0bc336 2026-09-25 5573 Allocate the deep copy's key scratch space with the provided allocator (#5573) 1965.216 4021.459 11630.855 3074.078 3807.258 902.782 444.394 542.562 6919.969 840.942 1975.668 645.827 1637.429 1918.607
149 147 1e44262091 2026-09-25 5560 Make JSON_STRICT_NUL_HANDLING part of the ABI tag (#5560) 1961.862 4069.617 11594.083 3117.500 3817.758 909.186 448.820 544.420 6845.802 844.016 1977.909 645.864 1651.269 1937.217
150 148 95e9a5931c 2026-09-25 5553 Write BSON in linear time, without recursing per nesting level (#5553) 1965.832 4033.394 11589.364 3120.422 3792.091 905.110 446.984 543.328 6794.244 844.943 1991.659 640.188 1647.675 1928.562
151 149 fe4a544c7e 2026-09-27 5515 handled when size exceed uint32 (#5515) 1998.244 4047.208 11755.209 3091.776 3815.000 908.733 447.990 546.295 6903.084 850.946 1993.351 645.487 1654.343 1933.385
152 150 4fa95d9810 2026-09-27 5583 Remove unreachable branches from the binary writer (#5583) 1983.323 4038.331 11666.480 3092.841 3844.935 910.149 449.697 541.110 6840.583 830.604 1979.750 653.542 1650.670 1928.883
153 151 6178982b8d 2026-09-27 5582 Compare unordered objects by key below the nesting bound (#5582) 1971.706 4073.498 11600.646 3132.700 3830.323 910.231 448.982 538.812 6836.770 846.149 2007.607 657.180 1653.089 1934.675
154 152 f7972970a4 2026-09-27 5584 Throw instead of writing MessagePack lengths beyond UINT32_MAX (#5584) 1969.417 4013.021 11602.447 3083.552 3842.495 904.223 447.444 542.170 6862.735 839.628 2000.766 655.034 1653.006 1939.922
155 153 6bd106893a 2026-09-27 5559 Fix CBOR tag handling in cbor_tag_handler_t::store for non-binary items (#5559) 1969.250 4034.693 11691.500 3119.171 3827.860 916.053 455.026 542.577 6886.360 839.718 2012.919 653.031 1651.090 1931.698
156 154 1e101ecac1 2026-09-27 2998 Add BON8 support (#2998) 1975.804 4082.375 11658.542 3192.828 3758.141 907.029 444.920 556.470 6844.698 849.276 1977.153 649.181 1645.306 1920.836
157 155 9e1a09eec0 2026-09-28 5594 Name the key type when rejecting non-string CBOR/MessagePack map keys (#5594) 2006.582 4151.784 11788.532 3156.156 3845.052 915.647 454.027 557.846 6814.282 864.094 2021.072 654.095 1663.051 1947.078
158 156 fc03b9912e 2026-09-28 5597 Look up the locale decimal point at conversion time, not lexer construction (#5597) 2020.431 4172.916 12716.958 3196.958 3909.774 910.001 449.314 547.334 6900.968 852.306 2048.019 665.843 1696.937 1982.586
159 157 5b9ffae8bb 2026-09-30 5616 Move the float conversion chain out of the lexer (#5616) 1992.332 4167.328 12638.573 3212.515 3842.885 906.649 446.941 539.674 6952.672 839.042 2021.057 695.813 1684.689 1967.216
160 158 d268eaa693 2026-09-30 5617 Convert floats with Eisel-Lemire when std::from_chars is unavailable (#5617) 1987.608 4086.125 11507.062 3170.013 3830.425 898.856 445.077 542.854 6919.568 839.210 2021.918 666.925 1701.466 1951.211
161 159 65af260117 2026-09-30 5609 Move instead of deep-copy ordered_json values when an object grows (#5609) 1998.981 4134.057 11592.855 3192.779 3863.005 904.702 446.575 539.685 6850.886 840.845 2035.646 680.331 1682.755 1968.744
162 160 6a8a7735ed 2026-09-30 5614 Do not throw in contains() for an empty array reference token (#5614) 2008.447 4144.024 11612.176 3165.468 3842.060 905.045 443.941 539.755 6846.042 846.248 1998.713 669.752 1684.717 1953.487
163 161 0050d0f7a4 2026-09-30 5637 Share one nesting depth limit between all bounded descents (#5637) 2021.078 4170.581 11589.886 3224.963 3937.021 906.411 448.033 541.177 6911.391 848.641 2040.978 670.005 1703.593 1984.639
164 162 68beba727c 2026-09-30 5679 Fix from_json() for enums with underlying type bool (#5679) 1986.468 4139.033 11632.833 3201.351 3798.006 888.464 438.471 535.903 6843.110 836.030 1996.109 685.053 1672.430 1940.598
165 163 fc4c9c3446 2026-09-30 5680 Fix clear() to also reset the subtype of a binary value (#5680) 1972.561 4094.867 11540.157 3155.722 3833.925 893.243 445.764 539.739 6848.562 843.068 2016.293 664.788 1685.759 1965.342
166 164 678fd3017b 2026-09-30 5681 Fix element path for map/unordered_map JSON_DIAGNOSTICS errors (#5681) 2014.783 4164.471 11563.614 3219.865 3891.917 892.727 445.945 542.044 6900.807 844.422 2034.323 669.901 1688.051 1981.601
167 165 6d7845d207 2026-09-30 5683 Fix deprecated json_pointer/string operator== warning in value() (#5683) 1965.197 4105.789 11501.364 3157.544 3800.289 898.122 445.399 539.685 6900.433 834.541 2000.133 652.354 1670.945 1960.876
168 166 42f89e3130 2026-09-30 5684 Let to_json(std::optional<T>) propagate exceptions from T's to_json (#5684) 2016.899 4156.430 11476.489 3216.315 3895.245 908.714 444.300 541.764 6923.422 839.459 2018.934 672.859 1689.306 1987.428
169 167 6218aa212b 2026-09-30 5687 Throw std::length_error for operator[](SIZE_MAX) instead of corrupting the array (#5687) 1989.158 4149.156 11547.229 3193.015 3845.187 905.308 446.389 541.290 6853.266 843.028 2037.245 661.213 1681.390 1966.649
170 168 1151826508 2026-09-30 5691 Take diff()'s fast path unless the object type reorders members (#5691) 1991.280 4147.341 11570.312 3171.182 3847.333 904.510 441.250 539.803 6885.776 836.303 2018.693 665.307 1685.990 1970.057
171 169 e444a66276 2026-09-30 5693 Copy values before inserting an initializer list into an array (#5693) 2000.774 4175.507 11546.979 3189.357 3841.169 897.455 442.384 539.493 6839.688 836.213 2014.519 667.390 1685.418 1968.991
172 170 bfea6f36d3 2026-09-30 5694 Fix to_msgpack() reading the inactive number union member (#5694) 1997.465 4144.279 11549.781 3224.287 3855.120 899.475 441.995 539.924 6903.776 839.550 2019.396 664.487 1688.249 1954.211
173 171 5b11a0282c 2026-09-30 5697 Exchange the CustomBaseClass subobject in basic_json::swap() (#5697) 1987.983 4074.349 11483.114 3174.632 3841.604 893.256 438.279 535.885 6866.641 834.328 1996.396 660.828 1676.300 1936.210
174 172 44a88d85be 2026-09-30 5698 Fix NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json message (#5698) 1972.237 4125.945 11373.917 3158.716 3810.039 890.097 438.075 534.577 6867.432 842.045 2028.150 664.206 1681.353 1936.231
175 173 bfe0f32d71 2026-09-30 5699 Fix std::terminate and null pointer access in input_stream_adapter (#5699) 2014.371 4159.779 11667.416 3200.425 3876.135 911.716 448.788 543.198 6932.657 852.397 2056.197 668.764 1699.573 1984.479
176 174 4bb1b14b06 2026-09-30 5702 Trim the compiler-appended NUL from wide/UTF string literals too (#5702) 1979.723 4105.685 11603.562 3180.932 3846.698 906.188 443.969 534.534 6837.479 840.588 2006.043 654.851 1672.289 1965.408
177 175 5bd766aa50 2026-09-30 5703 Move to_bson's binary subtype check into calc_bson_sizes (#5703) 1999.606 4183.386 11588.646 3192.771 3844.425 900.169 446.795 541.406 6888.114 847.107 2022.637 663.480 1686.702 1974.777
178 176 6ae17630a4 2026-09-30 5705 Reject integral keys for contains(), find(), and count() at compile time (#5705) 2000.405 4157.120 11551.656 3197.417 3891.646 903.558 448.544 541.553 6914.203 848.561 2042.578 663.661 1691.910 1974.341
179 177 7fd6895788 2026-09-30 5706 Hide a discarded container's content from the parser callback (#5706) 1971.987 4075.362 11463.219 3164.909 3797.453 889.534 443.974 535.026 6857.323 835.793 2025.343 651.970 1687.670 1951.428
180 178 66877675b1 2026-09-30 5719 Check the iterator range for binary values in basic_json(first, last) (#5719) 1970.369 4104.886 11534.635 3168.601 3796.291 897.271 444.655 538.917 6826.990 842.445 2016.962 650.099 1673.940 1953.693
181 179 2ea6d8c127 2026-09-30 5720 Require the found key to equal the looked-up key when comparing objects (#5720) 2015.556 4188.886 11567.125 3251.890 3863.818 903.970 448.691 540.422 6912.255 843.774 2044.479 653.832 1676.634 1951.959
182 180 67435c9c7e 2026-09-30 5721 Give a deep copy its type only after its container exists (#5721) 1994.257 4160.658 11600.553 3218.367 3880.128 900.769 449.260 541.607 6899.448 841.635 2043.909 666.759 1694.646 1974.861
183 181 6fc0d501f3 2026-09-30 5610 Move the user-defined string literals to <nlohmann/json_literals.hpp> and add JSON_NO_AUTOMATIC_UDLS (#5610) 2021.715 4187.888 11647.594 3209.388 3925.060 911.591 450.961 544.303 6975.265 845.109 2049.853 670.295 1697.019 1987.428
184 182 fdcc569eee 2026-09-30 5692 Use only documented StringType members in json_pointer (#5692) 1965.264 4147.273 11378.188 3159.364 3787.758 889.399 447.397 535.062 6809.698 835.116 2015.202 656.241 1689.072 1955.238
185 183 6a073dbae4 2026-09-30 5695 Give operator>> a strong exception-safety guarantee (#5695) 2010.979 4211.982 11698.218 3205.401 3897.172 898.499 445.961 545.225 6898.870 847.042 2051.316 664.716 1706.401 1981.247
186 184 3b6ae43c53 2026-09-30 5598 Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions (#5598) 2025.122 4195.468 11682.199 3204.529 3924.068 904.766 448.209 544.669 7041.276 849.103 2047.488 665.592 1695.987 1984.755
187 185 7d7055ec50 2026-09-30 5723 Fix stack overflow converting deep values between specializations (#5723) 1985.310 4117.099 11457.052 3157.591 3832.175 895.910 442.225 535.237 6864.375 833.653 2001.760 679.826 1674.819 1956.998
188 186 35802e78d6 2026-09-30 5735 Remove dead Makefile targets; document macro_builder; tidy serve_header (#5735) 2004.498 4163.065 11590.594 3184.810 3902.229 906.494 447.394 539.542 6923.969 845.596 2044.457 666.187 1692.019 1977.030
189 187 c261578431 2026-09-30 5730 Deduplicate binary reader/writer helpers and fix stale comments (#5730) 1968.723 4154.789 11441.718 3160.367 3870.578 889.545 443.139 535.314 6850.886 837.281 2024.650 660.842 1691.628 1978.000
190 188 1d675cdb46 2026-09-30 5733 Fix CI jobs that check less than they claim; move arm64 to GitHub (#5733) 1995.704 4206.185 11691.125 3227.622 3966.104 909.748 449.770 541.566 6951.938 852.506 2009.592 663.701 1686.265 1983.285
191 189 a32f61eb98 2026-09-30 5678 Fix update() and merge_patch() when the argument is *this or one of its members (#5678) 2014.810 4157.101 11636.135 3210.326 3924.659 899.344 448.133 541.371 6913.401 841.487 2038.263 667.515 1697.503 1980.686
192 190 18dd5663b0 2026-10-01 5548 Diff deeply nested values without recursing per nesting level (#5548) 1990.931 4152.500 11469.697 3204.740 3985.593 903.248 448.981 540.974 6929.740 847.493 2040.504 665.352 1698.903 1981.438
193 191 3926fcaac3 2026-10-01 5729 Deduplicate serializer dump code; fix stale includes, docs, and lint (#5729) 1999.556 4178.489 11581.000 3208.657 3876.755 891.669 452.445 538.525 6893.078 846.721 2042.010 662.154 1689.653 1975.503
194 192 cff0a61369 2026-10-01 5731 Share DOM SAX position handling; fix stale parser and lexer comments (#5731) 2017.231 4112.604 11588.291 3157.047 3890.343 902.329 458.713 539.539 7020.568 847.995 2073.873 654.562 1696.823 1978.381
195 193 e400780533 2026-10-01 5745 Re-amalgamate single_include (#5745) 1980.338 4100.659 11418.854 3166.896 3835.432 885.298 452.886 538.053 6888.203 824.666 2031.410 650.846 1668.952 1949.107
196 194 6aec1a085f 2026-10-02 5677 Report BON8 input that ends after a UTF-8 lead byte as truncated (#5677) 2003.321 4099.066 11614.364 3159.029 3849.857 899.995 459.542 539.436 6904.474 843.221 2071.503 652.303 1685.702 1972.556
197 195 4d46bce4e1 2026-10-02 5750 Fix CI on develop (#5750) 1962.685 4025.677 11277.718 3103.052 3785.213 894.610 448.583 533.887 6870.062 834.856 2020.231 658.339 1674.874 1954.242
198 196 63c10a51fc 2026-10-02 5638 Review and extend the documentation, and check it in CI (#5638) 1968.954 4036.851 11425.135 3104.359 3797.852 902.519 451.067 537.668 6910.375 852.438 2043.889 674.938 1701.314 1971.711
199 197 6d0867a85f 2026-10-02 5751 Make comparisons with scalars noexcept only when the conversion is (#5751) 2008.360 4091.453 11376.562 3144.575 3820.110 903.850 455.980 538.035 6851.885 841.549 2010.128 667.182 1690.586 1970.957
200 198 d11e89471b 2026-10-04 5606 Assert on missing array indices in const operator[] and document the JSON pointer case (#5606) 2000.121 4075.695 11475.520 3139.456 3837.211 900.437 453.703 538.895 6921.432 845.064 2027.417 663.969 1679.148 1964.082
201 199 df27cc3d4c 2026-10-04 5682 Add scalar-on-left overloads for legacy discarded comparisons in C++20 (#5682) 2010.838 4092.432 11495.625 3125.726 3873.167 911.281 456.807 538.386 6911.630 844.451 2033.630 688.219 1691.407 1971.697
202 200 6f2048cd5d 2026-10-04 5685 Accept lvalues in ordered_map::emplace's value parameter (#5685) 1999.816 4095.006 11445.740 3136.685 3924.146 918.692 458.336 542.423 6968.520 848.783 2037.096 667.772 1708.274 2002.449
203 201 0d01d6ae90 2026-10-04 5686 Classify leaves with operator<=> itself past the nesting bound (#5686) 1983.320 4116.981 11466.250 3192.969 3923.208 914.596 456.625 539.558 6975.537 849.252 2056.035 701.221 1716.493 1983.908
204 202 b730946432 2026-10-04 5689 Fix key types convertible to std::string_view breaking lookups (#5689) 1990.288 4060.487 11377.709 3107.537 3803.857 892.191 451.727 538.045 6896.480 844.989 2018.884 658.649 1676.566 2023.638
205 203 49cd427196 2026-10-04 5690 Copy-construct the base class of a deep copy's elements, not assign it (#5690) 1983.320 4033.156 11333.843 3138.547 3882.878 894.785 454.473 538.337 6918.619 841.205 2072.151 655.193 1693.871 1977.288
206 204 756b28c2b8 2026-10-04 5696 Keep a NUL byte ending a // comment as the end of input (#5696) 1985.931 4099.331 11579.875 3148.560 3872.422 896.276 451.436 536.774 6901.156 845.631 2014.820 648.054 1685.199 1971.762
207 205 1edf0ef041 2026-10-04 5700 Fix value(json_pointer, default) aborting under JSON_NOEXCEPTION (#5700) 1987.233 4076.133 11442.625 3124.099 3888.688 898.266 454.349 539.423 6950.140 852.803 2030.279 654.586 1691.751 1978.197
208 206 a212d3b2e4 2026-10-04 5722 Preserve the object comparator's state in a deep copy past the nesting bound (#5722) 2000.138 4113.471 11391.854 3151.006 3866.904 905.695 455.384 539.504 6929.818 842.213 2029.619 674.438 1697.044 1983.856
209 207 1df1e8a845 2026-10-04 5591 Make cross-string-type basic_json conversion explicit without implicit conversions (#5591) 2000.533 4107.994 11370.989 3160.854 3881.635 897.877 455.201 540.307 6927.167 840.130 2053.458 664.118 1697.618 1982.876
210 208 38a2db260c 2026-10-04 5728 Remove dead metaprogramming and duplicated code in traits and pointers (#5728) 1971.450 4040.828 11319.270 3109.521 3819.505 903.606 451.137 538.725 6825.640 843.951 2016.652 663.160 1684.596 1958.896
211 209 c5650eaa3c 2026-10-04 5704 Reject malformed UTF-16/UTF-32 units in wide-string input (#5704) 2006.689 4133.594 11469.209 3180.930 3881.633 902.924 456.572 540.557 6992.385 850.474 2025.267 652.367 1680.025 1957.468
212 210 40021f38fb 2026-10-04 5589 Add basic_json::as_base_class and document name conflicts with custom base classes (#5589) 2012.673 4147.193 11453.250 3167.448 3892.542 910.149 457.238 541.642 6998.084 852.247 2049.759 652.868 1688.229 1972.508
213 211 73e9eae3c1 2026-10-04 5746 Add an error_handler parameter for UTF-8 to the binary readers and writers (#5746) 2013.845 4130.237 11456.041 3135.688 3818.956 892.111 449.408 538.308 6825.213 835.872 1495.468 697.054 1679.760 1970.285
214 212 d8d47be4a5 2026-10-04 5754 Fix CI on develop after merging the ready-to-merge PRs (#5754) 2013.191 4119.948 11573.656 3173.029 3941.703 912.201 459.208 541.264 7013.364 848.908 1514.681 699.273 1685.391 1984.652
215 213 6b4b825af2 2026-10-04 5607 Handle numbers that do not fit narrow number types in the binary readers (#5607) 2009.190 4044.127 11362.677 3127.688 3827.841 892.131 449.386 534.731 6915.360 829.562 1487.640 697.206 1688.237 1952.157
216 214 8c1f60a45e 2026-10-04 5600 Store maps with enum keys as objects (opt-in) (#5600) 2008.560 4128.059 11523.011 3187.763 3843.177 912.520 456.427 537.514 6859.010 839.685 1501.515 696.508 1688.848 1968.910
217 215 c5a7a4b46d 2026-10-04 5688 Add deprecated from_bon8/from_bjdata(ptr, len) overloads (#5688) 2030.310 4108.505 11412.907 3141.836 3899.435 904.756 455.298 541.069 6926.151 846.240 1504.193 700.820 1693.983 1987.713
218 216 23d3b373e1 2026-10-04 5755 Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions (#5755) 2018.708 4106.015 11533.729 3134.945 3826.409 899.623 452.833 538.544 6846.443 830.555 1509.060 705.724 1692.819 1971.476
219 217 8a142bc436 2026-10-06 5764 Fix CI on develop after #5600, #5607, and #5755 (#5764) 2017.533 4151.854 11526.334 3195.240 3884.953 907.457 456.697 540.114 6891.136 844.145 1517.241 699.051 1690.344 1972.104
220 218 5379e04ce4 2026-10-06 5761 Throw type_error.321 when serializing discarded values to binary formats (#5761) 1999.156 4055.300 11427.521 3153.581 3836.060 891.927 455.413 540.938 6883.093 853.094 1510.099 701.888 1686.695 1982.806
221 219 0a365865f9 2026-10-06 5762 Make basic_json destruction allocation-free and non-recursive (#5762) 2024.289 4081.646 10719.428 3112.958 3900.503 924.900 462.081 540.765 6965.453 850.019 1511.381 669.802 1620.269 1912.078
222 220 5ecb704f6b 2026-10-06 5592 Speedup; check for the expected separator before the lexer's token switch (#5592) 1920.428 3801.979 10139.250 2891.862 3833.159 823.859 451.951 540.310 6885.672 843.570 1512.778 668.793 1608.501 1885.206
223 221 6d4543e743 2026-10-06 5767 Fix destroy() for ObjectTypes without reverse iteration (#5767) 1929.030 3843.266 10232.541 2911.458 3926.867 830.030 450.002 542.043 6938.890 846.589 1515.211 675.264 1622.245 1904.006
224 222 9b179cee1e 2026-10-06 5770 Handle all value_t enumerators in has_no_children() (#5770) 1931.275 3794.497 10155.125 2891.927 3871.831 829.432 446.176 535.126 6909.625 833.114 1498.945 677.571 1615.785 1884.043
225 223 69874e4544 2026-10-06 5760 Fix NUL bytes in UBJSON/BJData high-precision numbers (#5760) 1924.896 3853.081 10247.750 2926.515 3872.041 835.227 453.025 541.002 6919.037 842.240 1521.169 674.487 1607.441 1880.884
226 224 162e13b86f 2026-10-06 5758 Add with_*_t alias templates to create basic_json types with changed template parameters (#5758) 1938.268 3842.126 10289.968 2914.104 3962.414 834.967 455.536 543.630 6969.266 850.082 1530.064 678.054 1635.303 1916.763
227 225 21a69230bd 2026-10-06 5585 Create a value before giving it its type (#5585) 1918.165 3829.354 10247.656 2914.619 3874.909 832.287 451.252 543.791 6873.995 839.514 1521.088 699.604 1615.742 1894.449
228 226 ff6f3d7d4a 2026-10-07 5766 Reject nested indefinite-length CBOR string chunks (#5766) 1926.074 3868.810 10256.823 2919.802 3957.807 832.129 457.241 543.640 7024.745 847.770 1522.612 705.623 1634.212 1918.402
229 227 1c754cfe31 2026-10-07 5701 Copy a pair-shaped array value under JSON_BRACE_INIT_COPY_SEMANTICS (#5701) 1930.652 3828.195 10263.927 2921.570 3901.404 832.628 455.652 541.701 6909.037 843.563 1512.309 704.354 1623.254 1909.917
230 228 24dd7c63f0 2026-10-07 5777 Re-amalgamate after #5740 (#5777) 1908.632 3833.930 10278.146 2905.443 3935.422 838.465 454.491 545.605 6905.047 839.087 1519.816 709.223 1618.643 1886.706
231 229 30e542e52a 2026-10-07 5776 Declare the namespace-scope constants in to_chars.hpp inline (#5776) 1934.934 3823.724 10229.636 2916.698 3929.565 829.102 452.279 543.038 6951.995 837.059 1524.049 720.722 1619.823 1903.938
232 230 367336c83d 2026-10-07 5779 Fix CI on develop after #5585 (#5779) 1928.921 3780.927 10153.395 2883.604 3877.750 824.488 451.999 543.662 6927.395 835.495 1506.387 694.058 1622.903 1907.732
233 231 069ace74af 2026-10-07 5707 Round-trip BJData ND-array annotations exactly (single precision, key order) (#5707) 1937.387 3843.716 10184.302 2923.323 3936.570 827.610 456.123 543.169 6907.756 847.020 1515.229 696.202 1626.001 1901.142
234 232 43fe8928e1 2026-10-07 5781 Stop binary writers overflowing the stack on deep values (#5781) 1961.046 3868.274 10300.573 2899.792 3982.526 845.594 461.395 543.298 7059.093 846.696 1522.728 697.717 1623.846 1921.370
235 233 a5f5d3059b 2026-10-07 5772 Make std::hash<basic_json> consistent with operator== for numbers (#5772) 1949.220 3857.159 10170.427 2890.052 3981.349 840.234 459.334 541.947 6953.786 843.495 1509.713 703.339 1627.086 1911.653
236 234 a269794db7 2026-10-08 5782 Use MSVC intrinsics for full multiplication (#5782) 1931.869 3817.742 10159.666 2902.820 3903.263 840.740 455.827 540.621 6884.562 843.272 1513.776 702.028 1614.459 1901.008
237 235 69a0c1b82c 2026-10-09 5328 Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328) 1909.579 3777.560 10065.682 2852.732 3897.659 833.289 459.856 540.631 6882.354 833.998 1498.288 314.059 1609.343 1906.714
238 236 374dfe4f0f 2026-10-09 5791 Keep converted object keys alive while writing UBJSON and BJData (#5791) 1911.274 3827.188 10159.553 2886.568 3890.388 833.632 459.800 542.649 6954.547 838.507 1509.324 314.357 1613.655 1892.838
239 237 44e8597701 2026-10-09 5792 Flatten deeply nested values without recursing per nesting level (#5792) 1940.103 3811.779 10139.396 2865.050 3874.896 835.001 459.686 544.065 6866.943 836.862 1496.298 314.617 1614.837 1891.741
240 238 2913e96433 2026-10-09 5793 Unflatten in time and memory linear in the pointer depth (#5793) 1908.453 3785.099 10262.147 2878.961 3920.657 845.619 459.806 543.998 6874.813 832.659 1486.901 312.175 1589.620 1863.981
241 239 84ee12a67c 2026-10-09 5797 Make UTF8_ACCEPT/UTF8_REJECT inline variables to avoid TU-local exposure in modules (#5797) 1922.691 3792.849 10162.656 2871.562 3887.719 836.308 456.522 542.577 6912.807 840.369 1497.447 313.683 1609.988 1899.591
242 240 1649d9eda4 2026-10-11 5783 Use and extend the detail helpers to remove duplicated code (#5783) 1916.258 3804.242 10297.344 2913.118 3847.662 836.519 453.270 538.750 6953.015 832.774 1506.068 324.715 1596.974 1875.878
243 241 2cca04ae6f 2026-10-11 5800 Report one-character non-numeric array indices like longer ones (#5800) 1932.327 3803.750 10135.438 2881.041 3894.622 840.016 458.569 538.037 6842.948 829.444 1499.722 324.811 1607.194 1875.851
244 242 74a03dec84 2026-10-11 5802 Throw type_error.321 for discarded values in to_bon8 (#5802) 1924.695 3814.854 10084.239 2873.180 3848.498 839.406 450.575 534.181 6893.005 834.300 1503.369 324.389 1607.323 1887.871
245 243 e8b747e4bc 2026-10-11 5808 Re-amalgamate single_include after #5795 and #5806 (#5808) 1937.995 3840.622 10221.990 2896.024 3885.568 834.394 458.874 539.771 6906.182 839.793 1517.689 324.800 1609.838 1890.885
246 244 40a62947d3 2026-10-12 4965 support JSON Merge Patch (RFC 7396) diff creation (#4965) 1932.021 3822.188 10248.416 2924.560 3980.331 842.462 459.010 540.237 6978.526 838.941 1529.508 326.435 1636.153 1917.472
247 245 f23830b65e 2026-10-13 5809 Derive the lexer position lazily for seekable input (#5809) 1814.075 3368.028 9974.755 2807.532 3943.229 647.639 457.018 551.206 6954.166 843.355 1522.762 315.716 1618.953 1903.816
248 246 aa9620fb15 2026-10-13 5810 Skip the indentation after a newline 8 bytes at a time (#5810) 1719.629 2959.344 10139.771 2799.555 3939.292 592.867 465.821 545.858 6968.068 849.167 1519.774 315.385 1629.981 1907.253
249 247 e839bbd1c0 2026-10-13 5813 Export client-facing headers from json.hpp for IWYU / include-cleaner, and check clients in CI (#5813) 1725.742 2949.070 10136.603 2821.591 3919.927 589.957 463.642 544.851 6987.427 843.151 1517.562 314.425 1619.671 1903.613
250 248 5b4c8f9b00 2026-10-14 5738 Speed up the lexer: own float parser, string scan, and \u table (#5738) 1615.668 2934.565 8763.651 2794.503 3928.286 559.107 374.921 516.391 6937.140 815.776 1513.238 325.043 1625.226 1912.905
251 249 91a7a94cc6 2026-10-14 5634 Write doubles with the shortest digits (Żmij), digits in registers (#5634) 1613.126 2929.599 8708.599 2783.954 3874.248 548.449 363.632 468.127 2421.176 745.466 1511.406 323.743 1614.195 1900.392
252 250 a6e9785ab6 2026-10-15 5831 Look up the key only once in the callback parser's key() (#5831) 1589.309 2938.557 8798.823 2767.872 3882.154 547.301 364.257 467.833 2395.851 744.716 1506.830 316.192 1623.771 1899.458
253 251 0c4e7c103c 2026-10-15 5834 Make flatten() linear for ordered_json (#5834) 1625.754 2936.203 8755.088 2793.081 3879.740 557.529 366.745 468.359 2418.388 746.210 1524.325 315.954 1614.677 1898.544
254 252 0a4b3a84ee 2026-10-15 5836 Speed up JSON pointer parsing, formatting, comparison and lookup (#5836) 1622.914 2915.901 8819.073 2783.990 3922.758 558.429 366.216 470.019 2427.606 747.168 1526.881 316.972 1625.611 1912.601
255 253 6ba53e63dd 2026-10-15 5833 Speed up array-to-container from_json (#5833) 1626.155 2920.747 8777.989 2782.870 3988.206 560.154 367.695 469.892 2427.262 749.301 1529.474 316.399 1631.810 1915.217
256 254 ca7740fef2 2026-10-15 5837 Move elements when converting rvalue containers to JSON (#5837) 1615.747 2928.778 8765.792 2773.062 3926.456 561.034 367.498 469.807 2424.344 748.423 1523.215 316.339 1624.374 1894.455
257 255 4530d9681c 2026-10-15 5832 Fix quadratic parent updates for ordered_json with JSON_DIAGNOSTICS (#5832) 1618.937 2911.378 8794.094 2763.191 3886.974 555.789 366.475 469.275 2415.231 746.755 1512.590 315.856 1618.226 1899.284
258 256 91869983a0 2026-10-15 5840 Make the value lifecycle inline-friendly (#5840) 1595.075 2832.274 8420.390 2690.050 3876.841 555.209 366.118 469.783 2424.335 747.931 1485.914 314.048 1549.787 1775.823
259 257 6a27b9acb2 2026-10-15 5838 Construct remaining hot-path exceptions out of line so core functions inline (#5838) 1589.535 2824.360 8466.755 2699.690 3888.990 557.917 364.879 471.601 2422.995 746.543 1498.371 314.978 1539.656 1797.752
260 258 4f11512641 2026-10-15 5835 Speed up container destruction, iterator access and diff() (#5835) 1515.750 2714.756 8639.213 2574.698 3805.860 561.827 366.793 469.680 2421.769 748.727 1383.744 317.248 1446.525 1705.789
261 259 ed86019a21 2026-10-15 5839 Move binary reader error construction out of line (#5839) 1507.907 2766.774 8597.870 2622.289 3767.638 553.026 362.644 468.482 2408.731 744.936 1362.080 324.833 1445.531 1703.216
262 260 6261d1e432 2026-10-15 5842 Construct the JSON Patch exceptions out of line (#5842) 1532.015 2756.867 8670.677 2617.989 3869.133 558.865 365.834 469.932 2435.279 750.295 1380.628 327.010 1453.340 1705.232
263 261 ce28c722bc 2026-10-15 5815 Allow the same type for number_integer_t and number_unsigned_t (#5815) 1533.045 2775.807 8543.755 2615.412 3776.721 553.127 365.866 471.174 2433.384 745.309 1372.372 328.405 1452.848 1716.649
264 262 91b9ee2602 2026-10-15 5829 Update cppcheck to 1.5.2 (Cppcheck 2.20) and fix its new findings (#5829) 1516.450 2748.961 8571.521 2599.870 3807.744 557.303 367.220 472.209 2421.389 743.889 1379.405 326.087 1451.926 1710.506
265 263 dcb96e82fb 2026-10-15 5822 Escape characters below 0x60 from a table straight into the write buffer (#5822) 1525.777 2734.963 8524.771 2588.289 3790.726 557.907 360.057 463.574 2430.626 743.382 1375.816 325.308 1439.947 1695.307
266 264 b41228c227 2026-10-15 5843 Fix AppVeyor failures from the Zmij double writer (#5843) 1497.922 2690.614 8406.906 2582.482 3726.195 548.374 352.932 459.663 2398.953 737.639 1347.507 322.827 1429.640 1682.775
267 265 4da73dc5ff 2026-10-15 5858 Fix compiler warnings on develop from the API performance stack (#5858) 1523.138 2731.825 8474.073 2593.149 3782.769 553.758 359.180 462.915 2380.246 739.049 1346.755 324.909 1441.408 1698.043
268 266 5683f5e024 2026-10-15 5859 Define less_general() only without three-way comparison (#5859) 1504.689 2739.172 8603.693 2605.159 3797.057 560.213 358.865 464.429 2423.456 742.207 1374.000 326.702 1447.488 1712.379
269 267 cd6b428ef0 2026-10-16 5860 Fix CI failures on develop from the API performance stack (#5860) 1510.160 2732.695 8564.510 2603.242 3810.518 556.015 362.409 466.047 2437.364 745.153 1377.439 325.753 1444.892 1699.255
270 268 cc8334113c 2026-10-19 5866 Do not use Qt's keyword macros as identifiers (#5866) 1498.858 2732.644 8535.328 2587.258 3787.993 548.267 362.607 464.487 2403.147 735.633 1368.831 323.997 1442.709 1686.963
271 269 4da932f518 2026-10-19 5828 Make parsing from std::istream and FILE* fast (#5828) 1499.289 2723.605 8397.787 2597.237 1956.330 553.182 363.501 458.898 2397.342 733.054 1362.816 320.346 1429.314 1698.294
272 270 122d718330 2026-10-21 5620 Add json_document and json_view: node index, parser, and document (#5620) 1520.651 2751.099 8527.135 2588.494 1994.466 560.384 362.257 461.917 2393.611 741.198 1362.167 328.620 1441.211 1691.238 230.700 389.375 976.277
273 271 43e97b629b 2026-10-21 5622 Add element access, iteration, values, and JSON pointers to json_view (#5622) 1493.875 2687.307 8383.354 2567.078 1986.311 547.934 353.938 462.380 2400.331 737.098 1374.560 322.012 1445.504 1686.421 231.353 386.679 958.441
274 272 4c3a3eb5b5 2026-10-21 5624 Add dump() and comparisons to json_view (#5624) 1502.926 2714.747 8522.161 2608.565 2001.856 552.014 359.510 462.656 2393.110 732.091 1366.524 324.313 1442.119 1682.564 228.836 393.082 976.976
275 273 3ff37ead75 2026-10-21 5628 Scan json_view strings with SIMD and index large objects (#5628) 1514.580 2728.619 8406.562 2609.758 2041.176 556.017 357.330 462.573 2383.158 733.939 1368.057 324.391 1442.711 1700.884 177.833 367.806 950.071
276 274 823eee3b59 2026-10-21 5630 Add editable json_documents: set, push_back, insert, and erase (#5630) 1498.134 2754.810 8537.062 2588.474 1994.441 556.670 353.931 463.646 2392.987 740.023 1357.930 324.129 1441.622 1698.022 181.404 376.470 962.253
277 275 4971200b54 2026-10-21 5632 Add images of json_documents: save() and load() (#5632) 1494.231 2681.211 8425.834 2543.276 1984.849 548.146 354.762 460.440 2414.747 734.679 1363.841 321.349 1421.806 1670.134 177.777 368.631 949.292
278 276 4155e2938f 2026-10-21 5633 Write json_view's dump() without a call or conversion per token (#5633) 1500.247 2712.357 8612.193 2597.211 2012.860 558.559 359.889 462.371 2412.896 739.048 1372.456 324.070 1441.546 1697.571 180.320 371.514 954.088
279 277 08d7fbb0a1 2026-10-21 5874 Read FILE* input with std::fgetc under MemorySanitizer (#5874) 1543.124 2758.211 8565.730 2584.453 2046.255 558.522 358.865 464.542 2421.435 743.715 1374.005 324.687 1462.572 1700.819 180.714 372.601 965.361
280 278 0cbe95ffa2 2026-10-21 5824 Speed up writing CBOR and MessagePack, above all integer arrays (#5824) 1501.550 2706.534 8707.120 2584.807 2039.728 551.688 360.692 466.024 2397.182 742.777 1361.847 201.488 1429.223 1682.436 178.641 371.038 946.389
281 279 bd5227c2ec 2026-10-21 5805 Fix silent wrong results for custom number types (#5805) 1511.036 2733.325 8786.406 2588.906 2000.483 553.456 360.458 465.989 2398.381 743.338 1370.524 201.168 1444.051 1701.345 179.776 372.557 954.733
282 280 e13e976801 2026-10-21 5851 Accumulate number digits while scanning them (#5851) 1501.737 2667.570 7762.365 2523.289 1987.518 545.368 359.336 462.056 2407.652 739.226 1368.104 200.632 1440.390 1688.117 178.721 374.278 956.353
283 281 5e13f834c1 2026-10-21 5852 Copy the text of float tokens only when a SAX handler asks for it (#5852) 1512.318 2655.312 7314.354 2515.044 2019.288 547.993 362.038 463.788 2410.262 745.839 1364.898 208.969 1450.422 1713.902 179.198 371.996 968.699
284 282 e9970066c5 2026-10-21 5853 Scan strings with SSE2, SSSE3, or NEON (#5853) 1488.705 2654.404 7339.589 2551.050 2015.716 486.719 341.381 475.591 2434.369 756.973 1376.754 208.797 1449.981 1706.044 182.358 379.153 968.355
285 283 fa37b952df 2026-10-21 5854 Match literals without a stack array and keep parser states in bytes (#5854) 1471.894 2619.164 7285.000 2485.883 1949.380 471.534 347.785 475.287 2413.552 751.487 1374.254 207.522 1443.177 1699.611 181.643 377.971 977.268
286 284 52fecc1fab 2026-10-21 5855 Move object keys into the value when parsing (#5855) 1392.599 2628.688 7362.562 2485.293 1882.663 471.968 339.711 473.663 2414.903 751.376 1319.857 200.185 1448.057 1705.675 179.410 371.865 963.306
287 285 6aefd8c662 2026-10-21 5878 Copy short printable-ASCII strings without starting the scanner (#5878) 1399.384 2664.401 7232.557 2535.425 1922.431 470.185 320.230 418.440 2446.082 696.786 1317.889 201.955 1447.217 1701.135 180.860 376.217 968.215
288 286 7c26e99ac5 2026-10-21 5879 Copy ASCII strings in the view's dump with ensure_ascii (#5879) 1361.839 2610.182 7187.115 2471.708 1853.592 464.274 313.821 414.316 2388.840 687.851 1318.253 200.399 1434.986 1697.487 178.601 368.595 947.799
289 287 3e031b06a5 2026-10-21 5876 Use standard library helpers where available, with C++11 fallbacks (#5876) 1381.599 2592.122 7336.719 2499.994 1848.434 467.895 315.257 415.788 2430.769 692.250 1311.164 200.424 1444.303 1698.311 180.149 374.484 961.091
290 288 9bf531436f 2026-10-21 5861 Speed up flatten(), unflatten(), diff() and patch() (#5861) 1379.301 2613.219 7170.433 2472.628 1853.035 467.161 315.217 412.303 2406.597 683.062 1298.512 198.681 1434.089 1682.912 177.511 368.116 947.255
291 289 9855db81f3 2026-10-22 5881 Silence macro-to-enum for the endianness macros (#5881) 1369.150 2613.547 7209.787 2476.232 1841.347 467.780 316.011 416.187 2415.504 686.920 1304.263 200.868 1441.243 1694.603 178.739 368.123 948.579
292 290 aa0b371f7c 2026-10-23 5884 Faster std::istream input: inline get-area path, binary reads, unbuffered streambufs (#5884) 1375.030 2569.362 7218.375 2484.425 1743.476 470.240 319.245 403.750 2436.034 679.759 1319.508 201.531 1443.354 1698.057 180.133 372.206 946.488
293 291 86d5c56c54 2026-10-23 5886 Speed up flatten(), unflatten(), diff() and patch() further (#5886) 1386.169 2622.331 7281.551 2495.923 1700.794 472.317 317.282 403.416 2409.097 682.507 1320.319 200.963 1444.908 1697.678 179.138 375.751 954.573
294 292 dec0e9b749 2026-10-23 5883 Write strings, scalars and indentation in dump() with fewer calls (#5883) 1383.235 2621.847 7151.412 2491.644 1732.469 473.034 211.016 288.685 2276.953 416.068 1318.490 200.574 1452.099 1701.256 180.064 372.324 960.583
295 293 6fa14d8f95 2026-10-23 5885 Write binary formats through reserved sink space and number runs (#5885) 1366.956 2600.914 7176.994 2465.343 1691.333 462.351 210.662 285.259 2301.553 417.589 1324.173 136.601 1429.240 1687.947 179.319 368.881 962.518
296 294 0b924f5375 2026-10-23 5887 Split and print JSON pointers in one pass (#5887) 1377.526 2597.394 7242.688 2464.445 1739.841 466.382 211.716 288.202 2319.771 418.288 1318.592 138.744 1441.983 1706.639 179.684 372.087 976.078
297 295 e9c4fe3cdf 2026-10-24 5889 json_view: indented and ensure_ascii dumps through the fast writer (#5889) 1393.007 2627.226 7248.287 2491.551 1769.642 469.976 211.665 291.327 2305.655 420.168 1319.431 139.577 1457.965 1712.927 182.274 377.741 983.284
298 296 dd7686a269 2026-10-24 5888 json_view: faster reading, indexing and C-stream parsing (#5888) 1382.444 2607.026 7161.365 2472.635 1701.277 468.438 209.963 287.564 2276.329 415.511 1311.194 137.875 1439.700 1696.646 177.624 367.131 977.802
299 297 9c50bdd140 2026-10-24 5882 Make the DOM parser cheaper per container and per member (#5882) 1392.673 2461.082 6068.625 2334.706 1696.950 475.550 209.313 291.776 2300.287 416.349 1317.581 138.194 1441.209 1707.720 178.751 367.339 978.031
300 298 01139dc192 2026-10-24 5905 Silence an Infer false positive in json_view materialize (#5905) 1381.470 2463.013 6078.010 2335.216 1709.088 475.718 211.023 291.212 2275.302 418.098 1320.441 137.572 1443.434 1696.436 175.969 365.658 975.272
301 299 fe5e401870 2026-10-25 5901 Consolidate duplicated detail helpers and bodies (#5891) (#5901) 1395.881 2462.765 6066.698 2327.708 1706.745 474.184 212.683 289.321 2283.842 417.657 1314.153 138.084 1442.796 1696.588 177.144 364.092 961.847
302 300 3eae5680d6 2026-10-25 5902 from_json: number-first dispatch for arithmetic types, loop for std::array (#5902) 1397.343 2477.060 6080.864 2340.781 1711.774 481.523 213.618 289.360 2289.503 417.517 1313.541 138.271 1440.822 1695.785 178.731 367.293 983.555
303 301 2a56afc714 2026-10-25 5916 Fix VS 2015 build of the DOM parser (#5882) (#5916) 1373.929 2476.139 6056.797 2341.890 1749.167 482.883 215.107 290.053 2292.495 417.441 1320.640 137.868 1445.227 1702.064 177.912 367.669 984.794
304 302 d6431a9104 2026-10-26 5918 Throw out_of_range.411 for JSON Patch add into a null parent (#5917) (#5918) 1371.635 2445.905 6017.636 2314.178 1696.447 478.134 210.996 287.397 2278.718 414.186 1291.197 137.374 1436.212 1682.197 175.790 361.130 962.070
305 303 81d66291c5 2026-10-26 5358 Create objects for pointer tokens that cannot be array indices (#5358) 1382.909 2465.649 6052.114 2332.556 1711.721 479.927 213.359 289.913 2289.412 417.201 1311.695 137.572 1437.168 1696.302 177.495 367.526 963.924
306 304 d5da84249f 2026-10-26 5927 Skip CBOR tags in front of map keys, validate indefinite text chunks, fix CBOR docs (#5927) 1374.553 2476.464 6076.834 2346.075 1744.224 483.375 211.423 291.148 2287.800 420.247 1320.015 137.369 1449.068 1704.785 177.459 365.004 963.908
307 305 0c3570d44a 2026-10-26 5929 Validate the UBJSON/BJData container type marker for count 0; fix UBJSON docs (#5929) 1381.462 2462.578 6055.183 2329.970 1713.086 484.962 210.683 290.024 2260.371 416.895 1319.093 137.782 1453.495 1706.801 177.031 361.025 962.952
308 306 dc768a7d5d 2026-10-26 5930 Fix BSON binary subtype 0x02 and check the declared document size earlier (#5930) 1386.856 2463.400 6054.255 2337.105 1746.441 485.425 214.508 290.954 2314.702 418.769 1325.164 139.255 1452.125 1718.313 179.005 367.327 977.054
309 307 60107eda3f 2026-10-26 5931 Read BJData ND-arrays of float16, restrict ND-array char to 0..127, correct BJData docs (#5931) 1389.051 2464.457 6049.084 2336.727 1710.473 483.159 213.007 288.990 2285.073 417.663 1317.537 137.893 1443.301 1697.126 178.706 364.051 962.202
310 308 731f1b5bfb 2026-10-26 5919 json_view: view_mode enum instead of bool Editable, node_kind for node::kind (#5919) 1381.664 2428.529 5978.713 2333.485 1746.571 479.163 211.036 288.957 2281.592 416.990 1308.904 137.486 1447.665 1691.427 175.453 363.704 963.371
311 309 4cdfa6d0f4 2026-10-26 5920 json_view: no save() and load() on big-endian targets (#5920) 1390.901 2477.841 6102.474 2337.925 1777.003 485.382 214.373 290.946 2303.147 421.178 1321.976 139.942 1446.726 1704.816 179.928 367.825 976.532
312 310 5a2819c940 2026-10-26 5921 json_view: one SIMD macro set with the library (#5921) 1393.409 2479.841 6073.011 2350.336 1785.087 485.658 214.651 292.044 2304.448 418.026 1326.212 138.942 1468.981 1719.505 179.174 368.704 982.764
313 311 e5fe4ebdd2 2026-10-26 5922 json_view: from_json() of the macros reads views directly (#5922) 1384.612 2467.078 6056.328 2337.309 1742.751 482.554 213.389 289.543 2299.118 417.521 1309.673 138.237 1448.628 1704.550 177.925 365.163 984.351
314 312 9e67bfa115 2026-10-26 5923 json_view: the library's std conversions read views directly (#5923) 1395.103 2482.517 6066.604 2350.538 1751.603 482.504 213.399 290.185 2306.188 420.406 1317.415 138.730 1444.367 1708.720 178.016 369.111 975.875
315 313 21ec9bd801 2026-10-27 5915 json_view: fewer allocations when parsing small documents (#5915) 1388.282 2469.118 6066.495 2340.391 1744.901 478.745 214.934 292.970 2309.264 422.842 1323.237 138.541 1454.151 1707.314 178.058 366.514 958.110
316 314 2bb2feeef4 2026-10-27 5942 Fix the red CI on develop (json_view pointer tokens, bson, from_json tests, Infer, IWYU) (#5942) 1391.981 2468.266 6068.495 2335.707 1751.527 482.908 214.285 291.291 2300.453 417.876 1328.089 138.010 1454.934 1701.845 178.250 367.182 964.917
317 315 78a0687147 2026-10-27 5940 Strong exception guarantee for operator[](json_pointer) (#5940) 1379.414 2467.492 6109.136 2335.309 1723.090 480.260 216.197 292.075 2313.798 415.444 1314.530 138.314 1449.629 1698.792 177.628 364.844 965.314
318 316 091c10d4a5 2026-10-28 5936 Fix self-aliasing in json_pointer::operator/= and patch_inplace (#5936) 1389.195 2462.409 6052.125 2321.091 1722.944 473.064 214.421 290.952 2279.997 416.589 1315.370 138.531 1437.996 1683.844 176.596 363.105 952.473
319 317 54f6b3ef06 2026-10-28 5945 json_view: source positions in materialize() with JSON_DIAGNOSTIC_POSITIONS (#5945) 1417.895 2496.591 6325.787 2377.105 1737.749 478.133 213.209 293.150 2304.971 422.648 1348.357 139.793 1490.556 1735.758 178.445 368.380 990.587
320 318 0115bb47b3 2026-10-30 5965 Name the source and license of adapted code in the file comments (#5965) 1378.289 2456.731 6043.011 2330.780 1711.965 470.960 212.371 290.798 2298.443 419.433 1323.072 137.982 1441.316 1690.457 176.197 363.182 977.928
321 319 0b91f9ddd8 2026-10-30 5926 json_view: check_utf8 skips well-formed runs with the parser's string scan (#5926) 1400.777 2488.449 6137.021 2359.856 1747.026 473.449 213.226 290.736 2320.524 420.950 1325.039 139.324 1452.907 1703.426 177.699 364.500 988.981
322 320 ea03d601af 2026-10-30 5890 json_view: comparison without temporaries and a faster image float check (#5890) 1388.958 2477.531 6127.547 2357.032 1781.238 477.111 216.144 293.938 2340.267 424.058 1337.149 139.387 1459.923 1723.919
323 321 755bb16d7a 2026-10-30 5966 Fix the red CI on develop: remove the duplicate is_editable in basic_json_view (#5966) 1411.867 2497.560 6085.938 2326.880 1726.740 480.376 212.294 292.134 2312.521 420.608 1325.345 138.544 1465.640 1744.928 177.785 367.385 992.034
324 322 4fe670b5f4 2026-10-31 5969 json_view: decode chains of unicode escapes in a loop (#5969) 1390.866 2466.769 6026.817 2328.995 1736.168 475.935 212.530 291.166 2284.708 418.661 1323.436 137.513 1495.099 1736.832 176.566 365.541 963.794
325 323 9c349b1d7c 2026-10-31 5964 Write integers of 17 to 20 digits eight digits at a time in dump() (#5964) 1390.500 2469.332 6079.698 2359.276 1718.121 470.647 209.615 289.143 2300.836 419.976 1331.637 138.488 1450.106 1703.483 176.731 365.394 953.483
326 324 3fd3e0fdaa 2026-11-01 5908 json_view: dump and read canada.json-style floats faster (batched float decisions) (#5908) 1366.359 2456.409 6058.422 2329.066 1713.347 470.784 209.895 289.318 2294.111 417.490 1319.403 138.100 1435.053 1698.647 176.006 363.191 954.196
327 325 76001c6b4c 2026-11-01 5968 BSON reader: find C-string terminators 8 bytes at a time, skip array element names (#5968) 1408.222 2488.159 6124.287 2363.039 1759.751 477.558 216.880 294.011 2317.898 420.892 1345.718 138.602 1460.432 1713.978 179.721 370.205 970.525
328 326 1a018577cc 2026-11-01 5970 json_view: accept() checks the text without writing an index (#5970) 1427.279 2506.345 6160.916 2368.009 1765.595 480.552 214.060 293.093 2341.368 419.303 1330.990 138.625 1463.731 1724.021 181.150 373.171 964.666
329 327 162eda2574 2026-11-01 5971 json_view: skip the digits of a fraction 16 bytes at a time (SSE2) (#5971) 1404.191 2474.144 6049.006 2363.726 1711.013 471.608 211.613 289.736 2290.230 418.673 1322.822 138.556 1441.219 1697.559 178.814 370.881 956.959
330 328 6c3ab966d3 2026-11-01 5975 CBOR reader: read runs of scalar array elements in one loop (#5975) 1385.800 2466.923 6050.480 2325.901 1725.552 474.248 210.034 289.350 2296.399 418.689 1327.626 137.722 1440.577 1698.622 178.627 367.797 953.174
331 329 aecbef3949 2026-11-01 5976 Binary readers: swap the bytes of floats with a single byteswap (#5976) 1393.659 2479.298 6092.110 2337.421 1718.218 472.539 211.337 289.638 2307.378 417.589 1324.038 137.341 1447.860 1701.387 179.160 369.448 956.324
332 330 edf8d17601 2026-11-01 5980 MessagePack reader: read runs of scalar array elements in one loop (#5980) 1422.081 2486.171 6157.302 2360.678 1733.503 477.472 211.189 289.309 2307.724 419.448 1334.857 138.914 1449.345 1721.126 180.127 369.693 967.370
333 331 fb515ddc34 2026-11-01 5981 UBJSON/BJData readers: read optimized arrays of numbers in one loop (#5981) 1387.633 2470.528 6067.657 2345.342 1721.303 476.141 212.198 288.466 2292.649 416.597 1324.486 139.598 1441.019 1705.957 179.190 367.903 959.677
334 332 517444b504 2026-11-01 5978 accept() checks strings without copying them (#5978) 1385.026 2453.809 5975.744 2322.357 1711.222 475.186 210.256 288.348 2282.444 415.256 1321.012 138.726 1434.772 1698.120 178.106 365.411 976.135
335 333 9742edc294 2026-11-01 5979 BSON writer: write to_bson(j) in one pass, with sizes written afterwards (#5979) 1418.816 2514.802 6091.854 2380.269 1772.646 474.067 211.598 290.653 2316.886 421.043 1346.324 139.213 1469.659 1754.493 180.269 372.201 982.753
336 334 f022e3c59c 2026-11-01 5982 Binary readers and writers: faster UTF-8 checks of strings (#5982) 1399.836 2474.703 6060.781 2341.409 1707.583 468.692 209.824 290.357 2290.034 418.739 1312.448 138.360 1458.779 1707.575 178.911 369.303 968.200
337 335 ddc34f546a 2026-11-01 5974 json_view: exceptions name the path and the bytes of the value (#5974) 1394.263 2489.906 6017.599 2345.632 1728.593 473.672 210.364 289.980 2306.608 420.394 1327.301 138.827 1448.846 1707.037 177.406 368.436 978.755
338 336 b2674a4a2f 2026-11-01 5984 BSON reader: check array element names in place in strict mode (#5984) 1392.028 2460.989 5975.355 2357.154 1726.291 472.389 209.872 289.219 2301.092 417.632 1309.441 138.779 1438.270 1709.943 177.580 366.368 973.214
339 337 76dbe8f9c9 2026-11-02 6009 Fix the red CI on develop: Visual Studio 2017 build of the BSON writer, Valgrind timeouts (#6009) 1387.812 2461.244 5975.843 2323.693 1713.572 469.489 209.863 289.058 2291.892 415.935 1306.729 138.322 1447.714 1694.220 177.698 363.994 972.289
340 338 03d408aafa 2026-11-02 6003 JSON_DIAGNOSTIC_POSITIONS: comparing a value-initialized iterator throws instead of crashing (#6003) 1385.014 2455.146 5981.995 2380.493 1732.039 466.575 209.272 289.474 2295.226 416.844 1301.454 138.016 1445.840 1703.494 176.691 365.416 967.929
341 339 66e2eeeec0 2026-11-02 6000 Do not construct the base class when destroying a container (#6000) 1403.795 2457.426 6001.495 2323.510 1718.268 471.022 210.474 288.385 2308.462 417.187 1313.263 138.770 1437.867 1705.586 179.168 363.523 966.701
342 340 bdc737db6d 2026-11-02 5999 json_view: dump() without StringType::capacity() (#5999) 1378.656 2452.954 6020.464 2339.908 1724.630 470.774 211.638 288.939 2303.773 418.311 1312.024 139.010 1446.709 1704.406 177.291 363.859 966.602
343 341 494a74c242 2026-11-02 5996 insert(): strong guarantee for single elements, basic guarantee for the rest (#5996) 1390.153 2478.991 6032.084 2342.171 1727.040 469.799 213.660 291.104 2307.193 419.623 1329.285 139.000 1461.294 1718.750 178.995 366.898 974.652
344 342 bfe69c73c2 2026-11-02 5992 json_view: get<T>() of a boolean throws for the exact number types, as basic_json does (#5992) 1387.497 2452.207 6023.042 2335.261 1720.938 471.966 212.162 288.851 2310.949 417.260 1315.155 137.821 1448.762 1710.153 175.990 366.239 970.052
345 343 ff0bdfdef3 2026-11-02 5990 Keep the byte range in exceptions about the root value (#5990) 1386.358 2469.197 6037.812 2344.775 1768.382 479.285 214.375 290.939 2329.486 421.838 1332.654 138.666 1455.905 1720.376 178.637 368.500 972.955
346 344 1d69ef9ab4 2026-11-02 5997 Raise line coverage to 99.9 %: fix the measurement, remove unreachable code, add tests (#5997) 1404.481 2456.447 6166.942 2338.226 1749.981 478.338 211.609 289.387 2304.532 419.095 1321.195 140.055 1460.574 1706.842 179.067 369.688 982.029
347 345 5c4f585ac2 2026-11-02 6004 Lexer, parser, stream adapter, SAX: remove checks that invariants make dead (#6004) 1386.586 2468.772 6188.662 2373.328 1775.098 483.139 211.476 291.250 2315.874 420.854 1321.718 138.268 1464.254 1709.146 180.316 367.994 965.010
348 346 100f676b3e 2026-11-02 6012 Restore the two commits of #6005 that the stack merge dropped (fixes the build of develop) (#6012) 1369.597 2437.356 6122.282 2305.291 1691.485 472.217 208.716 288.666 2291.034 416.120 1300.906 137.896 1439.300 1688.769 176.641 366.389 972.368
349 347 590b622d48 2026-11-02 5991 parse(): propagate std::bad_alloc instead of crashing on a half-constructed member (#5991) 1377.480 2425.219 6113.438 2306.435 1716.697 474.315 209.052 288.883 2292.776 417.291 1305.336 137.989 1453.044 1704.638 179.096 368.072 978.198
350 348 6d5581c4e8 2026-11-02 6008 CBOR/MessagePack readers: leave one-element arrays to the general path (#6008) 1400.456 2439.163 6140.448 2328.635 1743.039 480.725 212.470 295.268 2348.332 427.202 1340.319 139.121 1489.584 1736.380 184.949 371.567 995.731
351 349 b18b6fc7e6 2026-11-02 6013 Build the parser's syntax error prefix with one concat() (#6013) 1370.175 2435.337 6098.834 2320.728 1726.256 472.914 210.817 289.786 2292.841 419.186 1306.593 139.277 1481.709 1714.543 177.065 366.270 971.330
352 350 07876e2292 2026-11-02 6015 json_view: a value that is not found has no bytes in its exception context (#6015) 1361.297 2435.980 6080.718 2305.853 1707.733 474.621 210.382 291.568 2337.276 424.783 1329.556 139.590 1450.506 1690.804 178.472 366.370 977.807
353 351 baba5db36f 2026-11-02 6016 Fix the MSVC and GCC builds of develop (C4127, -Weffc++) (#6016) 1381.280 2440.908 6116.068 2303.611 1713.472 476.121 210.492 290.105 2319.878 420.598 1318.037 139.554 1471.388 1729.097 177.078 369.621 959.145
354 352 candidate develop + open pull requests 1392.967 2469.204 6110.380 2348.760 1730.819 474.089 212.339 290.760 2284.428 420.179 1320.938 137.755 1441.341 1697.486 176.758 364.547 955.117
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+10 -39
View File
@@ -104,8 +104,10 @@ def ribbon(body, x0, y, cw, prefix, label=True):
# ---------------------------------------------------------------- figure 1: parse() vs json_document
def layout_tree(b, P):
"""panel A: basic_json::parse(), y from 0 to 220"""
def layout():
W, H, P = 840, 692, "jvl"
b = markers(P)
# --- panel A: basic_json::parse()
b.append(text(16, 26, "basic_json::parse(): a tree, every array, object, and string in its own heap allocation", "nj-jsonview-h"))
b.append(rect(16, 98, 60, 34, "nj-jsonview-box"))
b.append(text(46, 120, "json", "nj-jsonview-mono", anchor="middle"))
@@ -115,7 +117,7 @@ def layout_tree(b, P):
rows = [('"port"', "6379", None), ('"price"', "19.9", "double: 19.90 is gone"), ('"tags"', "\u2022", None)]
for i, (k, v, note) in enumerate(rows):
y = 50 + i * 48
b.append(line(192, 115, 226, y + 17, LINE, P))
b.append(curve(192, 115, 226, y + 17, LINE, P, bend=0))
b.append(rect(228, y, 180, 34, "nj-jsonview-heap"))
b.append(text(240, y + 22, k, "nj-jsonview-mono", KEY))
b.append(text(396, y + 22, v, "nj-jsonview-mono", NUM if i < 2 else LINE, anchor="end"))
@@ -130,9 +132,8 @@ def layout_tree(b, P):
b.append('<path class="nj-jsonview-sep" d="M624 %g V%g"/>' % (yt - 17, yt + 17))
b.append(text(601, yt + 5, "json", "nj-jsonview-mono", anchor="middle"))
b.append(text(647, yt + 5, "json", "nj-jsonview-mono", anchor="middle"))
for x1, y1, y2 in ((601, yt - 17, 130), (647, yt + 17, 196)):
b.append('<path class="nj-jsonview-arr nj-jsonview-c-%s" d="M%g %g C%g %g %g %g %g %g" marker-end="url(#%s-%s)"/>'
% (LINE, x1, y1, x1, y2, x1 + 40, y2, 706, y2, P, LINE))
b.append(curve(601, yt - 17, 706, 130, LINE, P, bend=-20))
b.append(curve(647, yt + 17, 706, 196, LINE, P, bend=20))
b.append(rect(708, 113, 126, 34, "nj-jsonview-heap"))
b.append(text(771, 135, "std::string eu", "nj-jsonview-mono nj-jsonview-sm", STR, anchor="middle"))
b.append(rect(708, 179, 126, 34, "nj-jsonview-heap"))
@@ -140,10 +141,9 @@ def layout_tree(b, P):
# legend
b.append(rect(16, 186, 18, 14, "nj-jsonview-heap", rx=3))
b.append(text(42, 198, "a separate heap allocation", "nj-jsonview-note"))
def layout_index(b, P, y0):
"""panel B: json_document::parse(), y from y0 - 16 to y0 + 440"""
# --- panel B: json_document::parse()
y0 = 252
b.append('<path class="nj-jsonview-sep" d="M16 %g H824"/>' % (y0 - 18))
b.append(text(16, y0 + 10, "json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes", "nj-jsonview-h"))
b.append(text(16, y0 + 38, "source text, 54 bytes (borrowed, or owned by the document)", "nj-jsonview-note"))
cw, rx0, ry = 14, 42, y0 + 48
@@ -185,25 +185,6 @@ def layout_index(b, P, y0):
b.append(curve(vx + 105, vy, n6x, ny + nh, STRUCT, P))
b.append(text(30, ny + nh + 50, "integers are converted while parsing and kept in their node;", "nj-jsonview-note"))
b.append(text(30, ny + nh + 68, "floats and strings point back into the text", "nj-jsonview-note"))
TREE_DESC = ("The text {\"port\": 6379, \"price\": 19.90, \"tags\": [\"eu\", \"a\\\"b\"]} 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.")
INDEX_DESC = ("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's buffer of decoded "
"strings. A json_view is two pointers: one to the document and one to a node, here the array.")
def layout():
# both panels in one figure (features/json_view.md)
W, H, P = 840, 692, "jvl"
b = markers(P)
layout_tree(b, P)
b.append('<path class="nj-jsonview-sep" d="M16 234 H824"/>')
layout_index(b, P, 252)
write("json_view_layout.svg", W, H, "fig-jvl-title",
"The same J\u200bSON text parsed by basic_json::parse() and by json_document::parse()",
"The text {\"port\": 6379, \"price\": 19.90, \"tags\": [\"eu\", \"a\\\"b\"]}. Top: basic_json::parse() builds a tree: "
@@ -214,16 +195,6 @@ def layout():
"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's buffer of decoded strings. A json_view is two "
"pointers: one to the document and one to a node, here the array.", b)
# each panel on its own (home/blog/how_3_13_0_got_faster.md), with their own marker ids
b = markers("jvlt")
layout_tree(b, "jvlt")
write("json_view_layout_tree.svg", W, 222, "fig-jvlt-title",
"A J\u200bSON text parsed by basic_json::parse()", TREE_DESC, b)
b = markers("jvli") + ['<g transform="translate(0 -236)">']
layout_index(b, "jvli", 252)
b.append('</g>')
write("json_view_layout_index.svg", W, H - 236, "fig-jvli-title",
"The same J\u200bSON text parsed by json_document::parse()", INDEX_DESC, b)
# ---------------------------------------------------------------- figure 2: lifetimes
-795
View File
@@ -1,795 +0,0 @@
"""Draws the figures of home/blog/how_3_13_0_got_faster.md as inline SVGs into docs/images/.
Generated files:
- perf_blog_overview.svg: speedup of 3.13.0 over 3.12.0 per workload (Google Benchmark suite)
- perf_blog_distribution.svg: how many of the suite's benchmarks got how much faster (data/perf_suite.csv)
- perf_blog_timeline_<workload>.svg: speedup over 3.12.0 of eight workloads at every develop commit that changed
json.hpp or json_view.hpp since 3.12.0, one panel each
- perf_blog_swar.svg: the eight-byte string test on one word of input
- perf_blog_overlap.svg: writing a short string with two overlapping 16-byte loads and stores
- perf_blog_digits.svg: converting eight ASCII digits with three multiplications
- perf_blog_cliffs.svg: operations that were quadratic or worse, 3.12.0 against 3.13.0 (log scale)
- perf_blog_heldout.svg: validate on the 19 files we didn't tune on, json_document against the fastest library per
file (data/perf_heldout_validate.json)
- perf_blog_usecases_<platform>.svg: libraries x use cases, time relative to the fastest fully validating library
(data/perf_usecases_<platform>.json); perf_blog_tables.py prints the tables of the appendix from the same data
The numbers are copied from the tables of the post (the timeline from data/perf_timeline.csv, which
`tests/benchmarks/history/history.py summarize` writes); the tables stay on the page as the accessible fallback. Update both together.
Like the figures of charts.py, the SVGs are not images: the page includes their text with
`--8<-- "images/<name>.svg"`, so they follow the colors and fonts of the page (`nj-charts` rules in
docs/css/fig-charts.css, `nj-fig` rules in docs/css/brand.css). Run `python3 scripts/figures/perf_blog.py` from
docs/mkdocs after changing data or drawing, and commit the generated files.
"""
import csv
import html
import json
import math
import re
from pathlib import Path
HERE = Path(__file__).resolve().parent
OUT = HERE.parents[1] / "docs" / "images"
MINUS = "&#8722;"
TIMES = "&#215;"
# words the abbreviation extension (includes/glossary.md) would wrap in <abbr> inside the SVG text
GLOSSARY = re.findall(r"^\*\[([^\]]+)\]", (HERE.parents[1] / "includes" / "glossary.md").read_text(), re.M)
ABBR = re.compile(r"(?<![\w;])(%s)(?!\w)" % "|".join(sorted(map(re.escape, GLOSSARY), key=len, reverse=True)))
def protect(text):
return ABBR.sub(lambda m: m.group(1)[0] + "&#8203;" + m.group(1)[1:], text)
def esc(s):
return html.escape(s, quote=True).replace("&amp;#", "&#")
def esc_md(s):
"""esc() for text with _ or *, which the page's Markdown pass would pair across text elements as emphasis"""
return esc(s).replace("_", "&#95;").replace("*", "&#42;")
def write(name, W, H, cls, tid, title, desc, body):
s = ['<svg class="nj-fig nj-charts %s" viewBox="0 0 %g %g" role="img" aria-labelledby="%s %s-d" '
'xmlns="http://www.w3.org/2000/svg">' % (cls, W, H, tid, tid),
'<title id="%s">%s</title>' % (tid, esc(title)),
'<desc id="%s-d">%s</desc>' % (tid, esc(desc))]
s += body
s.append('</svg>')
text = protect("\n".join(s)) + "\n"
assert "\n\n" not in text # a blank line would end the raw HTML block
(OUT / name).write_text(text)
def hbar(x0, x1, y, h, r=4):
"""Horizontal bar from the baseline x0 to x1, rounded only at the data end."""
if abs(x1 - x0) < 0.5:
return "M%g %g h0.5 v%g h-0.5 Z" % (x0, y, h)
r = min(r, h / 2, abs(x1 - x0))
s = 1 if x1 > x0 else -1
return ("M%g %g H%g Q%g %g %g %g V%g Q%g %g %g %g H%g Z"
% (x0, y, x1 - s * r, x1, y, x1, y + r, y + h - r, x1, y + h, x1 - s * r, y + h, x0))
def fx(v):
"""speedup factor for labels: 2 significant digits below 10, integers above"""
if v >= 100:
return "%d%s" % (round(v), TIMES)
if v >= 10:
return "%.0f%s" % (v, TIMES)
return "%.1f%s" % (v, TIMES) if v >= 1.995 else "%.2f%s" % (v, TIMES)
# ---------- SWAR: one word of a string ----------
def swar():
text = 'witter",'
W, H = 640, 312
L, cw, top = 40, 70, 34
b = []
b.append('<text class="fg-h" x="%g" y="20">eight input bytes, loaded as one 64-bit word (byte 0 is the lowest)</text>' % L)
for i, ch in enumerate(text):
x = L + i * cw
special = ch == '"'
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="40" rx="4"/>' % (x, top, cw - 6))
if special:
b.append('<rect class="nj-charts-c2" fill-opacity=".25" x="%g" y="%g" width="%g" height="40" rx="4"/>' % (x, top, cw - 6))
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (x + (cw - 6) / 2, top + 26, esc(ch)))
b.append('<text class="nj-charts-tick" x="%g" y="%g">0x%02X</text>' % (x + (cw - 6) / 2, top + 58, ord(ch)))
b.append('<text class="nj-charts-tick" x="%g" y="%g">byte %d</text>' % (x + (cw - 6) / 2, top + 74, i))
# result row
y2 = top + 112
b.append('<text class="fg-h" x="%g" y="%g">swar_string_special(): the high bit of each byte that needs handling</text>' % (L, y2 - 14))
for i, ch in enumerate(text):
x = L + i * cw
special = ch == '"'
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="34" rx="4"/>' % (x, y2, cw - 6))
if special:
b.append('<rect class="nj-charts-c2" fill-opacity=".25" x="%g" y="%g" width="%g" height="34" rx="4"/>' % (x, y2, cw - 6))
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>'
% (x + (cw - 6) / 2, y2 + 23, "0x80" if special else "0x00"))
# conclusion
y3 = y2 + 70
b.append('<text class="fg-code" x="%g" y="%g">count_trailing_zeros(0x0080000000000000) = 55</text>' % (L, y3))
b.append('<text class="fg-code" x="%g" y="%g">55 / 8 = 6: copy bytes 0 to 5 in one go, then handle the quote</text>' % (L, y3 + 26))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">No branch per byte: a few subtractions, ANDs and ORs per word,</text>' % (L, y3 + 56))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">then one count of trailing zeros.</text>' % (L, y3 + 74))
write("perf_blog_swar.svg", W, H, "nj-charts--swar", "nj-blog-swar",
"Finding the end of a run of ordinary string characters eight bytes at a time",
"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.", b)
def span(b, x0, x1, y, cls, label):
"""a bracket under the cells from x0 to x1, tinted, with a label to its right or inside"""
b.append('<rect class="%s" fill-opacity=".22" x="%g" y="%g" width="%g" height="22" rx="4"/>' % (cls, x0, y, x1 - x0))
b.append('<rect class="%s" x="%g" y="%g" width="4" height="22" rx="2"/>' % (cls, x0, y))
b.append('<rect class="%s" x="%g" y="%g" width="4" height="22" rx="2"/>' % (cls, x1 - 4, y))
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle" style="font-size:14px">%s</text>' % ((x0 + x1) / 2, y + 16, label))
# ---------- short strings: two overlapping 16-byte loads ----------
def overlap():
text = "profile_link_color" # a key of twitter.json, 18 bytes
n = len(text)
W = 640
L, cw, top = 40, 31, 34
X = lambda i: L + i * cw
b = ['<text class="fg-h" x="%g" y="20">a string of n = %d bytes: too long for one 16-byte vector, too short for a loop</text>' % (L, n)]
for i, ch in enumerate(text):
both = n - 16 <= i < 16
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="36" rx="4"/>' % (X(i), top, cw - 4))
if both:
b.append('<rect class="nj-charts-c3" fill-opacity=".3" x="%g" y="%g" width="%g" height="36" rx="4"/>' % (X(i), top, cw - 4))
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (X(i) + (cw - 4) / 2, top + 24, esc_md(ch)))
for i in (0, n - 16, 15, n - 1):
b.append('<text class="nj-charts-tick" x="%g" y="%g">%d</text>' % (X(i) + (cw - 4) / 2, top + 52, i))
y = top + 66
span(b, X(0), X(15) + cw - 4, y, "nj-charts-c1", "a = load 16 bytes at p")
span(b, X(n - 16), X(n - 1) + cw - 4, y + 30, "nj-charts-c2", "b = load 16 bytes at p + n " + MINUS + " 16")
y += 82
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Both loads lie inside the string, and together they cover all of it; bytes %d to 15 are in both.</text>' % (L, y, n - 16))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Test a and b for a quote, a backslash, a control character or 0x7F: none, so write</text>' % (L, y + 22))
b.append('<text class="fg-code" x="%g" y="%g">store a at d, store b at d + n %s 16</text>' % (L, y + 52, MINUS))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">The second store writes bytes %d to 15 again, with the same values. For any n from 16 to 32:</text>' % (L, y + 80, n - 16))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">two loads, one test, two stores, no loop and no branch on the length.</text>' % (L, y + 98))
write("perf_blog_overlap.svg", W, y + 112, "nj-charts--swar", "nj-blog-overlap",
"Writing an 18-byte string with two overlapping 16-byte loads and stores",
"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.", b)
# ---------- eight digits at a time: three multiplications ----------
def digits():
W = 600
L, cw, h = 40, 64, 34
X = lambda i: L + i * cw
steps = [
("eight ASCII digits in one 64-bit word (byte 0 is the lowest)", 1, list("12345678"), True),
("& 0x0F0F0F0F0F0F0F0F: one digit value per byte", 1, list("12345678"), False),
("× (10 · 2⁸ + 1) >> 8, every second byte kept: two digits per 16 bits", 2, ["12", "34", "56", "78"], False),
("× (100 · 2¹⁶ + 1) >> 16, every second lane kept: four digits per 32 bits", 4, ["1234", "5678"], False),
("× (10000 · 2³² + 1) >> 32: the value", 8, ["12345678"], False),
]
b = []
y = 20
for k, (head, width, cells, ascii_) in enumerate(steps):
b.append('<text class="fg-h" x="%g" y="%g">%s</text>' % (L, y, esc(head)))
for j, c in enumerate(cells):
x = X(j * width)
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="%g" rx="4"/>' % (x, y + 10, width * cw - 6, h))
if k == len(steps) - 1:
b.append('<rect class="nj-charts-c1" fill-opacity=".25" x="%g" y="%g" width="%g" height="%g" rx="4"/>' % (x, y + 10, width * cw - 6, h))
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (x + (width * cw - 6) / 2, y + 10 + 23, esc(c)))
if ascii_:
b.append('<text class="nj-charts-tick" x="%g" y="%g">0x%02X</text>' % (x + (width * cw - 6) / 2, y + h + 26, ord(c)))
y += h + (58 if ascii_ else 40)
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Each step combines neighboring lanes, in all lanes of the word at once:</text>' % (L, y - 8))
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">three multiplications instead of eight, and no branch.</text>' % (L, y + 10))
write("perf_blog_digits.svg", W, y + 22, "nj-charts--swar", "nj-blog-digits",
"Converting eight ASCII digits to their value with three multiplications",
"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.", b)
# ---------- overview: speedup per workload (Google Benchmark rows, 3.12.0 time / 3.13.0 time) ----------
# (group, label, speedup), copied from the table "The short version"
OVERVIEW = [
("Parsing", "twitter.json", 3.14),
("Parsing", "citm_catalog.json", 4.25),
("Parsing", "canada.json", 3.35),
("Parsing", "canada.json, indented", 6.51),
("Parsing", "citm, ordered_json", 6.85),
("Parsing", "twitter, std::ifstream", 2.50),
("Parsing", "citm, FILE*", 4.74),
("Parsing", "citm, accept()", 7.07),
("Writing", "dump() twitter", 6.70),
("Writing", "dump() canada", 2.98),
("Writing", "dump(4) citm", 4.70),
("Writing", "to_cbor() twitter", 4.59),
("Reading CBOR", "twitter, memory", 3.39),
("Reading CBOR", "twitter, FILE*", 6.59),
("Values", "diff() canada", 10.46),
("Values", "iterate canada", 2.73),
("Values", "copy + destroy citm", 1.13),
("Values", "== citm", 1.06),
]
def overview():
W, L, R = 560, 190, 520
hi = max(v for _, _, v in OVERVIEW)
hi = math.ceil(hi + 0.5)
X = lambda v: L + v / hi * (R - L)
pitch, bh, top = 24, 15, 8
b, desc = [], []
y = top
group = None
rows = []
for g, label, v in OVERVIEW:
if g != group:
if group is not None:
y += 10
b.append('<text class="nj-charts-panel" x="%g" y="%g">%s</text>' % (8, y + 12, esc(g)))
y += 22
group = g
rows.append((label, v, y))
y += pitch
axis_y = y + 2
for t in range(1, hi + 1):
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), top, X(t), axis_y))
b.append('<text class="nj-charts-tick" x="%g" y="%g">%d%s</text>' % (X(t), axis_y + 16, t, TIMES))
for label, v, yy in rows:
b.append('<text class="nj-charts-rowlabel nj-charts-tick--r" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 8, yy + bh - 3, esc(label)))
b.append('<path class="nj-charts-c1" d="%s"><title>%s: %s</title></path>' % (hbar(X(0), X(v), yy, bh), esc(label), fx(v)))
b.append('<text class="nj-charts-val" x="%g" y="%g">%s</text>' % (X(v) + 5, yy + bh - 3, fx(v)))
desc.append("%s %s" % (label, fx(v).replace(TIMES, "x")))
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(1), top, X(1), axis_y))
b.append('<line class="nj-charts-zero" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(0), top, X(0), axis_y))
b.append('<text class="nj-charts-tick" x="%g" y="%g">speedup over 3.12.0 (3.12.0 = 1%s), more is better</text>'
% ((L + R) / 2, axis_y + 34, TIMES))
write("perf_blog_overview.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-overview",
"Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang",
"Horizontal bars of the speedup, more is better. " + "; ".join(desc) + ".", b)
# ---------- distribution: how many of the suite's benchmarks got how much faster ----------
# bins of the speedup (3.12.0 time / 3.13.0 time) over all rows of data/perf_suite.csv
BINS = [(0, 1, "below 1" + TIMES), (1, 1.5, "1 to 1.5" + TIMES), (1.5, 2, "1.5 to 2" + TIMES),
(2, 3, "2 to 3" + TIMES), (3, 5, "3 to 5" + TIMES), (5, 10, "5 to 10" + TIMES), (10, 1e9, "10" + TIMES + " or more")]
def distribution():
rows = list(csv.DictReader((HERE / "data" / "perf_suite.csv").open()))
s = sorted(float(r["speedup"]) for r in rows)
n = len(s)
counts = [sum(lo <= v < hi for v in s) for lo, hi, _ in BINS]
geo = math.exp(sum(math.log(v) for v in s) / n)
med = (s[(n - 1) // 2] + s[n // 2]) / 2
W, H = 560, 250
L, R, T, B = 52, 548, 16, 196
hi = 10 * math.ceil(max(counts) / 10 + 0.4)
Y = lambda c: B - c / hi * (B - T)
slot = (R - L) / len(BINS)
b, desc = [], []
for t in range(0, hi + 1, 20):
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, Y(t), R, Y(t)))
b.append('<text class="nj-charts-tick nj-charts-tick--r" x="%g" y="%g">%d</text>' % (L - 6, Y(t) + 4, t))
for k, ((lo, _, label), c) in enumerate(zip(BINS, counts)):
x = L + k * slot + 8
w = slot - 16
cls = "nj-charts-c2" if lo < 1 else "nj-charts-c1"
b.append('<rect class="%s" x="%.1f" y="%.1f" width="%.1f" height="%.1f" rx="3"><title>%s: %d</title></rect>'
% (cls, x, Y(c), w, B - Y(c), label, c))
b.append('<text class="nj-charts-val" x="%.1f" y="%.1f" text-anchor="middle">%d</text>' % (x + w / 2, Y(c) - 5, c))
b.append('<text class="nj-charts-tick" x="%.1f" y="%.1f">%s</text>' % (x + w / 2, B + 16, label))
desc.append("%s: %d" % (label.replace(TIMES, "x"), c))
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, B, R, B))
b.append('<text class="nj-charts-tick" x="%g" y="%g">speedup over 3.12.0, more is better</text>' % ((L + R) / 2, H - 10))
b.append('<text class="nj-charts-tick" transform="rotate(-90)" x="%g" y="14">number of benchmarks</text>' % (-(T + B) / 2))
print("distribution: median %s, geometric mean %s" % (fx(med), fx(geo)))
write("perf_blog_distribution.svg", W, H, "nj-charts--blog", "nj-blog-dist",
"Speedup of 3.13.0 over 3.12.0 for all %d benchmarks of the suite" % n,
"Bars counting the benchmarks per speedup range: " + "; ".join(desc)
+ ". Median %s, geometric mean %s." % (fx(med).replace(TIMES, "x"), fx(geo).replace(TIMES, "x")), b)
# ---------- timeline: one panel per workload ----------
# (column in perf_timeline.csv, panel title, [(PR, label)]): each labeled step shows the number of the theme that
# explains it ("U" for the UTF-8 check of the binary readers that came and went); the appendix maps steps to PRs
TIMELINE = [
("parse_citm", "parse() citm_catalog.json", [(5234, "4"), (5283, "1"), (5592, "4"), (5809, "4"), (5810, "2"), (5882, "4")]),
("parse_canada", "parse() canada.json", [(5234, "4"), (5283, "1"), (5617, "3"), (5738, "3"), (5851, "3"), (5882, "4")]),
("accept_twitter", "accept() twitter.json", [(5234, "4"), (5283, "1"), (5592, "4"), (5809, "4"), (5810, "2"), (5853, "2")]),
("parse_twitter_ifstream", "parse() twitter.json, std::ifstream", [(5828, "1"), (5884, "1")]),
("dump_twitter", "dump() twitter.json", [(5285, "6"), (5738, "2"), (5878, "2"), (5883, "2")]),
("dump_canada", "dump() canada.json", [(5285, "6"), (5634, "3")]),
("from_cbor_twitter", "from_cbor() twitter", [(5233, "1"), (5501, "4"), (5185, "U"), (5746, "U")]),
("to_cbor_twitter", "to_cbor() twitter", [(5328, "4"), (5824, "6"), (5885, "6")]),
]
MONTHS = [("2025-04", "3.12.0"), ("2026-09", "Sep 2026"), ("2026-10", "Oct")]
def timeline():
rows = list(csv.DictReader((HERE / "data" / "perf_timeline.csv").open()))
n = len(rows)
W, H = 340, 270
L, R, T, B = 44, 330, 66, 208
for col, title, labels in TIMELINE:
vals = [float(r[col]) if r[col] else None for r in rows]
base = vals[0]
rel = [base / v if v else None for v in vals] # speedup over 3.12.0
hi = max(x for x in rel if x)
top = 2 ** math.ceil(math.log2(hi * 1.3))
Y = lambda s: B - math.log2(s) / math.log2(top) * (B - T)
X = lambda i: L + i / (n - 1) * (R - L)
b = ['<text class="nj-charts-panel" x="%g" y="18">%s</text>' % (8, esc(title))]
t = 1
while t <= top:
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, Y(t), R, Y(t)))
b.append('<text class="nj-charts-tick nj-charts-tick--r" x="%g" y="%g">%d%s</text>' % (L - 6, Y(t) + 4, t, TIMES))
t *= 2
# month ticks: first commit of the month
seen = set()
for i, r in enumerate(rows):
m = r["date"][:7]
for key, name in MONTHS:
if m == key and key not in seen:
seen.add(key)
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(i), B, X(i), B + 4))
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(i), B + 17, name))
# a step line: each commit's value holds until the next commit
pts, prev = [], None
for i, s in enumerate(rel):
if s is None:
continue
if prev is not None:
pts.append("%.1f,%.1f" % (X(i), Y(prev)))
pts.append("%.1f,%.1f" % (X(i), Y(s)))
prev = s
b.append('<polyline class="nj-charts-json" points="%s"/>' % " ".join(pts))
# labels for named steps: a dot at the commit and its PR number above it; PRs a few commits apart share a
# label, and a label that would overlap one already placed moves up
groups = []
for pr, lab in labels:
i = next(k for k, r in enumerate(rows) if r["pr"] == str(pr))
if groups and X(i) - X(groups[-1][-1][1]) < 6:
groups[-1].append((pr, i, lab))
else:
groups.append([(pr, i, lab)])
# labels in two rows above the plot, each with a guide down to its dot
placed = []
for g in groups:
i = g[-1][1]
x, y = X(i), Y(rel[i])
for pr, k, lab in g:
b.append('<circle class="nj-charts-json-dot" cx="%.1f" cy="%.1f" r="3.5"><title>#%s: %s</title></circle>'
% (X(k), Y(rel[k]), pr, fx(rel[k])))
marks = list(dict.fromkeys(lab for _, _, lab in g))
w = 18 * len(marks) - 3
tx = min(max(x, L + w / 2), R - w / 2)
row = 0
while any(r == row and abs(tx - px) < (w + pw) / 2 + 4 for px, r, pw in placed):
row += 1
placed.append((tx, row, w))
ty = 46 - 18 * row # the center of the badges
b.append('<line class="nj-charts-grid" stroke-dasharray="2 2" x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f"/>' % (x, ty + 8, x, y - 5))
for k, mark in enumerate(marks):
cx = tx - w / 2 + 7.5 + 18 * k
b.append('<circle class="nj-theme-dot%s" cx="%.1f" cy="%.1f" r="7.5"/>' % ("" if mark.isdigit() else " nj-theme-dot--other", cx, ty))
b.append('<text class="nj-theme-num" x="%.1f" y="%.1f" text-anchor="middle">%s</text>' % (cx, ty + 4, mark))
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, B, R, B))
b.append('<text class="nj-charts-note" x="%g" y="%g">speedup over 3.12.0 (log scale), more is better</text>' % (8, H - 8))
final = rel[-1]
desc = ("%s: speedup over 3.12.0 at each of %d commits, ending at %s. Labeled steps, by theme: %s."
% (title, n, fx(final).replace(TIMES, "x"), ", ".join(lab for _, lab in labels)))
write("perf_blog_timeline_%s.svg" % col, W, H, "nj-charts--timeline", "nj-blog-tl-" + col,
"%s: speedup over 3.12.0 by commit" % title, desc, b)
# ---------- cliffs: 3.12.0 and 3.13.0 times on a log axis ----------
# (operation, 3.12.0 ms, 3.13.0 ms), copied from the table in "Fix the algorithm first"
CLIFFS = [
("diff() 64k numbers vs []", 4237, 10.8),
("diff() 20k objects vs half", 122, 4.13),
("parse() callback, 32k objects", 1398, 12.1),
("operator< nested 24 deep", 64.4, 0.002),
("operator< citm, 10x", 284, 3.94),
("flatten() citm, ordered_json", 271, 1.45),
("to_bson() 200 deep, 100x", 20.3, 0.352),
("push_back() 100k, diagnostics", 1589, 5.32),
("at(i) 10k, diagnostics", 45.9, 0.088),
]
def cliffs():
W, L, R = 600, 250, 585
lo, hi = -3, 4 # 1 µs .. 10 s, in log10 ms
X = lambda ms: L + (math.log10(ms) - lo) / (hi - lo) * (R - L)
top, pitch = 40, 34
b, desc = [], []
axis_y = top + pitch * len(CLIFFS) - 10
for e in range(lo, hi + 1):
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(10 ** e), top - 10, X(10 ** e), axis_y))
lab = {-3: "1 µs", -2: "10 µs", -1: "0.1 ms", 0: "1 ms", 1: "10 ms", 2: "0.1 s", 3: "1 s", 4: "10 s"}[e]
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(10 ** e), axis_y + 16, lab))
b.append('<text class="nj-charts-tick" x="%g" y="%g">runtime (log scale), less is better</text>' % ((L + R) / 2, axis_y + 34))
b.append('<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>')
b.append('<circle class="nj-charts-ojson-dot" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">3.12.0</text>' % (L, L + 10))
b.append('<circle class="nj-charts-json-dot" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">3.13.0</text>' % (L + 80, L + 90))
for i, (op, old, new) in enumerate(CLIFFS):
y = top + i * pitch + 8
b.append('<text class="nj-charts-rowlabel" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 10, y + 4, esc(op)))
# an arrow from the old time to the new one, ending just before the new dot
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g" marker-end="url(#nj-blog-cliffs-head)"/>'
% (X(old) - 6, y, X(new) + 7, y))
b.append('<circle class="nj-charts-ojson-dot" cx="%g" cy="%g" r="5"><title>%s, 3.12.0: %g ms</title></circle>' % (X(old), y, esc(op), old))
b.append('<circle class="nj-charts-json-dot" cx="%g" cy="%g" r="5"><title>%s, 3.13.0: %g ms</title></circle>' % (X(new), y, esc(op), new))
b.append('<text class="nj-charts-factor" x="%g" y="%g">%s</text>' % ((X(old) + X(new)) / 2, y - 7, fx(old / new)))
desc.append("%s: %g ms to %g ms" % (op, old, new))
write("perf_blog_cliffs.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-cliffs",
"Operations that grew quadratically or worse: time with 3.12.0 and 3.13.0, log scale",
"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. " + "; ".join(desc) + ".", b)
# ---------- validating the files we didn't tune on, file by file ----------
# data/perf_heldout_validate.json: per platform, file and library the fastest fully validating way of the validate
# use case on the 19 other files of simdjson's jsonexamples (reused parsers not chosen), extracted from
# summarize.py --json of the held-out run
HELDOUT = [("mac", "Apple M1 Max", "nj-charts-json-dot"), ("x86-gcc", "x86-64, GCC 16.2", "nj-charts-ojson-dot")]
def heldout():
data = json.load((HERE / "data" / "perf_heldout_validate.json").open())
files = sorted(data["mac"])
rel, winner = {}, {}
for plat, _, _ in HELDOUT:
for f in files:
libs = data[plat][f]
# the fastest other library: below 1 json_document is the fastest, and the distance shows by how much
best = min((l for l in libs if l != "nlohmann json_document"), key=lambda l: libs[l]["us"])
rel[plat, f] = libs["nlohmann json_document"]["us"] / libs[best]["us"]
winner[plat, f] = UC_LIBS.get(best, best)
files.sort(key=lambda f: (rel["x86-gcc", f], rel["mac", f]))
W, L, R = 620, 262, 486
lo, hi = 0.4, 1.15
X = lambda r: L + (r - lo) / (hi - lo) * (R - L)
top, pitch = 58, 20
axis_y = top + pitch * len(files)
b, desc = [], []
for t in (0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1):
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), top - 8, X(t), axis_y))
b.append('<text class="nj-charts-tick" x="%g" y="%g">%.1f%s</text>' % (X(t), axis_y + 16, t, TIMES))
b.append('<text class="nj-charts-tick" x="%g" y="%g">json&#95;document&#8217;s time / the fastest other library&#8217;s, less is better</text>' % ((L + R) / 2, axis_y + 34))
x = 8
for plat, name, cls in HELDOUT:
b.append('<circle class="%s" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">%s</text>' % (cls, x + 5, x + 15, esc_md(name)))
x += 30 + 7.6 * len(name)
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="%g" y="%g">next on x86-64</text>' % (R + 14, top - 10))
for i, f in enumerate(files):
y = top + i * pitch + 6
b.append('<text class="nj-charts-rowlabel nj-charts-code" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 10, y + 4, esc_md(f)))
for k, (plat, name, cls) in enumerate(HELDOUT):
r = rel[plat, f]
b.append('<circle class="%s" cx="%.1f" cy="%g" r="4.5"><title>%s, %s: %.2f%s the time of %s</title></circle>'
% (cls, X(max(lo, min(r, hi))), y - 3.5 + 7 * k, esc_md(f), esc_md(name), r, TIMES, esc_md(winner[plat, f])))
w = winner["x86-gcc", f]
b.append('<text class="nj-charts-tick nj-charts-tick--l%s" x="%g" y="%g">%s</text>'
% (" nj-charts-best" if rel["x86-gcc", f] > 1.0005 else "", R + 14, y + 4, esc_md(w)))
desc.append("%s: Mac %.2f, x86-64 %.2f (%s)" % (f, rel["mac", f], rel["x86-gcc", f], w))
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(1), top - 8, X(1), axis_y))
b.append('<text class="nj-charts-tick" x="%g" y="%g">as fast as the next</text>' % (X(1), top - 14))
wins = {p: sum(rel[p, f] < 1 for f in files) for p, _, _ in HELDOUT}
print("heldout: json_document fastest on %s" % wins)
write("perf_blog_heldout.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-heldout",
"Validating 19 files 3.13.0 was not tuned on: json_document's time relative to the fastest other library per file",
"Dot plot per file, less is better; below 1.0 json_document is the fastest fully validating library. "
+ "; ".join(desc) + ".", b)
# ---------- the price: compile time of two programs against 3.12.0 ----------
# CPU time of the compiler in ms, median of 5 interleaved rounds, C++20, M1 Max (the post's appendix G)
# (3.12.0, 3.13.0, 3.13.0 with a precompiled header, 3.13.0 as a module)
PRICE = [
("Apple clang 21, -O0 (debug)", [("count_numbers", 955.0, 1320.5, 688.5, 917.5), ("server_config", 1113.2, 1496.4, 862.6, 1135.5)]),
("Apple clang 21, -O2", [("count_numbers", 1393.2, 2081.0, 1458.4, 1684.6), ("server_config", 1753.5, 2545.6, 1925.3, 2168.6)]),
("GCC 16, -O0 (debug)", [("count_numbers", 1569.4, 2548.4, 1725.0, 1699.8), ("server_config", 2025.4, 2985.1, 2301.6, 2325.8)]),
("GCC 16, -O2", [("count_numbers", 2336.0, 3701.5, 2986.8, 2913.4), ("server_config", 3121.5, 4714.2, 4006.2, 4054.9)]),
]
PRICE_SERIES = [("3.13.0", "nj-charts-c2"), ("3.13.0, precompiled header", "nj-charts-c1"), ("3.13.0, module", "nj-charts-c3")]
def price():
W, L, R = 600, 150, 560
lo, hi = -50, 70
X = lambda pct: L + (pct - lo) / (hi - lo) * (R - L)
pct = lambda new, old: round((new / old - 1) * 100)
lab = lambda p: (MINUS + "%d %%" % -p) if p < 0 else "+%d %%" % p
bh, pitch, gap = 11, 14, 10
b, desc = [], []
# the key above the plot
x = 8
for name, cls in PRICE_SERIES:
b.append('<rect class="%s" x="%g" y="6" width="12" height="12" rx="3"/>' % (cls, x))
b.append('<text class="nj-charts-leg" x="%g" y="16.5">%s</text>' % (x + 18, esc(name)))
x += 18 + 8.2 * len(name) + 22
top = 54
b.append('<text class="nj-charts-tick" x="%g" y="%g">as fast as 3.12.0</text>' % (X(0), top - 8))
y = top
for build, progs in PRICE:
b.append('<text class="nj-charts-panel" x="8" y="%g">%s</text>' % (y + 14, esc(build)))
y += 24
y0, at = y, len(b)
for prog, old, *new in progs:
b.append('<text class="nj-charts-rowlabel nj-charts-code" x="%g" y="%g" text-anchor="end">%s</text>'
% (L - 8, y + 1.5 * pitch + 2, prog))
for (name, cls), t in zip(PRICE_SERIES, new):
p = pct(t, old)
b.append('<path class="%s" d="%s"><title>%s, %s, %s: %s ms against %s ms with 3.12.0 (%s)</title></path>'
% (cls, hbar(X(0), X(p), y, bh), prog, esc(build), esc(name), format(round(t), ","), format(round(old), ","), lab(p)))
if p < 0:
b.append('<text class="nj-charts-val" x="%g" y="%g" text-anchor="end">%s</text>' % (X(p) - 5, y + bh - 1.5, lab(p)))
else:
b.append('<text class="nj-charts-val" x="%g" y="%g">%s</text>' % (X(p) + 5, y + bh - 1.5, lab(p)))
desc.append("%s, %s, %s: %s" % (build, prog, name, lab(p).replace(MINUS, "-")))
y += pitch
y += gap - (pitch - bh)
# the grid behind this panel's bars only, so that it doesn't cross the panel titles
b[at:at] = ['<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), y0 - 4, X(t), y - gap + 4)
for t in range(lo + 10, hi + 1, 20) if t]
y += 8
axis_y = y
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(0), top - 2, X(0), axis_y))
for t in range(lo + 10, hi + 1, 20):
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(t), axis_y + 16, "0" if t == 0 else lab(t)))
b.append('<text class="nj-charts-tick" x="%g" y="%g">compile time compared with 3.12.0, less is better</text>' % ((L + R) / 2, axis_y + 34))
write("perf_blog_price.svg", W, axis_y + 44, "nj-charts--blog", "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",
"Horizontal bars of the change in compile time against 3.12.0, less is better. " + "; ".join(desc) + ".", b)
# ---------- use cases: libraries x use cases, relative time ----------
# data/perf_usecases_<platform>.json is written by tests/benchmarks/json_view/others/summarize.py --json
UC_FILES = ["twitter", "citm_catalog", "canada", "jeopardy"]
USE_CASES = [("validate", "validate"), ("sum", "sum"), ("select", "select"),
("edit", "edit"), ("minify", "minify"), ("write", "write")]
UC_LIBS = { # library in the JSON -> row label
"nlohmann json_document": "nlohmann/json json_document", "nlohmann json": "nlohmann/json json",
"yyjson": "yyjson", "simdjson": "simdjson", "sonic-cpp": "sonic-cpp", "Glaze": "Glaze", "Boost.JSON": "Boost.JSON",
"RapidJSON": "RapidJSON", "sonic-rs": "sonic-rs (Rust)", "simd-json": "simd-json (Rust)", "serde_json": "serde_json (Rust)",
}
UC_PLATFORMS = [("mac", "Use cases: time of each library relative to the fastest, Apple M1 Max"),
("x86-gcc", "Use cases: time of each library relative to the fastest, x86-64 with GCC 16.2"),
("x86-gcc13", "Use cases: time of each library relative to the fastest, x86-64 with GCC 13"),
("x86-clang", "Use cases: time of each library relative to the fastest, x86-64 with Clang 23")]
LEVEL_MARK = {"no UTF-8": "U", "partial": "P", "full": ""}
# why a cell is empty (the tooltips of the n/a cells)
NA = {("simdjson", "edit"): "simdjson's documents are read-only: it has no API to change a value and write the result"}
def geomean(xs):
return math.exp(sum(math.log(x) for x in xs) / len(xs))
WRITING = ("edit", "minify", "write") # the use cases that write numbers
NUMBER_TEXT = ("source numbers", "raw numbers") # variants that write each number by copying its text
def normalize_usecases(data):
"""Chooses each library's best variants again with the rules of the post: variants that reuse a parser or document
across calls are measured but not chosen. Variants that write each number by copying its text instead of formatting
it (json_document's number_format::source, yyjson's and RapidJSON's raw numbers in edit, minify and write) are not
chosen as the fully validating way, but as a way that does less, marked "N" like "U" and "P". Skipping the number
conversion while reading is allowed. Each pick has a "mark": "", or the letters of what it skips"""
data = json.loads(json.dumps(data))
rank = {"full": 0, "n/a": 0, "no UTF-8": 1, "partial": 2}
for uc, files in data.items():
numtext = lambda k: uc in WRITING and any(w in k for w in NUMBER_TEXT)
for cell in files.values():
for e in cell.values():
vs = [(v["us"], k, v["level"]) for k, v in e["variants"].items() if "reused" not in k]
full = [v for v in vs if rank[v[2]] == 0 and not numtext(v[1])]
pick = lambda v: {"us": v[0], "variant": v[1], "level": "full" if rank[v[2]] == 0 else v[2],
"mark": " ".join(m for m in (LEVEL_MARK.get(v[2], ""), "N" if numtext(v[1]) else "") if m)}
e["best"] = pick(min(full)) if full else None
e["best_any"] = pick(min(vs))
return data
FILE_NAMES = {"twitter": "twitter.json", "citm_catalog": "citm_catalog.json", "canada": "canada.json",
"jeopardy": "jeopardy.json"}
# what a variant that checks less skips, worded as the trade it is (the tooltips of the heatmaps)
CHECKS_LESS = [
("simdjson", "On-Demand", "reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"),
("simdjson", "minify", "simdjson::minify() only removes whitespace, without parsing the values"),
("Glaze", "lazy_json", "reads lazily: lazy_json reads only what you ask for and steps over the rest"),
("Glaze", "minify_json", "minify_json only removes whitespace, without parsing the values"),
("Glaze", "generic", "accepts trailing garbage after the value: Glaze's default (validate_trailing_whitespace checks it)"),
("Glaze", "structs", "reads into structs and steps over fields it doesn't know without checking them "
"(validate_skipped checks them too)"),
("RapidJSON", "", "trusts UTF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"),
("sonic-cpp", "", "trusts UTF-8: sonic-cpp 1.0.2 doesn't check it"),
("serde_json", "", "trusts UTF-8 in the strings it skips (from_slice); strings it reads are checked"),
]
# what a variant that copies number text does (the "N" half of edit, minify and write)
NUMBER_TEXT_TIPS = {
"nlohmann json_document": "copies each number's text instead of formatting it (number_format::source)",
"yyjson": "copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)",
"RapidJSON": "copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)",
}
def checks_less(lib, variant):
for l, v, text in CHECKS_LESS:
if l == lib and v in variant:
return text
return "checks less"
def usecase_table(data):
"""{library: {use case: cell}}: per library the geometric mean over UC_FILES of its fastest fully validating time
("full") and of its fastest time at any level ("alt", only if it is at least 3 % faster), each divided by the best
such fully validating mean in the use case, so that every file counts equally and the fastest library is 1.00"""
out = {}
data = normalize_usecases(data)
for uc, _ in USE_CASES:
files = data.get(uc, {})
if not files:
continue
cells = {}
for lib in UC_LIBS:
es = [files.get(f, {}).get(lib) for f in UC_FILES]
if not all(es):
continue
full = [e["best"] for e in es]
alt = [e["best_any"] for e in es]
cells[lib] = {"full": geomean([b["us"] for b in full]) if all(full) else None, "alt": geomean([a["us"] for a in alt]),
"files": [(f, b, a) for f, b, a in zip(UC_FILES, full, alt)]}
ref = min(c["full"] for c in cells.values() if c["full"])
for lib, c in cells.items():
full = c["full"] / ref if c["full"] else None
alt = c["alt"] / ref
if full is not None and alt > full * 0.97:
alt = None
levels = {a["level"] for _, _, a in c["files"]} if alt is not None else set()
level = "partial" if "partial" in levels else "no UTF-8" if "no UTF-8" in levels else "full"
numtext = alt is not None and any("N" in a["mark"].split() for _, _, a in c["files"])
marks = " ".join(m for m in (LEVEL_MARK[level], "N" if numtext else "") if m)
out.setdefault(lib, {})[uc] = {"full": full, "alt": alt, "level": level, "marks": marks, "files": c["files"]}
return out
# cell colors: green for the fastest, gray around twice the time, red for the slowest; the upper bounds of the steps
HEAT_STEPS = [1.15, 1.5, 2.5, 5, float("inf")]
HEAT_LABELS = ["below 1.15", "1.15 to 1.5", "1.5 to 2.5", "2.5 to 5", "5 and more"]
def heat(r):
return next(i for i, b in enumerate(HEAT_STEPS) if r < b)
def fr(r):
return "%.2f" % r if r < 9.995 else "%.1f" % r if r < 99.95 else "%.0f" % r
def fus(us):
return "{:,.0f} µs".format(us) if us >= 100 else "%.1f µs" % us
def tip(lib, uc_label, c, half):
"""the tooltip of a cell: lines separated by newlines (&#10; in the attribute), the first one the heading"""
if half == "full":
lines = ["%s · %s" % (UC_LIBS[lib], uc_label),
"%s× the time of the fastest library (fully validating)" % fr(c["full"])]
picks = [(f, b) for f, b, _ in c["files"]]
else:
lines = ["%s · %s, checking less" % (UC_LIBS[lib], uc_label),
"%s× the time of the fastest fully validating library" % fr(c["alt"])]
picks = [(f, a) for f, _, a in c["files"]]
ways = sorted({e["variant"] for _, e in picks})
if len(ways) == 1:
lines.append("way: %s" % ways[0])
for f, e in picks:
lines.append("%s: %s%s%s" % (FILE_NAMES[f], fus(e["us"]), "" if len(ways) == 1 else " · " + e["variant"],
" (validates fully)" if half == "alt" and e["level"] == "full" else ""))
if half == "alt":
seen = []
for _, e in picks:
ts = ([checks_less(lib, e["variant"])] if e["level"] != "full" else []) + \
([NUMBER_TEXT_TIPS.get(lib, "copies each number's text instead of formatting it")] if "N" in e["mark"].split() else [])
for t in ts:
if t not in seen:
seen.append(t)
lines += seen
if any("(copy)" in e["variant"] for _, e in picks):
lines.append("(copy): parses in place, on a copy of the input that is part of the time")
return "&#10;".join(lines)
def heatmap(platform, title):
data = json.load((HERE / "data" / ("perf_usecases_%s.json" % platform)).open())
t = usecase_table(data)
libs = [l for l in UC_LIBS if l in t]
score = lambda l: geomean([v["full"] or v["alt"] for v in t[l].values()]) # the mean of the row as shown
libs.sort(key=score)
W, L, cw, ch, top = 784, 224, 92, 36, 44
b, desc = [], []
for j, (uc, label) in enumerate(USE_CASES):
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (L + j * cw + cw / 2, top - 10, esc(label)))
for i, lib in enumerate(libs):
y = top + i * ch
cls = "nj-charts-name-json" if lib.startswith("nlohmann") else ""
b.append('<text class="nj-charts-rowlabel %s" x="%g" y="%g" text-anchor="end">%s</text>' % (cls, L - 8, y + ch / 2 + 4, esc(UC_LIBS[lib])))
for j, (uc, label) in enumerate(USE_CASES):
x = L + j * cw
c = t[lib].get(uc)
if c is None:
b.append('<g class="nj-heat-cell" tabindex="0" data-tip="%s">' % esc("%s · %s&#10;%s" % (UC_LIBS[lib], label, NA.get((lib, uc), "the library has no API for this use case"))))
b.append('<rect class="nj-heat-na" x="%g" y="%g" width="%g" height="%g" rx="3"/>' % (x + 1, y + 1, cw - 2, ch - 2))
b.append('<text class="nj-charts-tick" x="%g" y="%g">n/a</text>' % (x + cw / 2, y + ch / 2 + 4))
b.append('</g>')
desc.append("%s %s: n/a" % (UC_LIBS[lib], label))
continue
halves = []
if c["full"] is not None:
halves.append(("full", c["full"]))
if c["alt"] is not None:
halves.append(("alt", c["alt"]))
hw = (cw - 2) / len(halves)
for k, (half, r) in enumerate(halves):
hx = x + 1 + k * hw
gap = 1 if len(halves) == 2 else 0
b.append('<g class="nj-heat-cell" tabindex="0" data-tip="%s">' % esc(tip(lib, label, c, half)))
b.append('<rect class="nj-heat-%d" x="%g" y="%g" width="%g" height="%g" rx="3"/>'
% (heat(r), hx + (gap if k else 0), y + 1, hw - gap, ch - 2))
cx = hx + hw / 2
if half == "alt":
b.append('<text class="nj-charts-cell" x="%g" y="%g" text-anchor="middle">%s</text>' % (cx, y + 16, fr(r)))
b.append('<text class="nj-charts-cell nj-charts-cell--small" x="%g" y="%g" text-anchor="middle">%s</text>'
% (cx, y + 29, c["marks"]))
else:
b.append('<text class="nj-charts-cell" x="%g" y="%g" text-anchor="middle">%s</text>' % (cx, y + ch / 2 + 4, fr(r)))
b.append('</g>')
if c["full"] is None: # no fully validating way: the left half stays empty
pass
desc.append("%s %s: %s%s" % (UC_LIBS[lib], label, fr(c["full"]) if c["full"] else "no fully validating way",
(" (%s doing less, %s)" % (fr(c["alt"]), c["marks"])) if c["alt"] else ""))
# the key, set apart from the grid and narrower than its columns, so that it doesn't read as a row of it
yb = top + len(libs) * ch + 28
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="8" y="%g">time relative to the fastest fully validating library, less is better</text>' % (yb + 4))
kw, ky = 76, yb + 14
for i, lab in enumerate(HEAT_LABELS):
# each swatch in its own group, so that the ink rule for the strong steps (a sibling selector) stays inside it
b.append('<g><rect class="nj-heat-%d" x="%g" y="%g" width="%g" height="20" rx="3"/>' % (i, 8 + i * (kw + 4), ky, kw))
b.append('<text class="nj-charts-cell nj-charts-cell--small" x="%g" y="%g" text-anchor="middle">%s</text></g>' % (8 + i * (kw + 4) + kw / 2, ky + 14, esc(lab)))
nx = 8 + len(HEAT_LABELS) * (kw + 4) + 12
b.append('<rect class="nj-heat-na" x="%g" y="%g" width="%g" height="20" rx="3"/>' % (nx, ky, 40))
b.append('<text class="nj-charts-tick" x="%g" y="%g">n/a</text>' % (nx + 20, ky + 14))
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="%g" y="%g">no API for it</text>' % (nx + 48, ky + 14))
write("perf_blog_usecases_%s.svg" % platform, W, ky + 28, "nj-charts--blog nj-charts--heat", "nj-blog-uc-" + platform, title,
"Table of relative times, libraries by use case. " + "; ".join(desc) + ".", b)
if __name__ == "__main__":
swar()
overlap()
digits()
heldout()
if OVERVIEW:
overview()
distribution()
if TIMELINE:
timeline()
if CLIFFS:
cliffs()
price()
for platform, title in UC_PLATFORMS:
if (HERE / "data" / ("perf_usecases_%s.json" % platform)).exists():
heatmap(platform, title)
@@ -1,66 +0,0 @@
"""Prints the tables of Appendix E of home/blog/how_3_13_0_got_faster.md (comparison with other libraries) as Markdown,
from data/perf_usecases_<platform>.json, which tests/benchmarks/json_view/others/summarize.py --json writes.
Usage: python3 scripts/figures/perf_blog_tables.py <platform> [title]
"""
import json
import sys
from pathlib import Path
from perf_blog import normalize_usecases
HERE = Path(__file__).resolve().parent
FILES = [("twitter", "`twitter.json`"), ("citm_catalog", "`citm_catalog.json`"), ("canada", "`canada.json`"),
("jeopardy", "`jeopardy.json`"), ("status", "one status (2.5 KB)")]
USE_CASES = [("validate", "validate"), ("sum", "sum"), ("select", "select"), ("edit", "edit"), ("minify", "minify"),
("write", "write")]
NAMES = {"nlohmann json_document": "nlohmann/json `json_document`", "nlohmann json": "nlohmann/json `json`",
"sonic-rs": "sonic-rs (Rust)", "simd-json": "simd-json (Rust)", "serde_json": "serde_json (Rust)"}
def fmt(us):
if us >= 10000:
return "{:,.0f}".format(us)
if us >= 100:
return "{:,.0f}".format(us)
return "%.1f" % us
def table(data, uc, indent):
files = [f for f, _ in FILES if f in data.get(uc, {})]
libs = list(data[uc][files[0]].keys())
jd = lambda f: data[uc][f]["nlohmann json_document"]["best"]["us"]
libs.sort(key=lambda l: sum(((data[uc][f][l]["best"] or data[uc][f][l]["best_any"])["us"] / jd(f)) for f in files))
head = "| library | variant | " + " | ".join(n for f, n in FILES if f in files) + " |"
rows = [head, "| --- | --- | " + " | ".join("--:" for _ in files) + " |"]
for lib in libs:
best = [data[uc][f][lib]["best"] for f in files]
anyv = [data[uc][f][lib]["best_any"] for f in files]
names = sorted({b["variant"] for b in best if b} | {a["variant"] + " [%s]" % a["mark"] for b, a in zip(best, anyv) if a["mark"] and (not b or a["us"] < b["us"])})
cells = []
for b, a in zip(best, anyv):
c = fmt(b["us"]) if b else "–"
if a["mark"] and (not b or a["us"] < b["us"] * 0.97):
c += " (%s %s)" % (a["mark"], fmt(a["us"]))
cells.append(c)
bold = "**%s**" if lib == "nlohmann json_document" else "%s"
rows.append("| %s | %s | %s |" % (bold % NAMES.get(lib, lib), ", ".join(names), " | ".join(cells)))
return "\n".join(indent + r for r in rows)
def main():
platform = sys.argv[1]
data = json.load((HERE / "data" / ("perf_usecases_%s.json" % platform)).open())
data = normalize_usecases(data) # the same choices as the figure
out = []
for uc, label in USE_CASES:
if uc not in data:
continue
out.append("**%s**\n" % label)
out.append(table(data, uc, ""))
out.append("")
print("\n".join(out))
if __name__ == "__main__":
main()
@@ -91,7 +91,7 @@ const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/) // LCOV_EXCL_LINE
{
return {}; // LCOV_EXCL_LINE
}
+35 -11
View File
@@ -198,18 +198,19 @@ class exception : public std::exception
// all other parent types (primitives) contribute no token
}
if (tokens.empty())
// the root value has no path, but still has a byte range
std::string prefix;
if (!tokens.empty())
{
return "";
const auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
[](const std::string & a, const std::string & b)
{
return concat(a, '/', detail::escape(b));
});
prefix = concat('(', str, ") ");
}
auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
[](const std::string & a, const std::string & b)
{
return concat(a, '/', detail::escape(b));
});
return concat('(', str, ") ", get_byte_positions(leaf_element));
return concat(prefix, get_byte_positions(leaf_element));
#else
return get_byte_positions(leaf_element);
#endif
@@ -222,7 +223,8 @@ class exception : public std::exception
template<typename BasicJsonType>
static std::string get_byte_positions(const BasicJsonType* leaf_element)
{
if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos))
// a value-initialized iterator has no value (invalid_iterator.212)
if (leaf_element != nullptr && leaf_element->start_pos() != std::string::npos && leaf_element->end_pos() != std::string::npos)
{
return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") ");
}
@@ -431,6 +433,28 @@ std::nullptr_t exception_context(const View& /*unused*/) noexcept
return nullptr;
}
namespace view
{
// the path and bytes of the value of a view (defined in <nlohmann/detail/view/errors.hpp>)
template<typename View>
std::string diagnostics_of(const View& v);
} // namespace view
// what goes in front of the message of an exception about j: nothing for a
// basic_json value (exception_context() passes the value itself), the context
// basic_json would add (JSON_DIAGNOSTICS, JSON_DIAGNOSTIC_POSITIONS) for a view
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
const char* exception_prefix(const BasicJsonType& /*unused*/) noexcept
{
return "";
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
std::string exception_prefix(const View& v)
{
return view::diagnostics_of(v);
}
/*!
@brief throws because @a j does not have the type a conversion expects
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
@@ -442,7 +466,7 @@ JSON_HEDLEY_NO_RETURN JSON_HEDLEY_NEVER_INLINE void throw_type_must_be(const cha
{
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
static_cast<void>(j);
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), exception_context(j)));
JSON_THROW(type_error::create(exception_id::type_mismatch, concat(exception_prefix(j), "type must be ", expected, ", but is ", j.type_name()), exception_context(j)));
}
/*!
+544 -46
View File
@@ -22,6 +22,7 @@
#include <bit> //byteswap
#endif
#include <nlohmann/detail/bit_ops.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp>
@@ -465,15 +466,19 @@ class binary_reader
}
const std::size_t element_type_parse_position = chars_read;
// an array's elements are named "0", "1", ... in the wire format,
// and those names are not passed on: they are skipped, and only
// checked if error_handler_t::strict must reject ill-formed UTF-8
const bool is_object = container_stack.back().is_object;
key.clear();
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
if (JSON_HEDLEY_UNLIKELY(!(is_object || error_handler != error_handler_t::strict
? get_bson_cstr(key, is_object)
: check_bson_cstr(key, std::integral_constant<bool, bulk_scan> {}))))
{
return false;
}
// an array's elements are named "0", "1", ... in the wire format,
// and those names are not passed on
if (container_stack.back().is_object && !sax->key(key))
if (is_object && !sax->key(key))
{
return false;
}
@@ -489,14 +494,18 @@ class binary_reader
@brief Parses a C-style string from the BSON input.
@param[in,out] result A reference to the string variable where the read
string is to be stored.
@param[in] store whether the characters are needed; if not (the names of
an array's elements), they are skipped and @a result may
be left unchanged, and they are not checked against
@ref error_handler (@ref check_bson_cstr checks them)
@return `true` if the \\x00-byte indicating the end of the string was
encountered before the EOF; false` indicates an unexpected EOF.
*/
bool get_bson_cstr(string_t& result)
bool get_bson_cstr(string_t& result, const bool store = true)
{
if (get_bson_cstr_bulk(result, std::integral_constant<bool, bulk_scan> {}))
if (get_bson_cstr_bulk(result, store, std::integral_constant<bool, bulk_scan> {}))
{
return check_string_utf8(result, "key");
return !store || check_string_utf8(result, "key");
}
auto out = std::back_inserter(result);
@@ -509,7 +518,7 @@ class binary_reader
}
if (current == 0x00)
{
return check_string_utf8(result, "key");
return !store || check_string_utf8(result, "key");
}
*out++ = static_cast<typename string_t::value_type>(current);
}
@@ -519,10 +528,11 @@ class binary_reader
@brief read a C-style string from contiguous input in one step
@param[in,out] result the string to append to
@param[in] store whether to append the characters to @a result
@return whether the string was read; if the input has no \\x00-byte, nothing
is read, and @ref get_bson_cstr reports the end of the input
*/
bool get_bson_cstr_bulk(string_t& result, std::true_type /*bulk*/)
bool get_bson_cstr_bulk(string_t& result, const bool store, std::true_type /*bulk*/)
{
const std::size_t remaining = ia.bulk_remaining();
if (remaining == 0)
@@ -530,18 +540,15 @@ class binary_reader
return false;
}
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
// a plain loop rather than std::memchr: most keys are short (array
// indices are keys, too), and the call would cost more than it saves
std::size_t length = 0;
while (length < remaining && data[length] != 0x00)
{
++length;
}
const std::size_t length = find_zero_byte(data, remaining);
if (length == remaining)
{
return false;
}
result.append(reinterpret_cast<const typename string_t::value_type*>(data), length);
if (store)
{
result.append(reinterpret_cast<const typename string_t::value_type*>(data), length);
}
// consume the string and its \x00-byte, as the byte-wise path does
ia.bulk_skip(length + 1);
chars_read += length + 1;
@@ -549,8 +556,44 @@ class binary_reader
return true;
}
/*!
@brief skip a C-style string that error_handler_t::strict must check
The names of an array's elements are not passed on. On contiguous input,
a well-formed name is checked in place and skipped without being copied.
Otherwise (no \\x00-byte in the input that can be scanned, or ill-formed
UTF-8), it is read by @ref get_bson_cstr, which reports the error.
@param[in,out] result an empty string, which may receive the name
@return whether the name was read and is well-formed
*/
bool check_bson_cstr(string_t& result, std::true_type /*bulk*/)
{
const std::size_t remaining = ia.bulk_remaining();
if (remaining != 0)
{
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
const std::size_t length = find_zero_byte(data, remaining);
if (length != remaining && JSON_HEDLEY_LIKELY(valid_utf8_string(data, length)))
{
// consume the string and its \x00-byte, as get_bson_cstr does
ia.bulk_skip(length + 1);
chars_read += length + 1;
current = 0x00;
return true;
}
}
return get_bson_cstr(result);
}
/// input that is not contiguous: the name is read and checked byte by byte
bool check_bson_cstr(string_t& result, std::false_type /*bulk*/)
{
return get_bson_cstr(result);
}
/// input that is not contiguous: C-style strings are read byte by byte
bool get_bson_cstr_bulk(string_t& /*result*/, std::false_type /*bulk*/) const noexcept
bool get_bson_cstr_bulk(string_t& /*result*/, const bool /*store*/, std::false_type /*bulk*/) const noexcept
{
return false;
}
@@ -741,11 +784,13 @@ class binary_reader
bool get_cbor_negative_integer()
{
NumberType number{};
if (JSON_HEDLEY_UNLIKELY(!get_number(number)))
{
return false;
}
return get_number(number) && emit_cbor_negative_integer(number);
}
/// pass the CBOR negative integer -1 - @a number to the SAX parser
template<typename NumberType>
bool emit_cbor_negative_integer(const NumberType number)
{
// the value is -1 - number, which fits into number_integer_t
// whenever number does; the outer cast undoes the integral promotion
// for number_integer_t types narrower than int
@@ -970,7 +1015,7 @@ class binary_reader
case 0x95:
case 0x96:
case 0x97:
return enter_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
return enter_cbor_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
case 0x98: // array (one-byte uint8_t for n follows)
case 0x99: // array (two-byte uint16_t for n follow)
@@ -979,7 +1024,7 @@ class binary_reader
{
std::uint64_t len{};
std::size_t size{};
return get_cbor_argument(len) && get_cbor_container_size(len, size, "array") && enter_array(size);
return get_cbor_argument(len) && get_cbor_container_size(len, size, "array") && enter_cbor_array(size);
}
case 0x9F: // array (indefinite length)
@@ -1133,16 +1178,10 @@ class binary_reader
return get_half_float(false);
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
{
float number{};
return get_number(number) && emit_float(number);
}
return get_cbor_float<float>();
case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
{
double number{};
return get_number(number) && emit_float(number);
}
return get_cbor_float<double>();
default: // anything else (0xFF is handled inside the other types)
{
@@ -1151,6 +1190,14 @@ class binary_reader
}
}
/// read a single- or double-precision float
template<typename NumberType>
bool get_cbor_float()
{
NumberType number{};
return get_number(number) && emit_float(number);
}
/*!
@brief reports a nested indefinite-length CBOR string or byte array
@param[in] type_name name of the rejected string type
@@ -1676,6 +1723,159 @@ class binary_reader
return true;
}
/*!
@brief read a big-endian number of type @a NumberType at @a data
*/
template<typename NumberType>
NumberType load_big_endian(const unsigned char* data) const noexcept
{
NumberType result{};
std::memcpy(&result, data, sizeof(NumberType));
if (is_little_endian)
{
byte_swap(result);
}
return result;
}
/*!
@brief read the integers, floats, booleans, and nulls that follow in a
definite-length array, without the per-element bookkeeping of
@ref parse_cbor_internal
Stops at the end of the array, at any other kind of value, and when fewer
than 9 bytes (the longest of these values) are left in the input, leaving
those to @ref parse_cbor_value, which reads them the same way.
Out of line, so that @ref parse_cbor_value stays small enough to be inlined.
The array is the one on top of @ref container_stack; its count of
elements not yet read is updated.
@return whether the SAX parser accepted the values
*/
JSON_HEDLEY_NEVER_INLINE
bool parse_cbor_scalar_run(std::true_type /*bulk*/)
{
// nothing pushes onto the stack while the run reads scalars
std::size_t& remaining = container_stack.back().remaining;
while (remaining != 0 && ia.bulk_remaining() >= 9)
{
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
const unsigned char head = data[0];
std::size_t size = 0;
bool accepted = false;
switch (head)
{
case 0x18:
size = 2;
accepted = emit_unsigned(data[1]);
break;
case 0x19:
size = 3;
accepted = emit_unsigned(load_big_endian<std::uint16_t>(data + 1));
break;
case 0x1A:
size = 5;
accepted = emit_unsigned(load_big_endian<std::uint32_t>(data + 1));
break;
case 0x1B:
size = 9;
accepted = emit_unsigned(load_big_endian<std::uint64_t>(data + 1));
break;
case 0x38:
size = 2;
accepted = emit_cbor_negative_integer(data[1]);
break;
case 0x39:
size = 3;
accepted = emit_cbor_negative_integer(load_big_endian<std::uint16_t>(data + 1));
break;
case 0x3A:
size = 5;
accepted = emit_cbor_negative_integer(load_big_endian<std::uint32_t>(data + 1));
break;
case 0x3B:
size = 9;
accepted = emit_cbor_negative_integer(load_big_endian<std::uint64_t>(data + 1));
break;
case 0xF4:
size = 1;
accepted = sax->boolean(false);
break;
case 0xF5:
size = 1;
accepted = sax->boolean(true);
break;
case 0xF6:
size = 1;
accepted = sax->null();
break;
case 0xFA:
size = 5;
accepted = emit_float(load_big_endian<float>(data + 1));
break;
case 0xFB:
size = 9;
accepted = emit_float(load_big_endian<double>(data + 1));
break;
default:
if (head <= 0x17)
{
size = 1;
accepted = sax->number_unsigned(static_cast<number_unsigned_t>(head));
}
else if (head >= 0x20 && head <= 0x37)
{
size = 1;
accepted = sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - head));
}
else
{
// any other value is read by parse_cbor_value
return true;
}
break;
}
// as if read by get() and get_number(): current is the head byte
ia.bulk_skip(size);
chars_read += size;
current = head;
--remaining;
if (JSON_HEDLEY_UNLIKELY(!accepted))
{
return false;
}
}
return true;
}
/*!
@brief open a definite-length array and read the scalars it begins with
(see @ref parse_cbor_scalar_run)
Only the start of an array is tried, which covers arrays of numbers
(e.g. coordinates) but costs arrays of other values only one call, not one
per element. An array of one element is not tried at all: that element is
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
polygon), for which the call would find no scalar, while a single scalar,
which the run would read faster, is rare. The benchmarks
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
@param[in] len the number of elements
@return whether the SAX parser accepted the array and the values read
*/
bool enter_cbor_array(const std::size_t len)
{
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
}
/// input that is not contiguous: every value is read by parse_cbor_value
bool parse_cbor_scalar_run(std::false_type /*bulk*/) const noexcept
{
return true;
}
/*!
@brief read a CBOR value and everything nested inside it
@@ -1705,6 +1905,7 @@ class binary_reader
// pop_back() below, which destroys the container_stack element
// it would otherwise alias
const container_frame top = container_stack.back();
const bool is_object = top.is_object;
bool at_end = false;
if (top.remaining != npos)
@@ -1716,7 +1917,7 @@ class binary_reader
{
// claim the element about to be read
--container_stack.back().remaining;
if (top.is_object)
if (is_object)
{
get();
}
@@ -1729,7 +1930,7 @@ class binary_reader
// Testing for it consumes a byte, which is the first byte
// of the next element when it is not one.
at_end = (get() == 0xFF);
fetch = top.is_object;
fetch = is_object;
}
if (at_end)
@@ -1746,7 +1947,7 @@ class binary_reader
continue;
}
if (top.is_object)
if (is_object)
{
if (JSON_HEDLEY_UNLIKELY(!skip_cbor_key_tags(tag_handler)))
{
@@ -1971,7 +2172,7 @@ class binary_reader
case 0x9D:
case 0x9E:
case 0x9F:
return enter_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
return enter_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixstr
case 0xA0:
@@ -2102,13 +2303,13 @@ class binary_reader
case 0xDC: // array 16
{
std::uint16_t len{};
return get_number(len) && enter_array(static_cast<std::size_t>(len));
return get_number(len) && enter_msgpack_array(static_cast<std::size_t>(len));
}
case 0xDD: // array 32
{
std::uint32_t len{};
return get_number(len) && enter_array(conditional_static_cast<std::size_t>(len));
return get_number(len) && enter_msgpack_array(conditional_static_cast<std::size_t>(len));
}
case 0xDE: // map 16
@@ -2450,6 +2651,141 @@ class binary_reader
}
}
/*!
@brief read the integers, floats, booleans, and nils that follow in a
MessagePack array, without the per-element bookkeeping of
@ref parse_msgpack_internal
Stops at the end of the array, at any other kind of value, and when fewer
than 9 bytes (the longest of these values) are left in the input, leaving
those to @ref parse_msgpack_value, which reads them the same way.
Out of line, so that @ref parse_msgpack_value stays small enough to be inlined.
The array is the one on top of @ref container_stack; its count of
elements not yet read is updated.
@return whether the SAX parser accepted the values
*/
JSON_HEDLEY_NEVER_INLINE
bool parse_msgpack_scalar_run(std::true_type /*bulk*/)
{
// nothing pushes onto the stack while the run reads scalars
std::size_t& remaining = container_stack.back().remaining;
while (remaining != 0 && ia.bulk_remaining() >= 9)
{
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
const unsigned char head = data[0];
std::size_t size = 0;
bool accepted = false;
switch (head)
{
case 0xC0: // nil
size = 1;
accepted = sax->null();
break;
case 0xC2: // false
size = 1;
accepted = sax->boolean(false);
break;
case 0xC3: // true
size = 1;
accepted = sax->boolean(true);
break;
case 0xCA: // float 32
size = 5;
accepted = emit_float(load_big_endian<float>(data + 1));
break;
case 0xCB: // float 64
size = 9;
accepted = emit_float(load_big_endian<double>(data + 1));
break;
case 0xCC: // uint 8
size = 2;
accepted = emit_unsigned(data[1]);
break;
case 0xCD: // uint 16
size = 3;
accepted = emit_unsigned(load_big_endian<std::uint16_t>(data + 1));
break;
case 0xCE: // uint 32
size = 5;
accepted = emit_unsigned(load_big_endian<std::uint32_t>(data + 1));
break;
case 0xCF: // uint 64
size = 9;
accepted = emit_unsigned(load_big_endian<std::uint64_t>(data + 1));
break;
case 0xD0: // int 8
size = 2;
accepted = emit_signed(static_cast<std::int8_t>(data[1]));
break;
case 0xD1: // int 16
size = 3;
accepted = emit_signed(load_big_endian<std::int16_t>(data + 1));
break;
case 0xD2: // int 32
size = 5;
accepted = emit_signed(load_big_endian<std::int32_t>(data + 1));
break;
case 0xD3: // int 64
size = 9;
accepted = emit_signed(load_big_endian<std::int64_t>(data + 1));
break;
default:
if (head <= 0x7F)
{
// positive fixint
size = 1;
accepted = sax->number_unsigned(static_cast<number_unsigned_t>(head));
}
else if (head >= 0xE0)
{
// negative fixint
size = 1;
accepted = sax->number_integer(static_cast<std::int8_t>(head));
}
else
{
// any other value is read by parse_msgpack_value
return true;
}
break;
}
// as if read by get() and get_number(): current is the last byte
ia.bulk_skip(size);
chars_read += size;
current = data[size - 1];
--remaining;
if (JSON_HEDLEY_UNLIKELY(!accepted))
{
return false;
}
}
return true;
}
/*!
@brief open a MessagePack array and read the scalars it begins with (see
@ref parse_msgpack_scalar_run)
An array of one element is not tried, for the reason given at
@ref enter_cbor_array.
@param[in] len the number of elements
@return whether the SAX parser accepted the array and the values read
*/
bool enter_msgpack_array(const std::size_t len)
{
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
}
/// input that is not contiguous: every value is read by parse_msgpack_value
bool parse_msgpack_scalar_run(std::false_type /*bulk*/) const noexcept
{
return true;
}
/*!
@brief read a MessagePack value and everything nested inside it
@@ -3255,6 +3591,107 @@ class binary_reader
return unexpected_byte("invalid byte", "value");
}
/*!
@brief read the elements of an optimized array of numbers (type marker
@a type) that are in the input, in one loop, without the
per-element bookkeeping of @ref parse_ubjson_internal
Values are emitted as @ref get_ubjson_value emits them. Types other than
the fixed-size integers and floats are left to @ref get_ubjson_value, as
are the elements the input ends before.
@param[in,out] remaining the number of elements not yet read
@param[in] type the type marker of the elements
@return whether the SAX parser accepted the values
*/
JSON_HEDLEY_NEVER_INLINE
bool parse_ubjson_typed_run(std::size_t& remaining, const char_int_type type, std::true_type /*bulk*/)
{
const bool bjdata = input_format == input_format_t::bjdata;
switch (type)
{
case 'U':
return parse_ubjson_typed_run<std::uint8_t>(remaining);
case 'i':
return parse_ubjson_typed_run<std::int8_t>(remaining);
case 'I':
return parse_ubjson_typed_run<std::int16_t>(remaining);
case 'l':
return parse_ubjson_typed_run<std::int32_t>(remaining);
case 'L':
return parse_ubjson_typed_run<std::int64_t>(remaining);
case 'u':
return !bjdata || parse_ubjson_typed_run<std::uint16_t>(remaining);
case 'm':
return !bjdata || parse_ubjson_typed_run<std::uint32_t>(remaining);
case 'M':
return !bjdata || parse_ubjson_typed_run<std::uint64_t>(remaining);
case 'd':
return parse_ubjson_typed_run<float>(remaining);
case 'D':
return parse_ubjson_typed_run<double>(remaining);
default:
return true;
}
}
/// input that is not contiguous: every element is read by get_ubjson_value
bool parse_ubjson_typed_run(std::size_t& /*remaining*/, const char_int_type /*type*/, std::false_type /*bulk*/) const noexcept
{
return true;
}
template<typename NumberType>
bool parse_ubjson_typed_run(std::size_t& remaining)
{
constexpr std::size_t size = sizeof(NumberType);
const std::size_t count = (std::min)(remaining, ia.bulk_remaining() / size);
if (count == 0)
{
return true;
}
const auto* const data = reinterpret_cast<const unsigned char*>(ia.bulk_data());
// UBJSON stores numbers big-endian, BJData little-endian
const bool swap = is_little_endian != (input_format == input_format_t::bjdata);
std::size_t read = 0;
bool accepted = true;
while (read < count && accepted)
{
NumberType number{};
std::memcpy(&number, data + (read * size), size);
if (swap)
{
byte_swap(number);
}
++read;
accepted = emit_ubjson_number(number);
}
// as if read by get_number(): current is the last byte read
ia.bulk_skip(read * size);
chars_read += read * size;
current = data[(read * size) - 1];
remaining -= read;
return accepted;
}
template<typename NumberType, enable_if_t<std::is_floating_point<NumberType>::value, int> = 0>
bool emit_ubjson_number(const NumberType number)
{
return emit_float(number);
}
template < typename NumberType, enable_if_t < std::is_integral<NumberType>::value&& std::is_signed<NumberType>::value, int > = 0 >
bool emit_ubjson_number(const NumberType number)
{
return emit_signed(number);
}
template < typename NumberType, enable_if_t < std::is_integral<NumberType>::value&& !std::is_signed<NumberType>::value, int > = 0 >
bool emit_ubjson_number(const NumberType number)
{
return emit_unsigned(number);
}
/*!
@return whether array creation completed
*/
@@ -3290,7 +3727,15 @@ class binary_reader
return false;
}
for (std::size_t i = 0; i < size_and_type.first; ++i)
// the numbers that are in the input, in one loop; the rest (if
// the input ends early) one by one below
std::size_t remaining = size_and_type.first;
if (!nd_is_char && JSON_HEDLEY_UNLIKELY(!parse_ubjson_typed_run(remaining, size_and_type.second, std::integral_constant<bool, bulk_scan> {})))
{
return false;
}
for (std::size_t i = size_and_type.first - remaining; i < size_and_type.first; ++i)
{
if (nd_is_char)
{
@@ -3350,7 +3795,8 @@ class binary_reader
container_stack.back().remaining = 0;
}
return true;
return size_and_type.second == 0
|| parse_ubjson_typed_run(container_stack.back().remaining, size_and_type.second, std::integral_constant<bool, bulk_scan> {});
}
return enter_array(detail::unknown_size());
@@ -3691,13 +4137,13 @@ class binary_reader
return sax->null();
case 0xFB:
return sax->number_float(static_cast<number_float_t>(-1.0), "");
return sax->number_float(static_cast<number_float_t>(-1.0), no_source);
case 0xFC:
return sax->number_float(static_cast<number_float_t>(0.0), "");
return sax->number_float(static_cast<number_float_t>(0.0), no_source);
case 0xFD:
return sax->number_float(static_cast<number_float_t>(1.0), "");
return sax->number_float(static_cast<number_float_t>(1.0), no_source);
case 0xFF: // empty string
{
@@ -4020,7 +4466,12 @@ class binary_reader
`char_traits<char_type>::eof()` in that case.
@return character read from the input
@note always inlined: GCC otherwise stops inlining the stream adapter's
get_character() into parse_cbor_internal once that function grows
(+0.45 % instructions for CBOR from a std::istringstream with GCC 13)
*/
JSON_HEDLEY_ALWAYS_INLINE
char_int_type get()
{
++chars_read;
@@ -4066,6 +4517,27 @@ class binary_reader
return current;
}
/// reverse the byte order of a double with a single byteswap(): GCC does
/// not merge the byte-wise swap of the generic version into one
static void byte_swap(double& number) noexcept
{
static_assert(sizeof(double) == sizeof(std::uint64_t), "double must have 64 bits");
std::uint64_t bits{};
std::memcpy(&bits, &number, sizeof(bits));
bits = byteswap(bits);
std::memcpy(&number, &bits, sizeof(bits));
}
/// reverse the byte order of a float with a single byteswap()
static void byte_swap(float& number) noexcept
{
static_assert(sizeof(float) == sizeof(std::uint32_t), "float must have 32 bits");
std::uint32_t bits{};
std::memcpy(&bits, &number, sizeof(bits));
bits = byteswap(bits);
std::memcpy(&number, &bits, sizeof(bits));
}
template<class NumberType>
static void byte_swap(NumberType& number)
{
@@ -4201,7 +4673,7 @@ class binary_reader
{
return out_of_range_error(exception_id::number_overflow, "number overflow", "value");
}
return sax->number_float(result, "");
return sax->number_float(result, no_source);
}
/*!
@@ -4261,7 +4733,7 @@ class binary_reader
}();
return sax->number_float((half & 0x8000u) != 0
? static_cast<number_float_t>(-val)
: static_cast<number_float_t>(val), "");
: static_cast<number_float_t>(val), no_source);
}
/*!
@@ -4293,6 +4765,19 @@ class binary_reader
return get_bytes(len, "string", result);
}
/// whether @a s is valid UTF-8: ASCII eight bytes at a time, the rest
/// sequence by sequence (as the binary writers check strings)
static bool is_valid_utf8_string(const string_t& s, std::true_type /*is_byte*/) noexcept
{
return valid_utf8_string(reinterpret_cast<const unsigned char*>(s.data()), s.size());
}
/// whether @a s, of a character type wider than a byte, is valid UTF-8
static bool is_valid_utf8_string(const string_t& s, std::false_type /*is_byte*/) noexcept
{
return is_valid_utf8(s);
}
/*!
@brief validate a decoded text string (value or object key) against @ref error_handler
@@ -4312,7 +4797,16 @@ class binary_reader
*/
bool check_string_utf8(string_t& result, const char* context)
{
if (error_handler == error_handler_t::keep || is_valid_utf8(result))
return error_handler == error_handler_t::keep || check_string_utf8_handler(result, context);
}
/// @ref check_string_utf8 for an error handler other than @ref
/// error_handler_t::keep; out of line, so that reading strings without a
/// check does not pay for the code of the check
JSON_HEDLEY_NEVER_INLINE
bool check_string_utf8_handler(string_t& result, const char* context)
{
if (is_valid_utf8_string(result, std::integral_constant<bool, sizeof(typename string_t::value_type) == 1>()))
{
return true;
}
@@ -4586,6 +5080,10 @@ class binary_reader
/// the SAX parser
json_sax_t* sax = nullptr;
/// the (empty) source text of every number_float event: binary formats
/// have none, and a string_t built for each float would cost more
const string_t no_source{};
/// the containers that have been opened and not closed yet; see @ref container_frame
std::vector<container_frame> container_stack{};
@@ -545,12 +545,9 @@ class input_stream_adapter
std::char_traits<char>::int_type get_character_slow()
{
#if !JSON_DISABLE_STREAM_BULK_SCAN
// sbumpc() refills the get area if it is exhausted
const bool refill = streambuf_access::get_ptr(sb) == streambuf_access::get_end(sb);
if (JSON_HEDLEY_UNLIKELY(refill))
{
save_token_segment();
}
// the get area is exhausted (get_character() handles the other case),
// so sbumpc() refills it
save_token_segment();
#endif
auto res = sb->sbumpc();
@@ -563,17 +560,13 @@ class input_stream_adapter
is->clear(is->rdstate() | std::ios::eofbit);
}
#if !JSON_DISABLE_STREAM_BULK_SCAN
else if (JSON_HEDLEY_UNLIKELY(refill))
else
{
// the consumed character is at gptr() - 1, unless the streambuf
// has no get area and returned it from uflow()
const char* const next = streambuf_access::get_ptr(sb);
after_refill(res, next != nullptr && next != streambuf_access::get_begin(sb));
}
else
{
current_in_get_area = true;
}
#endif
return res;
}
+25 -6
View File
@@ -999,7 +999,7 @@ class json_sax_dom_parser : public json_sax_dom_error_state
ordered_data.members[f.ordered.dest_member].second = std::move(value);
}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {}
static void place_member(const frame& /*f*/, BasicJsonType&& /*value*/, std::false_type /*indexed*/) noexcept {} // LCOV_EXCL_LINE
/// store the members of a new object directly in it
bool start_stored_object(std::size_t len)
@@ -1303,7 +1303,7 @@ class json_sax_dom_parser : public json_sax_dom_error_state
{
// a new member is null and holds nothing: construct the value
// over it instead of destroying and swapping
::new (static_cast<void*>(&member)) BasicJsonType(std::forward<Value>(v));
construct_member(member, std::forward<Value>(v), std::is_nothrow_constructible<BasicJsonType, Value> {});
}
else
{
@@ -1312,6 +1312,26 @@ class json_sax_dom_parser : public json_sax_dom_error_state
}
}
/// constructing the value cannot throw (for example a number or a boolean): construct it in place
template<typename Value>
JSON_HEDLEY_ALWAYS_INLINE
static void construct_member(BasicJsonType& member, Value&& v, std::true_type /*nothrow*/)
{
::new (static_cast<void*>(&member)) BasicJsonType(std::forward<Value>(v));
}
/// constructing the value can throw (for example a container or a string), and a
/// constructor that was interrupted must not have touched the member (#5985):
/// create the value first, then move it over the member (the move constructor is
/// noexcept)
template<typename Value>
JSON_HEDLEY_ALWAYS_INLINE
static void construct_member(BasicJsonType& member, Value&& v, std::false_type /*may throw*/)
{
BasicJsonType value(std::forward<Value>(v));
::new (static_cast<void*>(&member)) BasicJsonType(std::move(value));
}
/// a custom base class may care about the lifetime of the value
template<typename Value>
static void set_member(BasicJsonType& member, Value&& v, std::false_type /*custom base*/)
@@ -1737,7 +1757,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
key_stack.push_back(val);
// add discarded value at the given key and store the reference for later
if (keep && ref_stack.back())
if (keep)
{
auto& obj = *ref_stack.back()->m_data.m_value.object;
// a single lookup: insert the placeholder, or find the existing member
@@ -1794,7 +1814,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
const string_t object_key = pop_container();
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
if (!ref_stack.empty() && ref_stack.back())
{
// remove discarded value
remove_discarded_value(*ref_stack.back(), object_key);
@@ -1960,8 +1980,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
*/
string_t current_key() const
{
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object()
&& !key_stack.empty())
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object())
{
return key_stack.back();
}
+113 -65
View File
@@ -209,8 +209,13 @@ constexpr bool input_adapter_bulk_window(std::false_type /*detected*/)
@brief lexical analysis
This class organizes the lexical analysis during JSON deserialization.
DiscardValues: the caller only needs the token types and never looks at the values of number and string tokens (only
accept(), which parses through json_sax_acceptor). A template parameter rather than a member, so that the lexer of
parse() is compiled without the paths of accept(): with both string scans in one scan(), parse() was up to 2 % slower
on Apple M1.
*/
template<typename BasicJsonType, typename InputAdapterType>
template<typename BasicJsonType, typename InputAdapterType, bool DiscardValues = false>
class lexer : public lexer_base<BasicJsonType>
{
using number_integer_t = typename BasicJsonType::number_integer_t;
@@ -268,10 +273,9 @@ class lexer : public lexer_base<BasicJsonType>
public:
using token_type = typename lexer_base<BasicJsonType>::token_type;
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false, bool discard_number_values_ = false) noexcept
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
: ia(std::move(adapter))
, ignore_comments(ignore_comments_)
, discard_number_values(discard_number_values_)
{
// the token string of an error before the first token is everything
// read so far
@@ -296,14 +300,16 @@ class lexer : public lexer_base<BasicJsonType>
/// calls would (including the position and token bookkeeping of a
/// streaming adapter, see bulk_consume) and leaves @a current holding the last of
/// the 4 digits, just as the last such get() would; the codepoint is
/// written to @a out. Makes no state change and returns false for a
/// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
/// being a hex digit, so the caller falls back unchanged to the
/// per-character loop, which then reports the same diagnostic (stopping
/// at the first invalid digit) as before this optimization.
/// written to @a out. Makes no state change and returns false for fewer
/// than 4 remaining bytes or any of the 4 bytes not being a hex digit, so
/// the caller falls back unchanged to the per-character loop, which then
/// reports the same diagnostic (stopping at the first invalid digit) as
/// before this optimization.
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
{
if (next_unget || ia.bulk_remaining() < 4)
// no unget is pending inside a string (see get_after_string_run())
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < 4)
{
return false;
}
@@ -388,6 +394,8 @@ class lexer : public lexer_base<BasicJsonType>
checks if it is inside the range. If a violation was detected, set up an
error message and return false. Otherwise, return true.
@param[in] keep whether the bytes are added to token_buffer (false for
accept(), see scan())
@param[in] ranges list of integers; interpreted as list of pairs of
inclusive lower and upper bound, respectively
@@ -396,17 +404,18 @@ class lexer : public lexer_base<BasicJsonType>
@return true if and only if no range violation was detected
*/
bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
template<bool Keep>
bool next_byte_in_range(std::integral_constant<bool, Keep> keep, std::initializer_list<char_int_type> ranges)
{
JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
add(current);
add_string_char(keep, current);
for (auto range = ranges.begin(); range != ranges.end(); ++range)
{
get();
if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)
{
add(current);
add_string_char(keep, current);
}
else
{
@@ -419,20 +428,21 @@ class lexer : public lexer_base<BasicJsonType>
}
/// contiguous input: bulk-append the run of ordinary characters and complete
/// well-formed UTF-8 sequences starting at the current read position, then
/// well-formed UTF-8 sequences starting at the current read position (only
/// skip it if @a keep is false), then
/// read the first byte that needs individual handling (the closing quote, an
/// escape, a control character, or an ill-formed UTF-8 byte) like get().
/// That byte is taken from the buffer that was just scanned. Through get(),
/// Apple Clang merged this read with the other get() calls of the scan
/// function, which load the read position again right after it was stored
/// (3% of json::accept() on jeopardy.json on Apple M1).
char_int_type get_after_string_run(std::true_type /*bulk*/)
template<bool Keep>
char_int_type get_after_string_run(std::true_type /*bulk*/, std::integral_constant<bool, Keep> keep)
{
// a pending unget must be consumed through the normal path first
if (next_unget)
{
return get();
}
// scan_string() is entered from scan_after_whitespace(), whose current
// was read by skip_whitespace() (its first get() clears a pending
// unget), and nothing in scan_string() calls unget()
JSON_ASSERT(!next_unget);
const std::size_t remaining = ia.bulk_remaining();
if (remaining == 0)
{
@@ -444,7 +454,7 @@ class lexer : public lexer_base<BasicJsonType>
const std::size_t pos = lexer_string_bulk_run(data, remaining);
if (pos != 0)
{
token_buffer.append(reinterpret_cast<const typename string_t::value_type*>(data), pos);
append_string_run(keep, data, pos);
bulk_consume(reinterpret_cast<const char*>(data), pos);
}
if (pos == remaining)
@@ -488,7 +498,8 @@ class lexer : public lexer_base<BasicJsonType>
}
/// streaming input: no bulk fast path
char_int_type get_after_string_run(std::false_type /*bulk*/)
template<bool Keep>
char_int_type get_after_string_run(std::false_type /*bulk*/, std::integral_constant<bool, Keep> /*keep*/)
{
return get();
}
@@ -502,13 +513,18 @@ class lexer : public lexer_base<BasicJsonType>
may contain \0 bytes), and token_buffer.size() is the number of bytes in the
string.
@param[in] keep whether the string is copied into token_buffer; if false
(accept(), see scan()), it is only checked, with the same
errors, and token_buffer stays empty
@return token_type::value_string if string could be successfully scanned,
token_type::parse_error otherwise
@note In case of errors, variable error_message contains a textual
description.
*/
token_type scan_string()
template<bool Keep>
token_type scan_string(std::integral_constant<bool, Keep> keep)
{
// reset token_buffer (ignore opening quote)
reset();
@@ -520,7 +536,7 @@ class lexer : public lexer_base<BasicJsonType>
{
// bulk-consume ordinary characters from contiguous input, then
// get the next character, the one that ends the run
switch (get_after_string_run(std::integral_constant<bool, bulk_scan>()))
switch (get_after_string_run(std::integral_constant<bool, bulk_scan>(), keep))
{
// end of file while parsing the string
case char_traits<char_type>::eof():
@@ -542,35 +558,35 @@ class lexer : public lexer_base<BasicJsonType>
{
// quotation mark
case '\"':
add('\"');
add_string_char(keep, '\"');
break;
// reverse solidus
case '\\':
add('\\');
add_string_char(keep, '\\');
break;
// solidus
case '/':
add('/');
add_string_char(keep, '/');
break;
// backspace
case 'b':
add('\b');
add_string_char(keep, '\b');
break;
// form feed
case 'f':
add('\f');
add_string_char(keep, '\f');
break;
// line feed
case 'n':
add('\n');
add_string_char(keep, '\n');
break;
// carriage return
case 'r':
add('\r');
add_string_char(keep, '\r');
break;
// tab
case 't':
add('\t');
add_string_char(keep, '\t');
break;
// unicode escapes
@@ -638,10 +654,7 @@ class lexer : public lexer_base<BasicJsonType>
JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
// translate codepoint into bytes
encode_utf8(static_cast<std::uint32_t>(codepoint), [this](std::uint32_t byte)
{
add(static_cast<char_int_type>(byte));
});
add_codepoint(keep, codepoint);
break;
}
@@ -824,7 +837,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0x7E:
case 0x7F:
{
add(current);
add_string_char(keep, current);
break;
}
@@ -860,7 +873,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xDE:
case 0xDF:
{
if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range(keep, {0x80, 0xBF})))
{
return token_type::parse_error;
}
@@ -870,7 +883,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case 0xE0:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0xA0, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -894,7 +907,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xEE:
case 0xEF:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -904,7 +917,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+D000..U+D7FF: bytes ED 80..9F 80..BF
case 0xED:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0x80, 0x9F, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -914,7 +927,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case 0xF0:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -926,7 +939,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xF2:
case 0xF3:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -936,7 +949,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case 0xF4:
{
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range(keep, {0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -1398,7 +1411,7 @@ scan_number_done:
return token_type::value_unsigned;
}
}
else if (number_type == token_type::value_integer)
else // value_integer (the callers handle value_float themselves)
{
if (parse_integer_signed(first, last, value_integer))
{
@@ -1427,7 +1440,7 @@ scan_number_done:
token_type convert_number(token_type number_type, std::size_t mantissa_end)
{
// accept() only needs to know whether the input is valid, so it sets
// discard_number_values (see json.hpp), and an integer token whose
// discard_values (see json.hpp), and an integer token whose
// digit count shows that it fits is reported without calling
// convert_integer(). A number with up to 18 digits always fits into
// both std::uint64_t and std::int64_t (18 nines is about 1e18, below
@@ -1442,7 +1455,7 @@ scan_number_done:
// json_sax_acceptor, whose number callbacks discard their argument and
// return true, and the parser rejects neither integers nor finite
// floats. value_unsigned/value_integer are left unset here, so a caller
// that reads the converted value must not set discard_number_values.
// that reads the converted value must not set discard_values.
//
// On contiguous input, scan_number_bulk_contiguous() converts integer
// tokens itself and does not pass them to this function, unless
@@ -1450,7 +1463,7 @@ scan_number_done:
// reached for input without bulk access (e.g. streams), with
// JSON_DIAGNOSTIC_POSITIONS, or when scan_number_bulk_contiguous()
// falls back to scan_number().
if (discard_number_values)
if (discard_values())
{
constexpr std::size_t safe_digit_count = 18;
if (number_type == token_type::value_unsigned && token_buffer.size() <= safe_digit_count)
@@ -1504,11 +1517,9 @@ scan_number_done:
*/
token_type scan_number_bulk_contiguous()
{
// a pending unget offsets the buffer position from current; fall back
if (next_unget)
{
return token_type::uninitialized;
}
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
const std::size_t rem = ia.bulk_remaining();
if (rem == 0)
{
@@ -1529,11 +1540,7 @@ scan_number_done:
if (data[0] == '-')
{
number_type = token_type::value_integer;
i = 1;
if (i >= avail)
{
return token_type::uninitialized;
}
i = 1; // avail >= 2: rem == 0 returned above
}
const std::size_t integer_begin = i;
if (data[i] == '0')
@@ -1701,7 +1708,7 @@ scan_number_done:
// w < 10^19, so a value below 10^max_exponent10 cannot overflow, and a
// value that underflows is a finite number as well. Only a token that
// may overflow has to be converted to find out.
if (JSON_HEDLEY_UNLIKELY(discard_number_values && s.exponent + 19 <= std::numeric_limits<number_float_t>::max_exponent10))
if (JSON_HEDLEY_UNLIKELY(discard_values() && s.exponent + 19 <= std::numeric_limits<number_float_t>::max_exponent10))
{
value_float = 0;
return true;
@@ -1775,7 +1782,10 @@ scan_number_done:
/// the error at the right character
JSON_HEDLEY_ALWAYS_INLINE bool scan_literal_bulk(const char* rest, const std::size_t length, std::true_type /*bulk*/)
{
if (next_unget || ia.bulk_remaining() < length
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < length
|| std::memcmp(ia.bulk_data(), rest, length) != 0)
{
return false;
@@ -2033,6 +2043,34 @@ scan_number_done:
token_buffer.push_back(static_cast<typename string_t::value_type>(c));
}
/// add a character of a string token; accept() checks the string but does
/// not keep its value (@a keep is false)
void add_string_char(std::true_type /*keep*/, char_int_type c)
{
token_buffer.push_back(static_cast<typename string_t::value_type>(c));
}
static void add_string_char(std::false_type /*keep*/, char_int_type /*c*/) noexcept {}
/// add the UTF-8 bytes of a code point from a \\u escape to a string token
void add_codepoint(std::true_type /*keep*/, int codepoint)
{
encode_utf8(static_cast<std::uint32_t>(codepoint), [this](std::uint32_t byte)
{
add(static_cast<char_int_type>(byte));
});
}
static void add_codepoint(std::false_type /*keep*/, int /*codepoint*/) noexcept {}
/// append a run of ordinary string characters (see get_after_string_run())
void append_string_run(std::true_type /*keep*/, const unsigned char* data, std::size_t n)
{
token_buffer.append(reinterpret_cast<const typename string_t::value_type*>(data), n);
}
static void append_string_run(std::false_type /*keep*/, const unsigned char* /*data*/, std::size_t /*n*/) noexcept {}
public:
/////////////////////
// value getters
@@ -2427,7 +2465,9 @@ scan_number_done:
// string
case '\"':
return scan_string();
// accept() (DiscardValues) checks strings without copying them
// into token_buffer
return scan_string(keep_strings {});
// number
case '-':
@@ -2512,11 +2552,19 @@ scan_number_done:
std::size_t decimal_point_position = std::string::npos;
/// whether the caller only needs the token types and never looks at the
/// converted numeric values; set only by accept(), which parses through
/// json_sax_acceptor. When set, convert_number() skips converting integer
/// tokens whose digit count guarantees that they fit into 64 bits (see
/// there)
const bool discard_number_values = false;
/// values of number and string tokens; DiscardValues, set only by accept(), which parses
/// through json_sax_acceptor. When set, convert_number() skips converting
/// integer tokens whose digit count guarantees that they fit into 64 bits
/// (see there), floats are converted only when they may overflow (see
/// convert_accumulated_float()), and strings are checked without being
/// copied into token_buffer (see scan())
static bool discard_values() noexcept
{
return DiscardValues;
}
/// the tag of scan_string(): whether string tokens are kept
using keep_strings = typename std::conditional<DiscardValues, std::false_type, std::true_type>::type;
};
} // namespace detail
+6 -14
View File
@@ -72,14 +72,14 @@ This class implements a parser for JSON text. Nested arrays and objects are trac
stack instead of recursion, so deeply nested input does not exhaust the call stack, and what is read
is reported as SAX events.
*/
template<typename BasicJsonType, typename InputAdapterType>
template<typename BasicJsonType, typename InputAdapterType, bool DiscardValues = false>
class parser
{
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using lexer_t = lexer<BasicJsonType, InputAdapterType>;
using lexer_t = lexer<BasicJsonType, InputAdapterType, DiscardValues>;
using token_type = typename lexer_t::token_type;
public:
@@ -88,10 +88,9 @@ class parser
parser_callback_t<BasicJsonType> cb = nullptr,
const bool allow_exceptions_ = true,
const bool ignore_comments = false,
const bool ignore_trailing_commas_ = false,
const bool discard_number_values_ = false)
const bool ignore_trailing_commas_ = false)
: callback(std::move(cb))
, m_lexer(std::move(adapter), ignore_comments, discard_number_values_)
, m_lexer(std::move(adapter), ignore_comments)
, allow_exceptions(allow_exceptions_)
, ignore_trailing_commas(ignore_trailing_commas_)
{
@@ -574,14 +573,7 @@ class parser
std::string exception_message(const token_type expected, const std::string& context)
{
std::string error_msg = "syntax error ";
if (!context.empty())
{
error_msg += concat("while parsing ", context, ' ');
}
error_msg += "- ";
std::string error_msg = concat("syntax error while parsing ", context, " - ");
if (last_token == token_type::parse_error)
{
@@ -599,7 +591,7 @@ class parser
}
return error_msg;
}
} // LCOV_EXCL_LINE (exception cleanup only)
private:
/// callback function
@@ -322,6 +322,78 @@ JSON_SCAN_SSSE3_TARGET JSON_HEDLEY_NEVER_INLINE inline bool vector_utf8_run(cons
block_out = block;
return false;
}
/*!
@brief skip 16-byte blocks of well-formed UTF-8 at p (a character boundary)
Like vector_utf8_run, but quotes, backslashes, and control characters are
ordinary characters. Returns the start of the first block in which the check
found an error (which may belong to a sequence begun in the block before) or
where fewer than 16 bytes are left; a sequence may be cut at that point, so the
caller resumes at its start, one sequence at a time.
*/
JSON_SCAN_SSSE3_TARGET JSON_HEDLEY_NEVER_INLINE inline const unsigned char* vector_utf8_valid_blocks(const unsigned char* block, const unsigned char* e) noexcept
{
using lookup = utf8_lookup4<>;
#if JSON_SCAN_NEON
const uint8x16_t t1h = vld1q_u8(lookup::byte_1_high.data());
const uint8x16_t t1l = vld1q_u8(lookup::byte_1_low.data());
const uint8x16_t t2h = vld1q_u8(lookup::byte_2_high.data());
uint8x16_t prev = vdupq_n_u8(0);
while (e - block >= 16)
{
const uint8x16_t in = vld1q_u8(block);
if (vmaxvq_u8(vorrq_u8(in, prev)) < 0x80)
{
// ASCII here, and no sequence from the block before to finish
prev = in;
block += 16;
continue;
}
const uint8x16_t prev1 = vextq_u8(prev, in, 15);
const uint8x16_t sc = vandq_u8(vandq_u8(vqtbl1q_u8(t1h, vshrq_n_u8(prev1, 4)), vqtbl1q_u8(t1l, vandq_u8(prev1, vdupq_n_u8(0x0F)))), vqtbl1q_u8(t2h, vshrq_n_u8(in, 4)));
const uint8x16_t must23 = vorrq_u8(vqsubq_u8(vextq_u8(prev, in, 14), vdupq_n_u8(0xE0 - 0x80)), vqsubq_u8(vextq_u8(prev, in, 13), vdupq_n_u8(0xF0 - 0x80)));
const uint8x16_t err = veorq_u8(vandq_u8(must23, vdupq_n_u8(0x80)), sc);
if (vmaxvq_u8(err) != 0)
{
break;
}
prev = in;
block += 16;
}
#else
const __m128i t1h = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(lookup::byte_1_high.data()))); // NOLINT(bugprone-casting-through-void)
const __m128i t1l = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(lookup::byte_1_low.data()))); // NOLINT(bugprone-casting-through-void)
const __m128i t2h = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(lookup::byte_2_high.data()))); // NOLINT(bugprone-casting-through-void)
const __m128i nibble = _mm_set1_epi8(0x0F);
const __m128i zero = _mm_setzero_si128();
__m128i prev = zero;
while (e - block >= 16)
{
const __m128i in = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(block))); // NOLINT(bugprone-casting-through-void)
if (_mm_movemask_epi8(_mm_or_si128(in, prev)) == 0)
{
prev = in;
block += 16;
continue;
}
const __m128i prev1 = _mm_alignr_epi8(in, prev, 15);
const __m128i sc = _mm_and_si128(_mm_and_si128(_mm_shuffle_epi8(t1h, _mm_and_si128(_mm_srli_epi16(prev1, 4), nibble)),
_mm_shuffle_epi8(t1l, _mm_and_si128(prev1, nibble))),
_mm_shuffle_epi8(t2h, _mm_and_si128(_mm_srli_epi16(in, 4), nibble)));
const __m128i must23 = _mm_or_si128(_mm_subs_epu8(_mm_alignr_epi8(in, prev, 14), _mm_set1_epi8(0xE0 - 0x80)),
_mm_subs_epu8(_mm_alignr_epi8(in, prev, 13), _mm_set1_epi8(0xF0 - 0x80)));
const __m128i err = _mm_xor_si128(_mm_and_si128(must23, _mm_set1_epi8(static_cast<char>(-128))), sc);
if (_mm_movemask_epi8(_mm_cmpeq_epi8(err, zero)) != 0xFFFF)
{
break;
}
prev = in;
block += 16;
}
#endif
return block;
}
#endif
} // namespace detail
@@ -90,6 +90,34 @@ JSON_HEDLEY_ALWAYS_INLINE std::size_t find_string_special(const unsigned char* d
return n;
}
// return the index of the first 0x00 byte in [data, data+n), or n if there is
// none; scans 8 bytes at a time (BSON's C-style strings)
JSON_HEDLEY_ALWAYS_INLINE std::size_t find_zero_byte(const unsigned char* data, std::size_t n) noexcept
{
constexpr std::uint64_t ones = 0x0101010101010101ull;
constexpr std::uint64_t high = 0x8080808080808080ull;
std::size_t i = 0;
for (; i + 8 <= n; i += 8)
{
const std::uint64_t v = read_eight_bytes(data + i);
const std::uint64_t zero = (v - ones) & ~v & high;
if (zero != 0)
{
// the lowest flagged byte is the first zero byte (see
// find_string_special())
return i + (static_cast<std::size_t>(count_trailing_zeros(zero)) / 8);
}
}
for (; i < n; ++i)
{
if (data[i] == 0x00)
{
return i;
}
}
return n;
}
// classify a byte as one the serializer must NOT copy verbatim when
// ensure_ascii is requested: the closing quote, an escape, a control character
// (< 0x20), DEL (0x7F), or any non-ASCII byte (>= 0x80). Everything else -
@@ -236,6 +264,64 @@ inline std::size_t valid_utf8_prefix(const unsigned char* data, std::size_t n) n
return pos;
}
/*!
@brief whether [data, data+n) is valid UTF-8, for checking whole strings
The same answer as valid_utf8_prefix(data, n) == n. Short ASCII strings, the
most common keys and values, are decided in one test, and long strings are
checked 16 bytes at a time where the vector check is available.
*/
inline bool valid_utf8_string(const unsigned char* data, std::size_t n) noexcept
{
constexpr std::uint64_t high = 0x8080808080808080ull;
if (n <= 16)
{
// two overlapping words cover 8 to 16 bytes, one partial word fewer
std::uint64_t first = 0;
std::uint64_t last = 0;
if (n >= 8)
{
std::memcpy(&first, data, sizeof(first));
std::memcpy(&last, data + n - 8, sizeof(last));
}
else if (n != 0)
{
std::memcpy(&first, data, n);
}
if (((first | last) & high) == 0)
{
return true;
}
}
#if JSON_SCAN_VECTOR_UTF8
else if (n >= 32
#if JSON_SCAN_SSSE3_DISPATCH
&& cpu_has_ssse3()
#endif
)
{
const unsigned char* block = vector_utf8_valid_blocks(data, data + n);
// the rest from the start of a sequence that may be cut at block
for (int i = 1; i <= 3 && block - i >= data; ++i)
{
const unsigned char c = block[-i];
if (c < 0x80)
{
break;
}
if (c >= 0xC0)
{
block -= i;
break;
}
}
const auto checked = static_cast<std::size_t>(block - data);
return checked + valid_utf8_prefix(block, n - checked) == n;
}
#endif
return valid_utf8_prefix(data, n) == n;
}
#if JSON_SCAN_VECTOR_UTF8
/// the end of scan_string_vector from block, where the vector loop stopped
/// (ill-formed UTF-8, or fewer than 16 bytes left): one byte or sequence at a
@@ -108,6 +108,9 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{
JSON_ASSERT(m_object != nullptr);
// m_it is already value-initialized, so this is not needed for
// correctness; it is kept because GCC generates faster loops with it
// (iterating a parsed document is 0.5-2.7 % slower without it, #6005)
if (m_object->is_object())
{
m_it.object_iterator = typename object_t::iterator();
+4 -4
View File
@@ -304,7 +304,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.insert(result.reference_tokens.end(), rhs.reference_tokens.begin(), rhs.reference_tokens.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -315,7 +315,7 @@ class json_pointer
result.reference_tokens.insert(result.reference_tokens.end(), lhs.reference_tokens.begin(), lhs.reference_tokens.end());
result.reference_tokens.push_back(std::move(token));
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
@@ -2180,7 +2180,7 @@ class json_pointer
{
// create an entry in the array
current = &current->operator[](array_index<BasicJsonType>(token));
break;
break; // LCOV_EXCL_LINE (needs an array index with 10 or more digits: more than 1e9 elements)
}
/*
@@ -2217,7 +2217,7 @@ class json_pointer
json_pointer<string_t> result;
result.reference_tokens = reference_tokens;
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
json_pointer<string_t> convert()&&
{
+1 -1
View File
@@ -347,7 +347,7 @@
return ej_pair.second == j; \
}); \
if (it != std::end(m)) e = it->first; \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::exception_context(j))); \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat(nlohmann::detail::exception_prefix(j), "enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::exception_context(j))); \
}
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
+339 -124
View File
@@ -833,7 +833,7 @@ class binary_writer
while (n != 0);
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief the decimal digits of the integer @a n, with a leading '-' if it
@@ -860,7 +860,7 @@ class binary_writer
}
std::reverse(result.begin(), result.end());
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief throws because the integer @a j is too large for @a format
@@ -1792,7 +1792,7 @@ class binary_writer
std::memcpy(out, &n, sizeof(NumberType));
if (!is_little_endian)
{
std::reverse(out, out + sizeof(NumberType));
std::reverse(out, out + sizeof(NumberType)); // LCOV_EXCL_LINE (big-endian hosts only)
}
}
@@ -1921,7 +1921,7 @@ class binary_writer
const string_t& value = *j.m_data.m_value.string;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(value.size() + 1ul)))
{
return false;
return false; // LCOV_EXCL_LINE (a string of 2 GiB or more)
}
out[0] = to_char_type(0x02);
store_little_endian<std::int32_t>(p, static_cast<std::int32_t>(value.size() + 1ul));
@@ -2088,7 +2088,8 @@ class binary_writer
/// arrays: the first index with one more digit; only maintained by
/// @ref calc_bson_sizes
std::uint64_t index_boundary = 10;
/// @ref calc_bson_sizes only: where its size goes in the table
/// @ref calc_bson_sizes: where its size goes in the table; @ref
/// write_bson_document_single_pass: the position of its size field
std::size_t size_slot;
/// @ref calc_bson_sizes only: the size of its entries seen so far
std::size_t entries_size = 0;
@@ -2339,6 +2340,198 @@ class binary_writer
}
}
template<typename SinkType>
using sink_written_t = decltype(std::declval<const SinkType&>().written());
/// whether every integer fits the 64 bits BSON has, so that writing an
/// array of numbers needs no range check
static constexpr bool bson_integers_fit_64_bits =
std::numeric_limits<typename BasicJsonType::number_integer_t>::is_specialized
&& std::numeric_limits<typename BasicJsonType::number_integer_t>::digits <= std::numeric_limits<std::int64_t>::digits
&& std::numeric_limits<typename BasicJsonType::number_unsigned_t>::is_specialized
&& std::numeric_limits<typename BasicJsonType::number_unsigned_t>::digits <= std::numeric_limits<std::uint64_t>::digits;
/*!
@brief whether BSON documents can be written in a single pass: the sink
can overwrite what it has written (output_vector_sink), and
@ref bson_integers_fit_64_bits
*/
using bson_single_pass_sink = conjunction<is_detected<sink_written_t, OutputSinkType>, std::integral_constant<bool, bson_integers_fit_64_bits>>;
/// write a placeholder for the size of an object or array whose entries
/// follow; @return its position, for @ref close_bson_container
std::size_t write_bson_size_placeholder()
{
const std::size_t pos = oa.written();
// zero in any byte order
const std::array<CharType, sizeof(std::int32_t)> zero{};
oa.write_characters(zero.data(), zero.size());
return pos;
}
/// end the object or array whose size is at @a pos and write its size
/// there: everything from that field to the terminating null byte
/// @return false (and the size is not written) if it does not fit
bool close_bson_container(const std::size_t pos)
{
oa.write_character(to_char_type(0x00));
const std::size_t size = oa.written() - pos;
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
{
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
const auto le_size = static_cast<std::uint32_t>(size);
oa.overwrite(pos, is_little_endian ? le_size : byteswap(le_size));
return true;
}
/*!
@brief check the value @a j of a BSON entry as @ref calc_bson_value_size
does, for @ref write_bson_document_single_pass
@return at least the size of the value
A number, boolean, or null needs no check there (its integers have at most
64 bits) and has at most 8 characters; a discarded value is rejected with
the same exception when it is written.
*/
std::size_t check_bson_value(const BasicJsonType& j)
{
return (j.is_string() || j.is_binary()) ? calc_bson_value_size(j) : 8;
}
/// whether an entry of @a entry_size characters keeps the document that
/// begins at @a start, closed by @a open_containers null bytes, within
/// the 32-bit size of BSON
bool bson_entry_fits(const std::size_t start, const std::size_t entry_size, const std::size_t open_containers) const noexcept
{
const auto limit = static_cast<std::size_t>((std::numeric_limits<std::int32_t>::max)());
const std::size_t written = oa.written() - start;
return written <= limit && entry_size <= limit - written && open_containers <= limit - written - entry_size;
}
/*!
@brief Serializes the JSON object @a document as a BSON document in a
single pass, writing the size of each object and array once it is
complete
Checks every key and value as @ref calc_bson_sizes does, in the same
order, so the same exception is thrown; the output written up to then is
discarded with the vector it was written to.
@return false as soon as the document or a string, binary value, object,
or array in it would be larger than the 32-bit BSON sizes allow;
nothing large has been written then, and the caller writes the
document in two passes, which reports that error
*/
bool write_bson_document_single_pass(const BasicJsonType& document)
{
const std::size_t start = oa.written();
// the object or array whose entries are being written (with the
// position of its size), and the ones it is in
bson_frame current(&document, write_bson_size_placeholder());
std::vector<bson_frame> parents;
while (true)
{
const BasicJsonType* nested = nullptr;
std::size_t nested_size_pos = 0;
if (current.value->is_object())
{
const auto& object = *current.value->m_data.m_value.object;
while (nested == nullptr && current.member != object.cend())
{
const auto& el = *current.member;
++current.member;
const std::size_t header_size = calc_bson_entry_header_size(el.first, el.second);
const std::size_t value_size = el.second.is_structured() ? 0 : check_bson_value(el.second);
if (JSON_HEDLEY_UNLIKELY(!bson_entry_fits(start, header_size + value_size, parents.size() + 1)))
{
return false;
}
if (el.second.is_structured())
{
write_bson_entry_header(el.first, el.second.is_object() ? 0x03 : 0x04);
nested_size_pos = write_bson_size_placeholder();
nested = &el.second;
}
else
{
write_bson_value(el.first, el.second);
}
}
}
else
{
const auto& array = *current.value->m_data.m_value.array;
while (nested == nullptr && current.index < array.size())
{
if (is_bson_fixed_size(array[current.index]))
{
write_bson_array_fixed_entries(current);
if (current.index == array.size())
{
break;
}
}
// a string, binary value, object or array
const BasicJsonType& el = array[current.index];
const string_t index_name(current.index_name.data(), current.index_name_size);
current.next_index();
const std::size_t value_size = el.is_structured() ? 0 : check_bson_value(el);
if (JSON_HEDLEY_UNLIKELY(!bson_entry_fits(start, 2 + index_name.size() + value_size, parents.size() + 1)))
{
return false;
}
if (el.is_structured())
{
write_bson_entry_header(index_name, el.is_object() ? 0x03 : 0x04);
nested_size_pos = write_bson_size_placeholder();
nested = &el;
}
else
{
write_bson_value(index_name, el);
}
}
}
if (nested != nullptr)
{
if (nested->is_array())
{
// an array of booleans, numbers and null is written without a frame on the stack
bson_frame leaf(nested, nested_size_pos);
write_bson_array_fixed_entries(leaf);
if (leaf.index == nested->m_data.m_value.array->size())
{
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(nested_size_pos)))
{
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
continue;
}
parents.push_back(std::move(current));
current = std::move(leaf);
continue;
}
parents.push_back(std::move(current));
current = bson_frame(nested, nested_size_pos);
continue;
}
if (JSON_HEDLEY_UNLIKELY(!close_bson_container(current.size_slot)))
{
return false; // LCOV_EXCL_LINE (a document of 2 GiB or more)
}
if (parents.empty())
{
return true;
}
current = std::move(parents.back());
parents.pop_back();
}
}
/*!
@brief Serializes the JSON object @a document as a BSON document
@@ -2350,6 +2543,39 @@ class binary_writer
@pre document.type() == value_t::object
*/
void write_bson_document(const BasicJsonType& document)
{
write_bson_document(document, bson_single_pass_sink());
}
/// the sink can overwrite: one pass, unless the error handler replaces or
/// drops ill-formed UTF-8, which changes the sizes the checks compute
void write_bson_document(const BasicJsonType& document, std::true_type /*single_pass*/)
{
const std::size_t start = oa.written();
if ((error_handler == error_handler_t::keep || error_handler == error_handler_t::strict)
&& write_bson_document_single_pass(document))
{
return;
}
// a length does not fit: start over, so that it is reported as the
// two passes report it, before anything is written
oa.rewind(start);
write_bson_document_two_pass(document);
}
void write_bson_document(const BasicJsonType& document, std::false_type /*single_pass*/)
{
write_bson_document_two_pass(document);
}
/*!
@brief Serializes the JSON object @a document as a BSON document: the
sizes of all objects and arrays first, then the entries
@param[in] document the JSON object to serialize
@pre document.type() == value_t::object
*/
void write_bson_document_two_pass(const BasicJsonType& document)
{
std::vector<std::size_t> nested_sizes;
const std::size_t document_size = calc_bson_sizes(document, nested_sizes);
@@ -2552,10 +2778,10 @@ class binary_writer
Selected through masks rather than branches, as the type and the sign of
the values in an array of mixed signs alternate unpredictably (non-negative
integers are number_unsigned after parsing). Up to 64 bits, the sign is bit
63 of the result (a narrower integer is sign-extended); computing it with
masks keeps GCC from branching on the type. A wider integer has to be
compared.
integers are number_unsigned after parsing). The sign is bit 63 of the
result (a narrower integer is sign-extended); computing it with masks keeps
GCC from branching on the type. Only called if @ref integers_fit_64_bits();
a wider number type is written with range checks on the whole value.
*/
static std::uint64_t integer_bits(const BasicJsonType& j, std::uint64_t& sign_mask) noexcept
{
@@ -2563,9 +2789,7 @@ class binary_writer
const std::uint64_t raw = is_signed
? static_cast<std::uint64_t>(j.m_data.m_value.number_integer)
: static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned);
sign_mask = sizeof(typename BasicJsonType::number_integer_t) <= sizeof(std::uint64_t)
? (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u))
: std::uint64_t{0} - static_cast<std::uint64_t>(is_signed && j.m_data.m_value.number_integer < 0);
sign_mask = (std::uint64_t{0} - static_cast<std::uint64_t>(is_signed)) & (std::uint64_t{0} - (raw >> 63u));
return raw;
}
@@ -3080,6 +3304,25 @@ class binary_writer
}
}
/// write the head and the characters of @a value, at most
/// max_text_in_reservation of them, in one reservation
JSON_HEDLEY_ALWAYS_INLINE void write_cbor_string_reserved(const string_t& value)
{
CharType* const out = oa.reserve(value.size() + 2);
CharType* p = out;
if (value.size() <= 0x17)
{
*p++ = to_char_type(static_cast<std::uint8_t>(0x60 + value.size()));
}
else
{
*p++ = to_char_type(0x78);
*p++ = to_char_type(static_cast<std::uint8_t>(value.size()));
}
copy_characters(p, reinterpret_cast<const CharType*>(value.data()), value.size());
oa.commit(static_cast<std::size_t>(p - out) + value.size());
}
/*!
@brief write a CBOR text string
@@ -3101,19 +3344,7 @@ class binary_writer
// the string is written as it is: head and characters in one reservation
if (JSON_HEDLEY_LIKELY(value.size() <= max_text_in_reservation))
{
CharType* const out = oa.reserve(value.size() + 2);
CharType* p = out;
if (value.size() <= 0x17)
{
*p++ = to_char_type(static_cast<std::uint8_t>(0x60 + value.size()));
}
else
{
*p++ = to_char_type(0x78);
*p++ = to_char_type(static_cast<std::uint8_t>(value.size()));
}
copy_characters(p, reinterpret_cast<const CharType*>(value.data()), value.size());
oa.commit(static_cast<std::size_t>(p - out) + value.size());
write_cbor_string_reserved(value);
return;
}
}
@@ -3127,6 +3358,13 @@ class binary_writer
JSON_HEDLEY_NEVER_INLINE
void write_cbor_checked_string(const string_t& value, const BasicJsonType& context)
{
if (error_handler == error_handler_t::strict && value.size() <= max_text_in_reservation)
{
check_utf8(value, context);
write_cbor_string_reserved(value);
return;
}
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
@@ -3141,6 +3379,27 @@ class binary_writer
// MsgPack //
/////////////
/// write the head and the characters of @a value, at most
/// max_text_in_reservation of them, in one reservation
JSON_HEDLEY_ALWAYS_INLINE void write_msgpack_string_reserved(const string_t& value)
{
CharType* const out = oa.reserve(value.size() + 2);
CharType* p = out;
if (value.size() <= 31)
{
// fixstr
*p++ = to_char_type(static_cast<std::uint8_t>(0xA0 | value.size()));
}
else
{
// str 8
*p++ = to_char_type(0xD9);
*p++ = to_char_type(static_cast<std::uint8_t>(value.size()));
}
copy_characters(p, reinterpret_cast<const CharType*>(value.data()), value.size());
oa.commit(static_cast<std::size_t>(p - out) + value.size());
}
/*!
@brief write a MessagePack str
@@ -3158,21 +3417,7 @@ class binary_writer
// the string is written as it is: head and characters in one reservation
if (JSON_HEDLEY_LIKELY(value.size() <= max_text_in_reservation))
{
CharType* const out = oa.reserve(value.size() + 2);
CharType* p = out;
if (value.size() <= 31)
{
// fixstr
*p++ = to_char_type(static_cast<std::uint8_t>(0xA0 | value.size()));
}
else
{
// str 8
*p++ = to_char_type(0xD9);
*p++ = to_char_type(static_cast<std::uint8_t>(value.size()));
}
copy_characters(p, reinterpret_cast<const CharType*>(value.data()), value.size());
oa.commit(static_cast<std::size_t>(p - out) + value.size());
write_msgpack_string_reserved(value);
return;
}
}
@@ -3185,6 +3430,13 @@ class binary_writer
JSON_HEDLEY_NEVER_INLINE
void write_msgpack_checked_string(const string_t& value, const BasicJsonType& context)
{
if (error_handler == error_handler_t::strict && value.size() <= max_text_in_reservation)
{
check_utf8(value, context);
write_msgpack_string_reserved(value);
return;
}
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
@@ -3904,57 +4156,34 @@ class binary_writer
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of integer dtype @a T
@return whether @a el's value is in range of @a T; always true when @a dry_run is false
*/
template<typename T>
bool write_bjdata_ndarray_element(const BasicJsonType& el, const bool dry_run)
{
if (dry_run)
{
return bjdata_ndarray_value_in_range<T>(el);
}
using storage_type = typename std::conditional<std::is_unsigned<T>::value, std::uint64_t, std::int64_t>::type;
write_number(static_cast<T>(el.template get<storage_type>()), true);
return true;
}
/*!
@brief validate (dry_run) or write one BJData ND-array element of dtype 'd' (single precision)
@brief whether the BJData ND-array element @a el can be written with dtype 'd' (single precision)
@return whether @a el's value survives narrowing to float and back without any change
(so the ND-array round-trips exactly), or is infinite or NaN; always true when
@a dry_run is false
(so the ND-array round-trips exactly), or is infinite or NaN
*/
bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run)
static bool bjdata_ndarray_float_in_range(const BasicJsonType& el) noexcept
{
const auto dval = static_cast<double>(el.m_data.m_value.number_float);
if (dry_run)
{
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
#endif
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
const bool in_range = std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
// a value that would be rounded (rather than exactly represented) by the
// narrowing to float is treated like an out-of-range integer element; this
// is the same criterion write_compact_float() uses for CBOR/MessagePack
return std::isnan(dval) ||
(dval >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
dval <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(dval)) == dval) ||
std::isinf(dval);
#ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_POP
JSON_HEDLEY_DIAGNOSTIC_POP
#endif
return in_range;
}
write_number(static_cast<float>(dval), true);
return true;
}
/*!
@brief write the elements of an ND-array as the number kind @a dtype names
(see @ref write_bjdata_ndarray), after they have been found to be
in range by a dry run of @ref write_bjdata_ndarray_elements
in range by @ref bjdata_ndarray_elements_in_range
The elements are encoded in blocks into space reserved from the sink.
*/
@@ -4036,20 +4265,13 @@ class binary_writer
}
/*!
@brief validate or write every element of a BJData ND-array's `_ArrayData_`
@brief whether every element of a BJData ND-array's `_ArrayData_` is in range for its dtype
@param[in] array_data the `_ArrayData_` array
@param[in] dtype the ND-array dtype marker, as returned by bjdata_ndarray_type_marker()
@param[in] dry_run true to only range-check each element, false to write it
@return whether every element is in range for @a dtype (always true when @a dry_run is false)
@return whether every element is in range for @a dtype
*/
bool write_bjdata_ndarray_elements(const BasicJsonType& array_data, const CharType dtype, const bool dry_run)
static bool bjdata_ndarray_elements_in_range(const BasicJsonType& array_data, const CharType dtype)
{
if (!dry_run)
{
write_bjdata_ndarray_values(array_data, dtype);
return true;
}
for (const auto& el : array_data)
{
bool ok = true;
@@ -4057,43 +4279,39 @@ class binary_writer
{
case 'U':
case 'B':
ok = write_bjdata_ndarray_element<std::uint8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'C':
// BJData limits a char to 0..127 (the intersection of the int8 and uint8 ranges)
ok = bjdata_ndarray_value_in_range<std::int8_t>(el) && bjdata_ndarray_value_in_range<std::uint8_t>(el);
break;
case 'i':
ok = write_bjdata_ndarray_element<std::int8_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int8_t>(el);
break;
case 'u':
ok = write_bjdata_ndarray_element<std::uint16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint16_t>(el);
break;
case 'I':
ok = write_bjdata_ndarray_element<std::int16_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int16_t>(el);
break;
case 'm':
ok = write_bjdata_ndarray_element<std::uint32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint32_t>(el);
break;
case 'l':
ok = write_bjdata_ndarray_element<std::int32_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int32_t>(el);
break;
case 'M':
ok = write_bjdata_ndarray_element<std::uint64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::uint64_t>(el);
break;
case 'L':
ok = write_bjdata_ndarray_element<std::int64_t>(el, dry_run);
ok = bjdata_ndarray_value_in_range<std::int64_t>(el);
break;
case 'd':
ok = write_bjdata_ndarray_float_element(el, dry_run);
ok = bjdata_ndarray_float_in_range(el);
break;
case 'D':
default:
// 'D' (double) already spans the full range of number_float_t
if (!dry_run)
{
write_number(el.template get<double>(), true);
}
break;
}
if (!ok)
@@ -4180,7 +4398,7 @@ class binary_writer
const auto dim = el.template get<std::uint64_t>();
if (!value_in_range_of<std::size_t>(dim))
{
return true;
return true; // LCOV_EXCL_LINE (size_t is narrower than 64 bits)
}
const auto dim_size = static_cast<std::size_t>(dim);
@@ -4230,7 +4448,7 @@ class binary_writer
// wrap (integers) or overflow to infinity (the "single" precision
// float) instead of being reported, so such an object falls back to
// a plain object encoding as well
if (!write_bjdata_ndarray_elements(array_data, dtype, true))
if (!bjdata_ndarray_elements_in_range(array_data, dtype))
{
return true;
}
@@ -4242,7 +4460,7 @@ class binary_writer
write_ubjson(array_size, use_count, use_type, true, true, bjdata_version);
write_bjdata_ndarray_elements(array_data, dtype, false);
write_bjdata_ndarray_values(array_data, dtype);
return false;
}
@@ -4568,8 +4786,8 @@ class binary_writer
run are encoded into space reserved from the sink, as in
@ref write_array_elements; an integer that BON8 cannot write (an unsigned
one above the int64 range, or one of a number type wider than 64 bits) throws
from write_bon8_value, like any other value that is not a number. Kept out
of line, like @ref write_cbor_array.
out_of_range.407, as write_bon8_value does. Kept out of line, like
@ref write_cbor_array.
*/
template<typename ArrayType>
JSON_HEDLEY_NEVER_INLINE
@@ -4619,10 +4837,10 @@ class binary_writer
string_open = false;
}
if (unencodable)
if (JSON_HEDLEY_UNLIKELY(unencodable))
{
write_bon8_value(*it, string_open, depth + 1);
++it;
// an integer beyond the int64 range, as write_bon8_value would report it
throw_integer_out_of_range(*it, input_format_t::bon8, "int64");
}
}
}
@@ -4657,14 +4875,13 @@ class binary_writer
break;
case value_t::number_integer:
if (JSON_HEDLEY_LIKELY(integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits<std::int64_t>(value.m_data.m_value.number_integer)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
// beyond 64 bits (number types wider than that)
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// beyond 64 bits (number types wider than that): throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_integer));
string_open = false;
break;
case value_t::number_float:
@@ -4673,14 +4890,13 @@ class binary_writer
break;
case value_t::number_unsigned:
if (JSON_HEDLEY_LIKELY(integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
if (JSON_HEDLEY_UNLIKELY(!integer_fits_max<std::int64_t>(value.m_data.m_value.number_unsigned)))
{
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
// too large for BON8
throw_integer_out_of_range(value, input_format_t::bon8, "int64");
}
// too large for BON8: throws
write_bon8_value(value, string_open, depth + 1);
write_bon8_integer(static_cast<std::int64_t>(value.m_data.m_value.number_unsigned));
string_open = false;
break;
case value_t::object:
@@ -4794,10 +5010,9 @@ class binary_writer
static void check_utf8(const string_t& s, const BasicJsonType& context)
{
const auto* data = reinterpret_cast<const unsigned char*>(s.data());
const std::size_t valid = valid_utf8_prefix(data, s.size());
if (JSON_HEDLEY_UNLIKELY(valid != s.size()))
if (JSON_HEDLEY_UNLIKELY(!valid_utf8_string(data, s.size())))
{
throw_invalid_utf8(data, valid, context);
throw_invalid_utf8(data, valid_utf8_prefix(data, s.size()), context);
}
}
@@ -11,6 +11,7 @@
#include <algorithm> // max
#include <array> // array
#include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <cstring> // memcpy
#include <memory> // shared_ptr, make_shared
#include <string> // basic_string
@@ -227,6 +228,31 @@ class output_vector_sink
void flush() noexcept
{}
/// the number of characters written so far, the position of the next one
std::size_t written() const noexcept
{
return position();
}
/// @brief replace the 4 bytes written before at position @a pos with
/// those of @a n, in the byte order of the machine
///
/// Lets a writer put a length in front of data it has written since, such
/// as the size of a BSON document, without computing it in advance.
void overwrite(const std::size_t pos, const std::uint32_t n) noexcept
{
static_assert(sizeof(CharType) == 1, "overwrite() writes bytes");
JSON_ASSERT(pos + sizeof(n) <= position());
std::memcpy(v->data() + pos, &n, sizeof(n));
}
/// drop the characters written from position @a pos on
void rewind(const std::size_t pos) noexcept
{
JSON_ASSERT(pos <= position());
cursor = v->data() + pos;
}
private:
/// number of characters of *v written so far
std::size_t position() const noexcept
+42 -23
View File
@@ -1113,36 +1113,21 @@ class serializer
{
// the code point is at least 0x60 (smaller ones are handled
// above) and is not printable ASCII (which the scanner
// copies): it is DEL (0x7F) under EnsureAscii or a non-ASCII
// character
// copies). Under EnsureAscii it is DEL (0x7F): every
// well-formed multi-byte character is escaped by
// write_u_escapes() above, so decode() only ever accepts a
// single byte here, and nothing of it was buffered
if (EnsureAscii)
{
JSON_ASSERT(codepoint >= 0x7F);
if (error_handler == error_handler_t::keep)
{
// this character was buffered as raw bytes below
// in case it turned out to be part of an
// ill-formed sequence (which is kept as is); now
// that it decoded to a well-formed code point,
// undo that and \u-escape it like any other
// character instead
bytes = bytes_after_last_accept;
}
if (codepoint <= 0xFFFF)
{
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
}
JSON_ASSERT(codepoint == 0x7F);
JSON_ASSERT(bytes == bytes_after_last_accept);
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
// copy byte to buffer (all previous bytes of the
// sequence have been copied in the default case below)
string_buffer[bytes++] = s[i];
string_buffer[bytes++] = s[i]; // LCOV_EXCL_LINE (well-formed sequences are copied in runs)
}
reserve_string_buffer(bytes);
@@ -1977,6 +1962,23 @@ class serializer
return;
}
// 17 to 20 digits: the first one to four, then twice eight
if (magnitude_fits_64_bits(abs_value, std::integral_constant<bool, magnitude_has_at_most_64_bits>()))
{
const auto value = static_cast<std::uint64_t>(abs_value);
const std::uint64_t top = value / 10000000000000000u; // 1 to 1844
const std::uint64_t low16 = value - (top * 10000000000000000u);
const std::uint64_t middle = low16 / 100000000u;
const std::uint64_t first = dtoa_impl::eight_digit_bytes(top);
const auto leading = static_cast<unsigned>(count_leading_zeros(first) / 8); // (first is not 0)
char* const p = buffer_ptr + n_chars;
dtoa_impl::store_msb_first(p, (first << (8 * leading)) + 0x3030303030303030u);
dtoa_impl::store_msb_first(p + 8 - leading, dtoa_impl::eight_digit_bytes(middle) + 0x3030303030303030u);
dtoa_impl::store_msb_first(p + 16 - leading, dtoa_impl::eight_digit_bytes(low16 - (middle * 100000000u)) + 0x3030303030303030u);
write_buffer_pos += n_chars + 24 - leading;
return;
}
n_chars += count_digits(abs_value);
// spare 1 byte for '\0'
@@ -2122,6 +2124,23 @@ class serializer
}
}
/// whether every number_magnitude_t fits 64 bits
static constexpr bool magnitude_has_at_most_64_bits = std::numeric_limits<number_magnitude_t>::is_specialized
&& std::numeric_limits<number_magnitude_t>::digits <= 64;
/// whether @a x fits 64 bits: always if number_magnitude_t has at most
/// 64 bits (selected by type, as the comparison would be reported as
/// always true), else compared
static bool magnitude_fits_64_bits(const number_magnitude_t& /*unused*/, std::true_type /*unused*/) noexcept
{
return true;
}
static bool magnitude_fits_64_bits(const number_magnitude_t& x, std::false_type /*unused*/) noexcept
{
return x <= 18446744073709551615u;
}
/*
* Helper function for dump_integer
*
+1 -1
View File
@@ -139,7 +139,7 @@ inline OutStringType concat(Args && ... args)
str.reserve(concat_length(args...));
concat_into(str, std::forward<Args>(args)...);
return str;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -83,10 +83,6 @@ template<typename StringType>
inline void unescape(StringType& s)
{
auto pos = s.find_first_of('~', 0);
if (pos == StringType::npos)
{
return;
}
StringType result;
result.reserve(s.size());
+3 -3
View File
@@ -36,7 +36,7 @@ StringType to_string(std::size_t value)
StringType result;
int_to_string(result, value);
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/// @return a byte as two uppercase hexadecimal digits
inline std::string hex_byte(const std::uint8_t byte)
@@ -46,7 +46,7 @@ inline std::string hex_byte(const std::uint8_t byte)
result[0] = nibble_to_hex[byte / 16];
result[1] = nibble_to_hex[byte % 16];
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
/*!
@brief write a UTF-16 code unit as four lowercase hexadecimal digits
@@ -390,7 +390,7 @@ inline StringType sanitize_utf8(const StringType& s, const error_handler_t error
}
return result;
}
} // LCOV_EXCL_LINE (exception cleanup only)
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
+138 -20
View File
@@ -69,7 +69,8 @@ struct parse_failure
};
/// FloatType: the number_float_t of the document, whose overflow parse() rejects
template<typename FloatType, bool Comments, bool TrailingCommas, bool NulIsEnd, bool Sentinel>
/// Store: false for accept(): the grammar, number, string and UTF-8 checks run as for parse(), but no node is written
template<typename FloatType, bool Comments, bool TrailingCommas, bool NulIsEnd, bool Sentinel, bool Store>
class builder
{
public:
@@ -245,11 +246,87 @@ class builder
return p;
}
/// the string from p, the first backslash, control character, ill-formed UTF-8 byte, or the end, checked and not
/// decoded (accept() stores nothing, so the arena is not written): the checks, errors and error positions of
/// slow_string(), for everything up to the closing quote
NLOHMANN_VIEW_NOINLINE decoded check_string(const unsigned char* p)
{
const unsigned char* const end = m_end;
for (;;)
{
if (p == end)
{
return failed(error_code::string_missing_quote, p);
}
const unsigned char c = *p;
if (c == '"')
{
++p;
return decoded{p, 0, 0};
}
if (c != '\\')
{
return failed(c < 0x20 ? error_code::string_control_character : error_code::string_utf8, p);
}
++p;
if (p == end)
{
return failed(error_code::string_missing_quote, p);
}
const unsigned char d = *p++;
if (d == 'u')
{
const int cp = hex4(p); // (moves p past the four digits)
if (NLOHMANN_VIEW_UNLIKELY(cp < 0))
{
return failed(error_code::string_unicode_hex, p);
}
if (NLOHMANN_VIEW_UNLIKELY((cp & 0xF800) == 0xD800)) // a surrogate
{
if (cp >= 0xDC00)
{
return failed(error_code::string_surrogate_low, p);
}
if (end - p < 2 || p[0] != '\\' || p[1] != 'u')
{
return failed(error_code::string_surrogate_high, p);
}
p += 2;
const int lo = hex4(p); // (moves p past the four digits)
if (lo < 0)
{
return failed(error_code::string_unicode_hex, p);
}
if (lo < 0xDC00 || lo > 0xDFFF)
{
return failed(error_code::string_surrogate_high, p);
}
}
}
else if (!(d == '"' || d == '\\' || d == '/' || d == 'b' || d == 'f' || d == 'n' || d == 'r' || d == 't'))
{
--p;
return failed(error_code::string_escape, p);
}
if (p != end && *p == '\\')
{
continue; // (escapes in a row: no run of text between them)
}
p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8
}
}
/// s points to the start of the string, p to a backslash, a control
/// character, an ill-formed UTF-8 byte, or the end: decode the string into
/// the arena
NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p)
{
if (!enabled(Store))
{
// (accept(): the string is checked, not decoded)
static_cast<void>(s);
return check_string(p);
}
// single-character escapes; 0: invalid (and 'u', handled separately)
static const std::array<char, 128> simple_escape =
{
@@ -343,6 +420,21 @@ class builder
}
arena_ensure(w, w_end, 4);
w = put_utf8(w, cp);
// A chain of unicode escapes ("\u3042\u3044\u3046", as Python's json.dumps writes non-ASCII text) is
// decoded here, without going round the loop above for each of them. Anything else (a surrogate, a
// bad digit, fewer than six bytes) leaves p at the backslash: the loop above handles it, and reports
// the same error at the same position as it would without this loop.
while (end - p >= 6 && p[0] == '\\' && p[1] == 'u')
{
const int next = hex_codepoint(p + 2);
if (next < 0 || (next & 0xF800) == 0xD800)
{
break;
}
p += 6;
arena_ensure(w, w_end, 4);
w = put_utf8(w, next);
}
}
else if (NLOHMANN_VIEW_LIKELY(d < 128 && simple_escape[d] != 0))
{
@@ -610,10 +702,13 @@ run_found:
NLOHMANN_VIEW_ALWAYS_INLINE bool run()
{
cold.m_doc.reserve(estimate_nodes(reinterpret_cast<const char*>(b), static_cast<std::size_t>(e - b)));
base = cold.m_doc.nodes;
out = base;
cap = base + cold.m_doc.node_capacity;
if (enabled(Store))
{
cold.m_doc.reserve(estimate_nodes(reinterpret_cast<const char*>(b), static_cast<std::size_t>(e - b)));
base = cold.m_doc.nodes;
out = base;
cap = base + cold.m_doc.node_capacity;
}
if (e - p >= 3 && p[0] == 0xEF && p[1] == 0xBB && p[2] == 0xBF)
{
@@ -797,7 +892,10 @@ close_object:
// an array pays nothing for this)
if (NLOHMANN_VIEW_UNLIKELY(cur_count >= document_data::index_min_members))
{
cold.note_large_object(cur_idx);
if (enabled(Store))
{
cold.note_large_object(cur_idx);
}
}
close_container:
@@ -957,6 +1055,12 @@ indent_done:
/// an integer's value); two stores on little-endian targets
NLOHMANN_VIEW_ALWAYS_INLINE node* push_node(node_kind k, std::uint8_t flags, std::uint16_t extra, std::size_t off, std::uint64_t second)
{
if (!enabled(Store))
{
// accept(): nothing is stored, so what computes the arguments is not run either. base and out stay
// null: their difference, which open() takes, is 0.
return out;
}
if (NLOHMANN_VIEW_UNLIKELY(out == cap))
{
const auto n = static_cast<std::size_t>(out - base);
@@ -1015,9 +1119,12 @@ indent_done:
NLOHMANN_VIEW_ALWAYS_INLINE void close()
{
node& n = base[cur_idx];
n.len = cur_count;
n.next = static_cast<std::uint32_t>(out - base) - cur_idx;
if (enabled(Store))
{
node& n = base[cur_idx];
n.len = cur_count;
n.next = static_cast<std::uint32_t>(out - base) - cur_idx;
}
if (--depth != 0)
{
if (NLOHMANN_VIEW_LIKELY(depth <= 64))
@@ -1067,8 +1174,9 @@ indent_done:
{
++p;
}
else if (NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
else if (!negative || NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
{
// (without a sign, the dispatch saw a digit)
p = skip_digits(p + 1, e);
}
else
@@ -1082,7 +1190,7 @@ indent_done:
{
++p;
const unsigned char* const f0 = p;
p = skip_digits(p, e);
p = skip_fraction_digits(p, e);
if (NLOHMANN_VIEW_UNLIKELY(p == f0))
{
return fail(error_code::number_after_dot);
@@ -1192,34 +1300,44 @@ indent_done:
};
/// run the builder with compile-time options
template<typename FloatType, bool Comments, bool TrailingCommas, bool NulIsEnd>
template<typename FloatType, bool Comments, bool TrailingCommas, bool NulIsEnd, bool Store>
inline bool build_with(document_data& d, const char* src, std::size_t size, bool sentinel, parse_failure& failure)
{
if (sentinel)
{
builder<FloatType, Comments, TrailingCommas, NulIsEnd, true> bld(d, src, size);
builder<FloatType, Comments, TrailingCommas, NulIsEnd, true, Store> bld(d, src, size);
const bool ok = bld.run();
failure = bld.failure();
return ok;
}
builder<FloatType, Comments, TrailingCommas, NulIsEnd, false> bld(d, src, size);
builder<FloatType, Comments, TrailingCommas, NulIsEnd, false, Store> bld(d, src, size);
const bool ok = bld.run();
failure = bld.failure();
return ok;
}
/// sentinel: src[size] is readable and 0 (e.g. std::string); FloatType: the
/// number_float_t of the document
/// number_float_t of the document; validate_only: accept(), only the result is
/// used
template<typename FloatType, bool NulIsEnd>
inline bool build(document_data& d, const char* src, std::size_t size, bool comments, bool trailing_commas, bool sentinel, parse_failure& failure)
inline bool build(document_data& d, const char* src, std::size_t size, bool comments, bool trailing_commas, bool sentinel, bool validate_only,
parse_failure& failure)
{
if (validate_only && !comments && !trailing_commas)
{
// accept() of plain JSON: nothing is stored. The other option sets
// could skip the stores just as well; they keep the builder that
// stores only so that there are two more instantiations of the parse
// loop, not eight.
return build_with<FloatType, false, false, NulIsEnd, false>(d, src, size, sentinel, failure);
}
if (comments)
{
return trailing_commas ? build_with<FloatType, true, true, NulIsEnd>(d, src, size, sentinel, failure)
: build_with<FloatType, true, false, NulIsEnd>(d, src, size, sentinel, failure);
return trailing_commas ? build_with<FloatType, true, true, NulIsEnd, true>(d, src, size, sentinel, failure)
: build_with<FloatType, true, false, NulIsEnd, true>(d, src, size, sentinel, failure);
}
return trailing_commas ? build_with<FloatType, false, true, NulIsEnd>(d, src, size, sentinel, failure)
: build_with<FloatType, false, false, NulIsEnd>(d, src, size, sentinel, failure);
return trailing_commas ? build_with<FloatType, false, true, NulIsEnd, true>(d, src, size, sentinel, failure)
: build_with<FloatType, false, false, NulIsEnd, true>(d, src, size, sentinel, failure);
}
} // namespace view
+13 -22
View File
@@ -397,9 +397,9 @@ class view_side
return m_view.size();
}
string_view_t string() const
string_view_t string() const noexcept
{
return m_view.get_string();
return {m_view.m_doc->str(*m_view.m_node), m_view.m_node->len};
}
bool boolean() const noexcept
@@ -428,28 +428,19 @@ class view_side
return string_view_t(m_view.m_doc->str(*m_view.m_node), m_view.m_node->len);
}
/// a number, boolean, or null as a basic_json value (no allocation)
/// a number as a basic_json value (no allocation); only called for numbers
BasicJsonType scalar() const
{
switch (m_view.type())
const value_t t = m_view.type();
if (t == value_t::number_integer)
{
case value_t::number_integer:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
case value_t::number_unsigned:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
case value_t::number_float:
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
case value_t::boolean:
return BasicJsonType(m_view.template get<bool>());
case value_t::null:
case value_t::object:
case value_t::array:
case value_t::string:
case value_t::binary:
case value_t::discarded:
default:
return BasicJsonType(nullptr);
return BasicJsonType(m_view.template get<typename BasicJsonType::number_integer_t>());
}
if (t == value_t::number_unsigned)
{
return BasicJsonType(m_view.template get<typename BasicJsonType::number_unsigned_t>());
}
return BasicJsonType(m_view.template get<typename BasicJsonType::number_float_t>());
}
/// start at the first element of this array
@@ -531,9 +522,9 @@ class json_side
return m_json->size();
}
string_view_t string() const
string_view_t string() const noexcept
{
const auto& s = m_json->template get_ref<const typename BasicJsonType::string_t&>();
const auto& s = *m_json->template get_ptr<const typename BasicJsonType::string_t*>();
return string_view_t(s.data(), s.size());
}
+13 -13
View File
@@ -96,11 +96,11 @@ NLOHMANN_VIEW_NOINLINE inline void check_utf8_scan(const unsigned char* p, std::
}
if (*q >= 0x80)
{
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
return; // not reached: the scan stopped at ill-formed UTF-8
break; // ill-formed UTF-8: reported below
}
++q; // a quote, backslash, or control character
}
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
}
inline void check_utf8(const char* s, std::size_t n)
@@ -157,7 +157,7 @@ class editor
node* const o = own(object);
if (o->kind != node_kind::object && o->kind != node_kind::null)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
throw_type_error(site_of(object), exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
}
check_utf8(key.data(), key.size());
const encoded e = encode(std::forward<V>(value));
@@ -208,9 +208,9 @@ class editor
node* const a = own(array);
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
throw_type_error(site_of(array), exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
}
check_index(idx, a->len);
check_index(a, idx, a->len);
const encoded e = encode(std::forward<V>(value));
node* const slot = const_cast<node*>(nav::value(element_at<true>(m_doc, a, idx))); // NOLINT(cppcoreguidelines-pro-type-const-cast)
assign(slot, e, a, true);
@@ -225,7 +225,7 @@ class editor
node* const a = own(array);
if (a->kind != node_kind::array && a->kind != node_kind::null)
{
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
throw_type_error(site_of(array), exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
}
const encoded e = encode(std::forward<V>(value));
if (a->kind == node_kind::null)
@@ -249,9 +249,9 @@ class editor
node* const a = own(array);
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
throw_type_error(site_of(array), exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
}
check_index(idx, a->len + 1);
check_index(a, idx, a->len + 1);
const encoded e = encode(std::forward<V>(value));
node* const slot = new_slot(e);
node* const h = block_of(m_doc, a, 1);
@@ -269,7 +269,7 @@ class editor
node* const o = own(object);
if (o->kind != node_kind::object)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
throw_type_error(site_of(object), exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
}
for (const node* k = nav::first(m_doc, o), *end = nav::end(m_doc, o); k != end; k = document_data::after(k + 1))
{
@@ -287,9 +287,9 @@ class editor
node* const a = own(array);
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
throw_type_error(site_of(array), exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
}
check_index(idx, a->len);
check_index(a, idx, a->len);
node* const h = block_of(m_doc, a, 0);
std::memmove(h + 1 + idx, h + 2 + idx, (h->next - 2 - idx) * sizeof(node));
--h->next;
@@ -316,11 +316,11 @@ class editor
return const_cast<node*>(v.m_node); // NOLINT(cppcoreguidelines-pro-type-const-cast): the nodes belong to this document
}
static void check_index(std::size_t idx, std::size_t limit)
void check_index(const node* array, std::size_t idx, std::size_t limit) const
{
if (idx >= limit)
{
throw_array_index_out_of_range(idx);
throw_array_index_out_of_range(error_site(&m_doc, array), idx);
}
}
@@ -158,7 +158,7 @@ inline void set_moved(document_data& d, node* n, node* seq, std::size_t cap)
e.moved_cap[n->off] = cap;
return;
}
reserve_moved(d);
// every caller has called reserve_moved() (see above), so neither push_back() can throw
e.moved.push_back(seq);
e.moved_cap.push_back(cap);
n->off = static_cast<std::uint32_t>(e.moved.size() - 1);
@@ -243,7 +243,7 @@ inline node* find_parent(const document_data& d, const node* target)
}
if (target == lo)
{
return nullptr;
return nullptr; // LCOV_EXCL_LINE (the root, or a new value's root, which is linked)
}
for (;;)
{
+320 -8
View File
@@ -10,11 +10,15 @@
#include <algorithm> // min
#include <cstddef> // size_t
#include <string> // string
#include <string> // string, to_string
#include <vector> // vector
#include <nlohmann/json.hpp>
#include <nlohmann/detail/view/builder.hpp>
#include <nlohmann/detail/view/document_data.hpp>
#include <nlohmann/detail/view/macro_scope.hpp>
#include <nlohmann/detail/view/materialize.hpp>
#include <nlohmann/detail/view/node.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -22,8 +26,295 @@ namespace detail
namespace view
{
/*!
@brief the value an exception is about
basic_json passes the value to the exception, which then names its path
(JSON_DIAGNOSTICS) and its bytes in the source (JSON_DIAGNOSTIC_POSITIONS). A
view's value has no parent pointer and no stored positions: both are found
from the document and the node, when the exception is thrown (so only the
error path pays for them). Without the two macros, a site is empty.
*/
class error_site
{
public:
error_site() noexcept = default;
#if JSON_DIAGNOSTICS || JSON_DIAGNOSTIC_POSITIONS
error_site(const document_data* d, const node* n) noexcept
: m_doc(d), m_node(n)
{}
const document_data* doc() const noexcept
{
return m_doc;
}
const node* value() const noexcept
{
return m_node;
}
private:
const document_data* m_doc = nullptr;
const node* m_node = nullptr;
#else
error_site(const document_data* /*d*/, const node* /*n*/) noexcept {}
#endif
};
/// the site of a view's value (the views make this a friend)
struct view_access
{
template<typename View>
static error_site site(const View& v) noexcept
{
return {v.m_doc, v.m_node};
}
};
template<typename View>
error_site site_of(const View& v) noexcept
{
static_assert(is_json_view<View>::value, "the site of a value is only defined for views");
return view_access::site(v);
}
#if JSON_DIAGNOSTICS
/*!
@brief the JSON pointer tokens from the root of document @a d to node @a target
Nodes have no parent index, so the path is found by descending from the root:
before the first edit, only into the subtree that contains the target (a
container spans the next `next` nodes); after edits, elements can live in
other sequences, so every container is searched. Iterative (the nesting depth
is limited by memory only). False if the target is not found (then tokens is
unspecified).
*/
template<bool Editable>
bool value_path(const document_data& d, const node* target, std::vector<std::string>& tokens)
{
using nav = navigation<Editable>;
struct frame
{
const node* pos;
const node* end;
std::size_t index;
bool object;
};
const node* const root = d.nodes;
if (target == root)
{
return true;
}
if (!is_container(*root))
{
return false;
}
std::vector<frame> stack;
stack.push_back(frame{nav::first(d, root), nav::end(d, root), 0, root->kind == node_kind::object});
// (tokens[i] leads from stack[i] to stack[i + 1], or to the target)
for (;;)
{
// a copy: pop_back() and push_back() below change the stack
const frame f = stack.back();
if (f.pos == f.end)
{
stack.pop_back();
if (stack.empty())
{
return false;
}
tokens.pop_back();
continue;
}
const node* entry = f.pos;
std::string token;
if (f.object)
{
// (as basic_json: the key up to a null byte)
token.assign(d.str(*entry), entry->len);
const std::size_t nul = token.find('\0');
if (nul != std::string::npos)
{
token.resize(nul);
}
++entry;
}
else
{
token = std::to_string(f.index);
}
const node* const child = nav::value(entry);
if (child == target)
{
tokens.push_back(token);
return true;
}
stack.back().pos = document_data::after(entry);
++stack.back().index;
if (is_container(*child) && (nav::editable() || (target > child && target < child + child->next)))
{
tokens.push_back(token);
stack.push_back(frame{nav::first(d, child), nav::end(d, child), 0, child->kind == node_kind::object});
}
}
}
#endif
#if JSON_DIAGNOSTIC_POSITIONS
/*!
@brief the bytes [start, end) of node @a n in the source, as materialize() sets them
Scalars as position_source::set_scalar; an array or object from its opening
bracket to its closing bracket, which is found by following the chain of last
elements to a scalar (or an empty container) and scanning from there to the
closing brackets. None (npos) for values written by edits, and for containers
whose last element has none, as with materialize().
*/
template<bool Editable>
void value_range(const document_data& d, const node* n, std::size_t& start, std::size_t& end)
{
using nav = navigation<Editable>;
position_source p;
start = std::string::npos;
end = std::string::npos;
if (!is_container(*n))
{
p.set_scalar(d, *n);
start = p.start;
end = p.end;
return;
}
// the open brackets: n, then the last element as long as it is a non-empty container
std::size_t closing = 0;
std::size_t pos = std::string::npos;
for (const node* c = n;;)
{
if (!is_container(*c))
{
p.set_scalar(d, *c);
pos = p.end;
break;
}
if ((c->flags & node_flags::is_new) != 0 || c->off >= d.size)
{
return;
}
++closing;
const node* const first = nav::first(d, c);
const node* const last_end = nav::end(d, c);
if (first == last_end)
{
pos = std::size_t{c->off} + 1;
break;
}
const std::size_t value_offset = c->kind == node_kind::object ? 1 : 0;
const node* last = first;
for (const node* e = document_data::after(first + value_offset); e != last_end; e = document_data::after(e + value_offset))
{
last = e;
}
c = nav::value(last + value_offset);
}
for (; closing != 0 && pos != std::string::npos; --closing)
{
pos = position_source::container_end(d.base[0], d.size, pos);
}
if (pos != std::string::npos)
{
start = n->off;
end = pos;
}
}
#endif
/// the context basic_json puts in front of the message of an exception about
/// a value: "(/path) " with JSON_DIAGNOSTICS (none for the root), then
/// "(bytes a-b) " with JSON_DIAGNOSTIC_POSITIONS (also for the root); with
/// JSON_DIAGNOSTICS, nothing for a value that is no longer part of the document
///
/// This and the throw helpers that take an error_site are templates, so that
/// the path and range code is instantiated only where an exception can be
/// thrown: instantiated in every translation unit (as a non-template inline
/// function makes it), it changed GCC's early inlining of unrelated view
/// functions, so that GCC 13 no longer inlined a recursive walk over a view
/// into itself (2.7 times the instructions).
#if JSON_DIAGNOSTICS || JSON_DIAGNOSTIC_POSITIONS
template<typename Unused = void>
std::string diagnostics(const error_site site)
{
if (site.doc() == nullptr || site.value() == nullptr)
{
return "";
}
const document_data& d = *site.doc();
const bool edited = d.edits != nullptr;
std::string context;
#if JSON_DIAGNOSTICS
std::vector<std::string> tokens;
// a value that is no longer part of the document has no path, and its
// node still holds the bytes it had in the source: no context at all
const bool found = edited ? value_path<true>(d, site.value(), tokens) : value_path<false>(d, site.value(), tokens);
if (!found)
{
// context is still empty; returning it keeps the copy elided (-Wnrvo)
return context;
}
if (!tokens.empty())
{
// the root value has no path, but still has a byte range
std::string path;
for (const std::string& token : tokens)
{
path.push_back('/');
path += detail::escape(token);
}
context = concat('(', path, ") ");
}
#endif
#if JSON_DIAGNOSTIC_POSITIONS
std::size_t start = 0;
std::size_t end = 0;
if (edited)
{
value_range<true>(d, site.value(), start, end);
}
else
{
value_range<false>(d, site.value(), start, end);
}
if (start != std::string::npos && end != std::string::npos)
{
context += concat("(bytes ", std::to_string(start), "-", std::to_string(end), ") ");
}
#endif
return context;
}
#else
template<typename Unused = void>
std::string diagnostics(const error_site /*site*/)
{
return "";
}
#endif
/// the context of an exception about view @a v (see exception_prefix())
template<typename View>
std::string diagnostics_of(const View& v)
{
return diagnostics<>(site_of(v));
}
// Exceptions are thrown out of line, so that the accessors that may throw stay
// small enough to be inlined.
// small enough to be inlined. The overloads with an error_site put its context
// in front of the message.
//
// The overloads without one are for exceptions that are not about a value of a
// document: limits and invalid input of the editing and image functions, a
// discarded view (it has no node), a view of another document (its path would
// be one in that document), and those that basic_json creates without a
// context too (the errors of json_pointer, invalid UTF-8). The one exception
// about a value that has no site is key(), see view_iterator::key().
[[noreturn]] NLOHMANN_VIEW_NOINLINE inline void throw_type_error(exception_id id, const char* prefix, const char* type)
{
@@ -45,6 +336,24 @@ namespace view
NLOHMANN_VIEW_THROW(invalid_iterator::create(id, msg, nullptr));
}
template<typename Unused = void>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_type_error(const error_site site, exception_id id, const char* prefix, const char* type)
{
NLOHMANN_VIEW_THROW(type_error::create(id, concat(diagnostics<>(site), prefix, type), nullptr));
}
template<typename Unused = void>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_out_of_range(const error_site site, exception_id id, const std::string& msg)
{
NLOHMANN_VIEW_THROW(out_of_range::create(id, concat(diagnostics<>(site), msg), nullptr));
}
template<typename Unused = void>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_invalid_iterator(const error_site site, exception_id id, const char* msg)
{
NLOHMANN_VIEW_THROW(invalid_iterator::create(id, concat(diagnostics<>(site), msg), nullptr));
}
/// a parse error without a position (as those of json_pointer)
[[noreturn]] NLOHMANN_VIEW_NOINLINE inline void throw_parse_error(exception_id id, const std::string& msg)
{
@@ -53,22 +362,23 @@ namespace view
/// out_of_range.401: the array index @a idx is not below the size
template<typename Index>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_out_of_range(const Index idx)
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_out_of_range(const error_site site, const Index idx)
{
throw_out_of_range(exception_id::array_index_out_of_range, concat("array index ", std::to_string(idx), " is out of range"));
throw_out_of_range(site, exception_id::array_index_out_of_range, concat("array index ", std::to_string(idx), " is out of range"));
}
/// out_of_range.402: the JSON Pointer token '-' of an array of @a size elements
[[noreturn]] NLOHMANN_VIEW_NOINLINE inline void throw_array_index_past_end(std::size_t size)
template<typename Unused = void>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_past_end(const error_site site, std::size_t size)
{
throw_out_of_range(exception_id::pointer_past_the_end_index, concat("array index '-' (", std::to_string(size), ") is out of range"));
throw_out_of_range(site, exception_id::pointer_past_the_end_index, concat("array index '-' (", std::to_string(size), ") is out of range"));
}
/// out_of_range.403: the object has no member @a key
template<typename Key>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_key_not_found(const Key& key)
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_key_not_found(const error_site site, const Key& key)
{
throw_out_of_range(exception_id::key_not_found, concat("key '", key, "' not found"));
throw_out_of_range(site, exception_id::key_not_found, concat("key '", key, "' not found"));
}
/// SAX handler of the error replay: accepts every event without storing it,
@@ -112,10 +422,12 @@ struct throwing_sax
return true;
}
// LCOV_EXCL_START (throw_parse_failure parses JSON only)
bool binary(binary_t& /*unused*/)
{
return true;
}
// LCOV_EXCL_STOP
bool start_object(std::size_t /*unused*/)
{
-4
View File
@@ -787,10 +787,6 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
d.edits.reset();
d.base[2] = nullptr;
d.owned.clear();
if (d.owned_image.empty() || image != d.owned_image.data())
{
d.owned_image.clear();
}
d.arena.clear();
d.indexes.clear();
d.index_slots.clear();
+4 -1
View File
@@ -105,7 +105,10 @@ class view_iterator
}
/// the key of the current object member; throws invalid_iterator.207 for
/// other iterators, like basic_json's iterators
/// other iterators, like basic_json's iterators (but without the context
/// JSON_DIAGNOSTICS and JSON_DIAGNOSTIC_POSITIONS add: the iterator does not
/// know the value it iterates over, and keeping it would make iterators
/// larger, which keeps GCC from inlining recursive walks)
string_view_t key() const
{
if (NLOHMANN_VIEW_UNLIKELY(m_value_offset == 0))
@@ -40,6 +40,15 @@
#define NLOHMANN_VIEW_NOINLINE
#endif
// GCC: a function compiled as written, without the clones in which interprocedural
// constant propagation drops an argument that every caller passes as the same constant
// (calling such a clone changes the code GCC generates for the parse loop that calls it)
#if defined(__GNUC__) && !defined(__clang__)
#define NLOHMANN_VIEW_NOCLONE __attribute__((noclone))
#else
#define NLOHMANN_VIEW_NOCLONE
#endif
#if defined(__GNUC__) || defined(__clang__)
#define NLOHMANN_VIEW_NODISCARD __attribute__((warn_unused_result))
#elif defined(_MSC_VER)
@@ -15,6 +15,7 @@
#undef NLOHMANN_VIEW_UNLIKELY
#undef NLOHMANN_VIEW_ALWAYS_INLINE
#undef NLOHMANN_VIEW_NOINLINE
#undef NLOHMANN_VIEW_NOCLONE
#undef NLOHMANN_VIEW_NODISCARD
#undef NLOHMANN_VIEW_THROW
#undef NLOHMANN_VIEW_LITTLE_ENDIAN
+3 -8
View File
@@ -65,14 +65,9 @@ struct position_source
return token{end - start};
}
/// the range [first, last), or none if either is npos
/// the range [first, last)
void set(std::size_t first, std::size_t last) noexcept
{
if (first == std::string::npos || last == std::string::npos)
{
clear();
return;
}
start = first;
end = last;
}
@@ -191,11 +186,11 @@ struct position_source
first = n.off;
last = n.off + 4u;
break;
case node_kind::object:
case node_kind::object: // LCOV_EXCL_LINE
case node_kind::array:
case node_kind::link:
default:
break;
break; // LCOV_EXCL_LINE
}
// (a crafted image can point past the text)
if (last == std::string::npos || last > d.size)
+163 -8
View File
@@ -19,6 +19,7 @@
#include <nlohmann/detail/view/macro_scope.hpp>
#include <nlohmann/detail/view/node.hpp>
#include <nlohmann/detail/view/scan.hpp>
#include <nlohmann/detail/view/simd.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -103,12 +104,56 @@ NLOHMANN_VIEW_NOINLINE FloatType float_value(const char* first, const node& n)
return convert_float<FloatType>(first, last, dot, mantissa_end);
}
#if NLOHMANN_VIEW_VECTOR
/*!
@brief the value of the first 16 digits of a run of digits with a point after
int_digits of them (or none, if int_digits >= 16)
The 17 bytes at p are read at once: the bytes after the point move down by one,
then pairs, quadruples, and octets of digits are combined by multiplications
(after simdjson). The bytes [p, p + 32) must be readable. Bytes that are not
digits (only in a damaged image loaded with image_check::bounds) give a wrong
value, but no undefined behavior.
*/
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t sixteen_digits(const unsigned char* p, unsigned int_digits) noexcept
{
#if NLOHMANN_VIEW_NEON
const uint8x16_t low = vld1q_u8(p);
const uint8x16_t index = vcombine_u8(vcreate_u8(0x0706050403020100u), vcreate_u8(0x0F0E0D0C0B0A0908u));
const uint8x16_t before_point = vcltq_u8(index, vdupq_n_u8(static_cast<std::uint8_t>(int_digits)));
const uint8x16_t digits = vsubq_u8(vbslq_u8(before_point, low, vextq_u8(low, vld1q_u8(p + 16), 1)), vdupq_n_u8('0'));
const uint16x8_t twos = vpaddlq_u8(vmulq_u8(digits, vreinterpretq_u8_u16(vdupq_n_u16(0x010A))));
const uint32x4_t fours = vpaddlq_u16(vmulq_u16(twos, vreinterpretq_u16_u32(vdupq_n_u32(0x00010064))));
const uint64x2_t eights = vpaddlq_u32(vmulq_u32(fours, vreinterpretq_u32_u64(vdupq_n_u64(0x0000000100002710u))));
return (vgetq_lane_u64(eights, 0) * 100000000u) + vgetq_lane_u64(eights, 1);
#else
// NOLINTBEGIN(portability-simd-intrinsics)
const __m128i low = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(p))); // NOLINT(bugprone-casting-through-void)
const __m128i high = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(p + 16))); // NOLINT(bugprone-casting-through-void)
const __m128i before_point = _mm_cmpgt_epi8(_mm_set1_epi8(static_cast<char>(int_digits)), _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
const __m128i moved = _mm_or_si128(_mm_srli_si128(low, 1), _mm_slli_si128(high, 15));
const __m128i digits = _mm_sub_epi8(_mm_or_si128(_mm_and_si128(before_point, low), _mm_andnot_si128(before_point, moved)), _mm_set1_epi8('0'));
// (16-bit lanes: SSE2 has no multiply-add of bytes)
const __m128i tens = _mm_setr_epi16(10, 1, 10, 1, 10, 1, 10, 1);
const __m128i twos = _mm_packs_epi32(_mm_madd_epi16(_mm_unpacklo_epi8(digits, _mm_setzero_si128()), tens),
_mm_madd_epi16(_mm_unpackhi_epi8(digits, _mm_setzero_si128()), tens));
const __m128i fours = _mm_madd_epi16(twos, _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1));
const __m128i eights = _mm_madd_epi16(_mm_packs_epi32(fours, fours), _mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1));
const auto upper = static_cast<std::uint32_t>(_mm_cvtsi128_si32(eights));
const auto lower = static_cast<std::uint32_t>(_mm_cvtsi128_si32(_mm_srli_si128(eights, 4)));
// NOLINTEND(portability-simd-intrinsics)
return (std::uint64_t{upper} * 100000000u) + lower;
#endif
}
#endif
/*!
@brief the digits of a float token with at most 19 digits, from its layout
The digit layout recorded while parsing says where the integer digits, the
fraction digits, and the exponent are, so the digits are read eight at a
time without scanning.
time without scanning (with SIMD, a token of 16 to 19 digits sixteen at a
time).
@param[in] p first character of the token
@param[in] e end of the token
@@ -118,15 +163,34 @@ NLOHMANN_VIEW_ALWAYS_INLINE float_significand layout_decimal(const unsigned char
{
const bool negative = *p == '-';
p += negative ? 1 : 0;
std::uint64_t w = parse_upto19(p, int_digits, limit);
p += int_digits;
std::uint64_t w = 0;
std::int64_t q = 0;
if (frac_digits != 0)
#if NLOHMANN_VIEW_VECTOR
const unsigned count = int_digits + frac_digits;
if (count >= 16 && limit - p >= 32)
{
w = (w * int_pow10(frac_digits)) + parse_upto19(p + 1, frac_digits, limit);
p += 1 + frac_digits;
// (the point, if any, follows the integer digits; the digits after
// the first 16 are at most three)
w = sixteen_digits(p, int_digits);
for (unsigned i = 16; i < count; ++i)
{
w = (w * 10) + static_cast<std::uint64_t>(p[i + (i >= int_digits ? 1 : 0)] - '0');
}
p += count + (frac_digits != 0 ? 1 : 0);
q = -static_cast<std::int64_t>(frac_digits);
}
else /* NOLINT(readability/braces) */
#endif
{
w = parse_upto19(p, int_digits, limit);
p += int_digits;
if (frac_digits != 0)
{
w = (w * int_pow10(frac_digits)) + parse_upto19(p + 1, frac_digits, limit);
p += 1 + frac_digits;
q = -static_cast<std::int64_t>(frac_digits);
}
}
if (p != e)
{
// [eE][+-]digits; huge exponents saturate (the parser rejected
@@ -161,12 +225,22 @@ NLOHMANN_VIEW_ALWAYS_INLINE float_significand layout_decimal(const unsigned char
The result is correctly rounded by the lexer's conversion
(detail::decimal_to_float(): Clinger's fast path where both operands are
exact, else the Eisel-Lemire algorithm, which needs no fallback for up to 19
digits), so it is the value parse() produces.
digits), so it is the value parse() produces. Tokens of 16 or more digits go
to Eisel-Lemire directly: the fast path takes few of them (none of 17 digits),
and its check is a branch that data like GeoJSON coordinates mispredicts.
*/
template<typename FloatType>
NLOHMANN_VIEW_ALWAYS_INLINE FloatType layout_float(const unsigned char* p, const unsigned char* e, unsigned int_digits, unsigned frac_digits, const unsigned char* limit) noexcept
{
return decimal_to_float<FloatType>(layout_decimal(p, e, int_digits, frac_digits, limit));
const float_significand d = layout_decimal(p, e, int_digits, frac_digits, limit);
if (int_digits + frac_digits >= 16)
{
using format = ieee_binary_format<std::numeric_limits<FloatType>::digits>;
native_float_t<FloatType> value{};
float_from_bits(eisel_lemire<format>(d.exponent, d.w) | (d.negative ? (std::uint64_t{1} << format::sign_bit()) : 0u), value);
return value;
}
return decimal_to_float<FloatType>(d);
}
/// the value of a float set by an edit: its token (the shortest round-trip
@@ -185,6 +259,80 @@ NLOHMANN_VIEW_NOINLINE FloatType edited_float(const char* token, const node& n)
return float_value<FloatType>(token, n);
}
#if NLOHMANN_VIEW_VECTOR
/// eisel_lemire() for the token w * 10^q of coordinate_float()
template<typename Format>
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t coordinate_bits(std::int64_t q, std::uint64_t w, Format /*format*/) noexcept
{
return eisel_lemire<Format>(q, w);
}
/*!
@brief (binary64) eisel_lemire() without the cases that tokens of 16 or 17
digits with 5 or more after the point cannot reach: a value of 0, a
subnormal, an infinity, or a tie (q < -4)
*/
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t coordinate_bits(std::int64_t q, std::uint64_t w, ieee_binary_format<53> format) noexcept
{
if (NLOHMANN_VIEW_UNLIKELY(w == 0 || q > -5))
{
return eisel_lemire<ieee_binary_format<53>>(q, w);
}
static_cast<void>(format);
const int lz = count_leading_zeros(w);
const std::uint64_t normalized = w << static_cast<unsigned>(lz);
const auto index = static_cast<std::size_t>(2 * (q - pow5_128_smallest_power));
const uint128_parts product = full_multiplication(normalized, pow5_128()[index]);
std::uint64_t high = product.high;
if (NLOHMANN_VIEW_UNLIKELY((high & 0x1FFu) == 0x1FFu))
{
// (the lower bits may carry into the result)
const std::uint64_t second = full_multiplication(normalized, pow5_128()[index + 1]).high;
high += product.low + second < product.low ? 1u : 0u;
}
const auto upperbit = static_cast<unsigned>(high >> 63u);
std::uint64_t mantissa = high >> (upperbit + 9);
auto power2 = static_cast<std::uint64_t>(((217706 * q) >> 16) + 63 + static_cast<std::int64_t>(upperbit) - lz + 1023);
mantissa = (mantissa + (mantissa & 1u)) >> 1u;
const bool carry = mantissa >= (std::uint64_t{2} << 52u);
mantissa = carry ? (std::uint64_t{1} << 52u) : mantissa;
power2 += carry ? 1u : 0u;
return (mantissa & ~(std::uint64_t{1} << 52u)) | (power2 << 52u);
}
/*!
@brief (binary32 and binary64) the value of a float token of the source with
16 or 17 digits, a point, and no exponent, the shape of most coordinates
written with full precision; whether the token of n has this shape
These tokens skip the general layout of layout_decimal(): no digits beyond
the 17th, no exponent (and Eisel-Lemire directly, as in layout_float()).
*/
template<typename FloatType>
NLOHMANN_VIEW_ALWAYS_INLINE bool coordinate_float(const document_data& d, const node& n, FloatType& value) noexcept
{
const unsigned int_digits = n.extra & 0xFFu;
const unsigned frac_digits = n.extra >> 8u;
const unsigned count = int_digits + frac_digits;
const auto* const first = reinterpret_cast<const unsigned char*>(d.src + n.off); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
const unsigned negative = first[0] == '-' ? 1u : 0u;
if (count - 16u > 1u || frac_digits == 0 || n.len != negative + count + 1 || d.size - n.off < 33)
{
return false;
}
const unsigned char* const digits = first + negative;
const std::uint64_t w = sixteen_digits(digits, int_digits);
// (the 17th digit follows the point)
const std::uint64_t w17 = (w * 10) + static_cast<std::uint64_t>(digits[17] - '0');
using format = ieee_binary_format<std::numeric_limits<FloatType>::digits>;
native_float_t<FloatType> result{};
float_from_bits(coordinate_bits(-static_cast<std::int64_t>(frac_digits), count == 17 ? w17 : w, format{}) | (static_cast<std::uint64_t>(negative) << format::sign_bit()), result);
value = result;
return true;
}
#endif
/// the value of the float token of a node, as parse() converts it; floats and
/// doubles with at most 19 digits are converted from the digit layout
template<typename FloatType>
@@ -200,6 +348,13 @@ FloatType float_value(const document_data& d, const node& n)
template<typename FloatType>
FloatType float_value(const document_data& d, const node& n, std::true_type /*binary32 or binary64*/)
{
#if NLOHMANN_VIEW_VECTOR
FloatType value {};
if (coordinate_float(d, n, value))
{
return value;
}
#endif
const unsigned int_digits = n.extra & 0xFFu;
const unsigned frac_digits = n.extra >> 8u;
if (NLOHMANN_VIEW_LIKELY(int_digits + frac_digits <= 19)) // (255 marks "many")
+5 -4
View File
@@ -44,6 +44,7 @@ index_status array_index(const StringType& s, std::size_t& idx) noexcept
}
/// throws the exception json_pointer::array_index throws for this status
/// (without a context, as json_pointer::array_index)
template<typename StringType>
[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_error(index_status status, const StringType& s)
{
@@ -83,7 +84,7 @@ View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode)
{
if (mode == pointer_mode::checked)
{
throw_key_not_found(token);
throw_key_not_found(site_of(cur), token);
}
return View();
}
@@ -95,7 +96,7 @@ View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode)
{
if (throwing)
{
throw_array_index_past_end(cur.size());
throw_array_index_past_end(site_of(cur), cur.size());
}
return View();
}
@@ -114,7 +115,7 @@ View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode)
{
if (mode == pointer_mode::checked)
{
throw_array_index_out_of_range(idx);
throw_array_index_out_of_range(site_of(cur), idx);
}
return View();
}
@@ -124,7 +125,7 @@ View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode)
{
if (throwing)
{
throw_out_of_range(exception_id::pointer_unresolved, concat("unresolved reference token '", token, "'"));
throw_out_of_range(site_of(cur), exception_id::pointer_unresolved, concat("unresolved reference token '", token, "'"));
}
return View();
}
+51
View File
@@ -198,6 +198,57 @@ inline const unsigned char* find_block_comment_end(const unsigned char* p, const
return p;
}
/// The digits of a fraction, whose number varies from one number to the next: skip_digits() with 16 bytes compared at
/// once and the end of the run taken from a bit mask (SSE2), instead of a compare and a branch for each digit. That
/// is about a third of the instructions for a fraction of 12 digits, and no branch that is mispredicted when the
/// lengths vary. Where there is no SSE2, skip_digits() is used.
#if NLOHMANN_VIEW_SSE2
// The last bytes of the input, one at a time. GCC unrolls this loop in every inlined copy of the function below, which
// makes the parse loop 4 KiB larger and slows down documents that have hardly any fractions; out of line, it does
// not. Clang does better with the loop inline (a call in the parse loop costs it more than the unrolling).
#if defined(__GNUC__) && !defined(__clang__)
inline NLOHMANN_VIEW_NOINLINE const unsigned char* skip_digits_tail(const unsigned char* p, const unsigned char* e) noexcept
{
while (p != e && is_digit(*p))
{
++p;
}
return p;
}
#else
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_digits_tail(const unsigned char* p, const unsigned char* e) noexcept
{
while (p != e && is_digit(*p))
{
++p;
}
return p;
}
#endif
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_fraction_digits(const unsigned char* p, const unsigned char* e) noexcept
{
while (e - p >= 16)
{
const __m128i in = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(p))); // NOLINT(bugprone-casting-through-void)
// a digit is above '/' and below ':' (signed compares: a byte with the top bit set is negative, and neither)
const __m128i digits = _mm_and_si128(_mm_cmpgt_epi8(in, _mm_set1_epi8('/')), _mm_cmplt_epi8(in, _mm_set1_epi8(':')));
const auto not_digit = static_cast<std::uint64_t>(~static_cast<unsigned>(_mm_movemask_epi8(digits)) & 0xFFFFu);
if (not_digit != 0)
{
return p + count_trailing_zeros(not_digit);
}
p += 16;
}
return skip_digits_tail(p, e);
}
#else
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_fraction_digits(const unsigned char* p, const unsigned char* e) noexcept
{
return skip_digits(p, e);
}
#endif
/// powers of ten up to 10^19 as integers
inline std::uint64_t int_pow10(unsigned k) noexcept
{
Loaded 100 of 169 files, more files were not shown because too many files have changed in this diff. Show more