Describe comparison in the no-thread-local docs and CI target

Comparing two values now bounds its descent with a thread_local counter
just as copying does, so the JSON_NO_THREAD_LOCAL page, the macro
overview and the ci_test_no_thread_local target cover both rather than
copying alone.

Also record what switching the macro on costs a comparison: on the
benchmark documents, comparing two equal values takes 10% to 90% longer.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-24 17:01:19 +02:00
committed by GitHub
parent e6a2c674ef
commit a645352bc6
3 changed files with 16 additions and 15 deletions
+4 -4
View File
@@ -315,10 +315,10 @@ add_custom_target(ci_test_skiplibraryversioncheck
# Disable thread-local storage. # Disable thread-local storage.
############################################################################### ###############################################################################
# Without thread-local storage, the copy constructor cannot bound its descent # Without thread-local storage, copying and comparing cannot bound their
# and copies every object and array without the call stack. That path is # descent and handle every object and array without the call stack. Those paths
# otherwise only reached by values nested deeper than the bound, so this target # are otherwise only reached by values nested deeper than the bound, so this
# is what runs the whole test suite through it. # target is what runs the whole test suite through them.
add_custom_target(ci_test_no_thread_local add_custom_target(ci_test_no_thread_local
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
@@ -7,16 +7,16 @@
When defined, the library does not use `#!cpp thread_local` storage. This is relevant for the few environments whose When defined, the library does not use `#!cpp thread_local` storage. This is relevant for the few environments whose
toolchain does not support it. toolchain does not support it.
The copy constructor copies the first levels of a value by copying the containers, which copy their elements, and Copying a value and comparing two values both descend into the first levels by letting the containers copy or compare
completes whatever is nested deeper than that without the call stack, so that copying a value cannot exhaust the stack themselves, and finish whatever is nested deeper than that without the call stack, so that neither can exhaust the stack
however deeply it is nested. It counts the levels it has descended into in a `#!cpp thread_local` variable, as a counter however deeply the values are nested. Each counts the levels it has descended into in a `#!cpp thread_local` variable, as
shared between threads would be raced. a counter shared between threads would be raced.
Without that counter, no descent can be bounded safely, so objects and arrays are copied without the call stack right Without those counters, no descent can be bounded safely, so objects and arrays are copied and compared without the call
away. Copying keeps working exactly as it does otherwise - the same values come out, and deeply nested values are copied stack right away. Both keep working exactly as they do otherwise - the same values come out, the same comparisons hold,
just as safely - but copying is slower, because the containers no longer copy themselves. Copying the benchmark and deeply nested values are handled just as safely - but both are slower, because the containers no longer copy or
documents takes 9% (`canada.json`) to 34% (`twitter.json`) longer; values built mostly from objects are affected the compare themselves. Copying the benchmark documents takes 9% (`canada.json`) to 34% (`twitter.json`) longer, and
most. comparing two equal ones 10% (`citm_catalog.json`) to 90% (`canada.json`) longer.
## Default definition ## Default definition
+3 -2
View File
@@ -93,8 +93,9 @@ See [full documentation of `JSON_NO_IO`](../api/macros/json_no_io.md).
## `JSON_NO_THREAD_LOCAL` ## `JSON_NO_THREAD_LOCAL`
When defined, the library does not use `#!cpp thread_local` storage. Copying a value then always avoids the call stack When defined, the library does not use `#!cpp thread_local` storage. Copying a value and comparing two values then
rather than descending into a bounded number of levels first, which is slower but yields the same values. always avoid the call stack rather than descending into a bounded number of levels first, which is slower but yields the
same values and the same comparisons.
See [full documentation of `JSON_NO_THREAD_LOCAL`](../api/macros/json_no_thread_local.md). See [full documentation of `JSON_NO_THREAD_LOCAL`](../api/macros/json_no_thread_local.md).