From 0e9754d772b8e53281c6f95ff0b676f467e49dbf Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 20 Aug 2026 22:51:17 +0200 Subject: [PATCH] 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 --- cmake/ci.cmake | 8 ++++---- .../docs/api/macros/json_no_thread_local.md | 18 +++++++++--------- docs/mkdocs/docs/features/macros.md | 5 +++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 011c552fd..ba7d6d558 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -246,10 +246,10 @@ add_custom_target(ci_test_noglobaludls # Disable thread-local storage. ############################################################################### -# Without thread-local storage, the copy constructor cannot bound its descent -# and copies every object and array without the call stack. That path is -# otherwise only reached by values nested deeper than the bound, so this target -# is what runs the whole test suite through it. +# Without thread-local storage, copying and comparing cannot bound their +# descent and handle every object and array without the call stack. Those paths +# are otherwise only reached by values nested deeper than the bound, so this +# target is what runs the whole test suite through them. add_custom_target(ci_test_no_thread_local COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja diff --git a/docs/mkdocs/docs/api/macros/json_no_thread_local.md b/docs/mkdocs/docs/api/macros/json_no_thread_local.md index 126116ec3..485f037ac 100644 --- a/docs/mkdocs/docs/api/macros/json_no_thread_local.md +++ b/docs/mkdocs/docs/api/macros/json_no_thread_local.md @@ -7,16 +7,16 @@ When defined, the library does not use `#!cpp thread_local` storage. This is relevant for the few environments whose toolchain does not support it. -The copy constructor copies the first levels of a value by copying the containers, which copy their elements, and -completes whatever is nested deeper than that without the call stack, so that copying a value cannot 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 -shared between threads would be raced. +Copying a value and comparing two values both descend into the first levels by letting the containers copy or compare +themselves, and finish whatever is nested deeper than that without the call stack, so that neither can exhaust the stack +however deeply the values are nested. Each counts the levels it has descended into in a `#!cpp thread_local` variable, as +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 -away. Copying keeps working exactly as it does otherwise - the same values come out, and deeply nested values are copied -just as safely - but copying is slower, because the containers no longer copy themselves. Copying the benchmark -documents takes 9% (`canada.json`) to 34% (`twitter.json`) longer; values built mostly from objects are affected the -most. +Without those counters, no descent can be bounded safely, so objects and arrays are copied and compared without the call +stack right away. Both keep working exactly as they do otherwise - the same values come out, the same comparisons hold, +and deeply nested values are handled just as safely - but both are slower, because the containers no longer copy or +compare themselves. Copying the benchmark documents takes 9% (`canada.json`) to 34% (`twitter.json`) longer, and +comparing two equal ones 10% (`citm_catalog.json`) to 90% (`canada.json`) longer. ## Default definition diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index 8296eb05e..bd98a61cf 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -93,8 +93,9 @@ See [full documentation of `JSON_NO_IO`](../api/macros/json_no_io.md). ## `JSON_NO_THREAD_LOCAL` -When defined, the library does not use `#!cpp thread_local` storage. Copying a value then always avoids the call stack -rather than descending into a bounded number of levels first, which is slower but yields the same values. +When defined, the library does not use `#!cpp thread_local` storage. Copying a value and comparing two values then +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).