mirror of
https://github.com/nlohmann/json.git
synced 2026-10-21 11:29:53 +00:00
bd5227c2ec93264fea1696c33f6333e187d682a5
327
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd5227c2ec |
Fix silent wrong results for custom number types (#5805)
* Fix silent wrong results for custom number types
Squashed onto develop
|
||
|
|
08d7fbb0a1 |
Read FILE* input with std::fgetc under MemorySanitizer (#5874)
With glibc and optimization, <stdio.h> turns getc_unlocked into an extern inline function that reads the stdio buffer (fp->_IO_read_ptr) directly. glibc, which is not instrumented, fills that buffer, so MemorySanitizer treats the bytes as uninitialized and reports a false positive when the parsers read from a FILE* (e.g., the fuzz harness FILE* leg, OSS-Fuzz 575915982). std::fgetc is an opaque call whose result MemorySanitizer treats as initialized. Select JSON_UNLOCKED_FILE_IO 0 when compiled with MemorySanitizer. This is a regression from #5828 and not part of any release. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
4971200b54 |
Add images of json_documents: save() and load() (#5632)
* Add images of json_documents: save() and load()
An image is a document stored so that loading it needs no
parsing: save() writes the node index, the text and the decoded
strings; the static load() reads an image written by save().
load() takes a pointer and size, a borrowed vector, or an owned
rvalue vector; the nodes are copied so they are aligned and can
be edited, while the text and decoded strings stay in the image.
image_check controls how much load() trusts the input: full
checks structure, bounds, strings and numbers, the parser's own
guarantees; bounds checks structure and bounds only; none skips
all checks, for images from a trusted source.
Layout is little-endian only ("NJVI" header, nodes, text, decoded
strings), following the idea of zero-copy formats such as
FlatBuffers and YaFF; the check follows FlatBuffers' Verifier.
New errors: parse_error.116 for a malformed image or a failed
check, type_error.320 for a discarded document or a big-endian
target.
A dedicated fuzzer and 6,000 seeded corruptions, checked under
ASan/UBSan, found and fixed two gaps: unchecked reserved header
fields, and unbounded null/boolean offsets that could make
dump() throw std::length_error.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Fix MSVC errors in image test and add image_check doc anchor
Move the raw string literal out of the CHECK macro (MSVC preprocessor),
cast 64-bit header fields to std::size_t (C4244 on 32-bit), and give the
image_check section in load.md a real anchor for the mkdocs strict build.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Check each distinct string and float range once in the full image check
The full check scanned the contents of every string node and every float token over its own range, so many nodes pointing to one large range made load() quadratic. The structural walk now only collects the ranges; after it, each kind is sorted and checked once per distinct range. Ranges of one kind that overlap without being identical are rejected, as save() never writes them (nodes that share a value share the whole range). The cost is linear in the size of the image plus sorting the ranges.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Adapt the image tests to named documents and last-wins lookups
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Test that the targets of links never reach an image
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Test lookups in loaded images with duplicate and colliding keys
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Release the list of large objects once load() has built the indexes
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Test that invalid UTF-8 of a loaded image is not copied into an editable document
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Document that editable documents refuse invalid UTF-8 copied from a loaded image
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Expect first-wins lookups in the image tests
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Avoid useless casts of header fields in the image tests
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Fix clang-tidy 22 findings in unit-json_view_image.cpp and image.hpp
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Fix MSVC C4244 and C2017 in the image test
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Fix the indentation of a loop in the image test
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Make json_view.hpp pass include-what-you-use
ci_single_binaries runs IWYU with --error on every header. For json_view.hpp
it suggested adding <array> (std::array is used), the headers that json.hpp
already provides (abi_config, abi_macros, input_adapters, json_pointer,
cpp_future, string_concat, value_t, json_fwd), and <version> for
std::nullptr_t, and removing <cstddef>.
- include <array>
- keep <cstddef> (nullptr_t, size_t; IWYU attributes them to <version> and <cstring>)
- tell IWYU not to suggest the headers that json.hpp provides: the amalgamated
json_view.hpp only includes json.hpp, so including them here would duplicate
their definitions
- drop edit_storage.hpp, which edit.hpp includes
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Silence a clang-tidy C++17 finding in the image test
bugprone-suspicious-stringview-data-usage flags data() of the source view
under C++17, although the length is passed and checked by the REQUIRE
before it.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Build the image link test without exceptions
load_result() exists only with exceptions; with JSON_NOEXCEPTION the test
loads the image with the check directly (a failed check aborts).
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Regenerate the amalgamated headers
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Follow the renames from the review of the view builder
The review of #5620 renamed document_data's tape/tape_size/tape_cap to
nodes/node_count/node_capacity and made the decode arena a
std::vector<char>; adapt the code of this change to it.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Rename the emit lambda in the image writer for Qt compatibility
Qt defines emit as an empty macro, so a Qt header included before
json_view.hpp broke the lambda's declaration (see #5865). The slots
variables in the image tests are renamed as well.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Address the review of json_document images
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Regenerate the amalgamated headers
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
|
||
|
|
823eee3b59 |
Add editable json_documents: set, push_back, insert, and erase (#5630)
* Add editable json_documents: set, push_back, insert, and erase basic_json_document gets a second template parameter, Editable (false by default), plus the aliases json_editable_document, json_editable_view, ordered_json_editable_document and ordered_json_editable_view. Editable documents can change values and structure without rewriting the source text: set()/push_back() on values, keys, array indices and JSON pointers; insert() before an array element; erase() of an object key, array index or JSON pointer. New values and element sequences go into edit storage that the document owns and never moves, so views keep referring to their value across edits and a parsed node never moves. Read-only documents walk the plain node array and are unaffected. Strings are checked for UTF-8 on entry, so dump() of an editable document never throws type_error.316. Binary values cannot be stored (type_error.319). A seeded differential test applies random edits to an editable document and to the equivalent ordered_json and compares both after every step. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix old clang and MSVC C4127 in editable json documents Value-initialize the const std::less in find_parent (clang 3.4/3.6 do not implement DR 253), and test the Editable template argument through a function to avoid MSVC C4127. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Copy nested values into a document without recursion Counting and copying the nodes of a view or a basic_json value into an editable document recursed once per nesting level, so that a deeply nested value overflowed the stack. The four functions now walk the value with an explicit stack, as materialize() does. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Do not leave a half-assigned container when set_moved() throws assign() rewrote the kind, length and extent of a slot before set_moved() registered its new element sequence. set_moved() can throw (std::bad_alloc from reserving the bookkeeping vectors) for a slot that is not moved yet, which left a container without the moved flag that showed its old children. The bookkeeping is now reserved first (reserve_moved()), so that nothing after the first write to the slot can throw. block_of() reserves before it marks anything for the same reason. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Check strings copied from another document for valid UTF-8 An editable document only holds valid UTF-8, but copy_scalar() copied the strings and keys of a view of another document unchecked. A document of a weaker check (or a borrowed text that changed after parsing) could therefore bring ill-formed UTF-8 into it. The copy is checked now, with the error that dump() reports for the string; copies within the same document stay unchecked. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Allow the edit arena to grow up to 4 GiB - 1 bytes append_text() doubled the capacity of the arena and rejected the result if it exceeded 4 GiB, so that an arena of more than 2 GiB could not grow even though the 32-bit offsets of nodes address 4 GiB - 1 bytes. The capacity is now clamped to that limit (text_capacity()), and an append is rejected only if the bytes themselves do not fit. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Set a null value below a pointer as basic_json does set(json_pointer, value) turned a null parent into an object for every last reference token, so "/a/0" and "/a/-" below {"a":null} made {"a":{"0":1}}, where basic_json's operator[](json_pointer) makes an array. A null parent now becomes an array for "-" and for digit tokens (filled with nulls up to the index) and an object otherwise. An invalid index is reported before the parent changes. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Replace a container by a scalar in constant time once it is linked Replacing an array or object that spans several nodes by a scalar looks up its parent from the root (find_parent), which is linear in the size of the document: setting every element of a 20,000 element array took more than half a second. The parent only has to switch to links once; afterward the extent of the replaced value no longer matters. Nodes that an entry of a moved sequence links to are now marked (node_flags::linked), and assign() skips the lookup for them. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Update the json_view banner and type_error.319 for editable documents The banner still described a read-only view, and the documentation of type_error.319 listed set and push_back only, although insert rejects binary values as well. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Assign the member that lookups find when set() meets duplicate keys An editable document reads the last member of a repeated key (as the read-only document does), but set(object, key, value) assigned the first one: a view taken from object[key] before the call did not show the new value. It now assigns the last member's value, keeps the key at the position of its first occurrence (where materialize() puts it), and drops the other members. The seeded differential test now also edits documents whose objects repeat keys and compares every lookup (operator[], at, find, value, contains, count, and JSON pointers) with the parsed basic_json value. A targeted test covers duplicates before and after edits that move the object, in large objects with an index, in moved arrays, and in values copied from other documents. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Assign the first member when set() meets duplicate keys again Lookups find the first member of a repeated key again, so set(object, key, value) assigns that member (keeping the key where it is) and drops the others, as documented before, and a view taken from object[key] shows the new value. This undoes the code and documentation changes of |
||
|
|
3ff37ead75 |
Scan json_view strings with SIMD and index large objects (#5628)
* Scan json_view strings with SIMD and index large objects Speed up json_view's parser with SIMD scanning and a hash table for large objects. Long runs of string bytes are scanned 16 bytes at a time with NEON (AArch64, GCC and Clang) and SSE2 (x86-64), both baseline instruction sets. Keys keep 16 table checks before the vector loop, because their lengths repeat from record to record; string values get 8, because their lengths vary more. Non-ASCII text is validated 16 bytes at a time with simdjson's "lookup4" check (Keiser and Lemire, 2021), with NEON on AArch64 and, on x86-64, with SSSE3. SSSE3 is not part of baseline x86-64, so the check is compiled for SSSE3 with a function attribute and used only where CPUID reports it, which all x86-64 CPUs since about 2011 do; the answer is cached in a statically initialized atomic, so there is no guard of a local static and no global constructor. The same input is accepted either way. JSON_VIEW_NO_SIMD selects the portable code. On x86-64, string runs are now checked vector-first: one SSE2 compare from the first byte finds the end of most keys and short values, instead of a branch per byte for the first 8-16 bytes. AArch64 keeps the byte-wise steps, where a NEON mask costs more and the branches predict well. Entering an object or array no longer stalls: open() stores the parent's frame field by field instead of building it on the stack and reading it back with wider loads, which waited for the narrower stores to retire. Objects with 128 members or more get an open-addressing hash table built when the object closes, so operator[], at(), find(), contains(), count(), value(), and JSON pointers take constant time on average in such objects; of duplicate keys, the first is kept, as for the linear search. The idea comes from Boost.JSON. simdjson is credited in simd.hpp's SPDX block, the README, and license.md. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix GCC module build and MSVC C4127 in the json_view SIMD code GCC ignores the target attribute in modules, so the SSSE3 dispatch is disabled for the module interface (the check stays portable, SSE2 is kept). Make the 8-vs-16 byte unrolling condition in scan_string_run a preprocessor/template split to avoid a constant condition (C4127). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Remove an accidentally committed GCC module cache Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Bound the probe length of the large-object hash index The key hash is not seeded, so keys chosen to collide made building the table quadratic (20,000 colliding keys took 470 ms to parse). A key may now sit at most 64 slots from its home slot; if a key would sit further away, the table is dropped and the object is searched linearly. Lookups stop after the same distance. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Release the spare capacity of the hash index in shrink_to_fit shrink_to_fit() now trims the tables of large objects like the node array and the decoded strings, and the list of large objects is released as soon as the tables are built. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use the portable string scan on non-x86 targets that define __SSE2__ WebAssembly with -msse2 defines __SSE2__, but has no <cpuid.h> or x86 intrinsics headers. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Document the hash index number in node::extra Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Keep the last of duplicate keys in the object hash index Lookups in objects with 128 members or more now return the last member of a repeated key, like the linear search of smaller objects and like materialize() and basic_json::parse(). build_object_index let the first occurrence win, so the same text gave different results depending on the size of the object. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Keep the first of duplicate keys in the object hash index again Lookups in objects with 128 members or more return the first member of a repeated key again, like the linear search of smaller objects. This undoes the code change of a69542046; its test now expects the first member from lookups (with and without a table) and the last value from materialize() and basic_json::parse(). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix clang-tidy 22 findings in the json_view headers Silence bugprone-casting-through-void for the SSE loads (a reinterpret_cast would trip -Wcast-align=strict), use auto for a cast initialiser, add parentheses to a mixed expression, and name bugprone-std-namespace-modification in the NOLINTs of the tuple_size/tuple_element specialisations. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix clang-tidy 22 findings in unit-json_view.cpp and unit-json_view_builder.cpp Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Avoid GCC useless-cast and strict-overflow warnings in unit-json_view.cpp Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Index strings with size_t in the colliding-keys test (MSVC C4244 on Win32) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make json_view.hpp pass include-what-you-use ci_single_binaries runs IWYU with --error on every header. For json_view.hpp it suggested adding <array> (std::array is used), the headers that json.hpp already provides (abi_config, abi_macros, input_adapters, json_pointer, cpp_future, string_concat, value_t, json_fwd), and <version> for std::nullptr_t, and removing <cstddef>. - include <array> - keep <cstddef> (nullptr_t, size_t; IWYU attributes them to <version> and <cstring>) - tell IWYU not to suggest the headers that json.hpp provides: the amalgamated json_view.hpp only includes json.hpp, so including them here would duplicate their definitions Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Move the dump, comparison, and large-object tests to unit-json_view_dump.cpp The dump and comparison tests moved to their own file in the dump pull request; the hash index tests of this branch join them there. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Follow the renames from the review of the view builder The review of #5620 renamed document_data's tape/tape_size/tape_cap to nodes/node_count/node_capacity and made the decode arena a std::vector<char>; adapt the code of this change to it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Rename slots in the object index for Qt compatibility Qt defines slots as a macro, so a Qt header included before json_view.hpp broke the declarations of the local variable (see #5865). The test variable is renamed as well. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the review of the json_view object index and SIMD scan From gregmarr's review of #5628: - Docs and comments say that the hash index is one of the object's keys. - object_index.hpp: conditional_static_cast for the hash, "slot" for the table position, no flag for a degenerate table, and a static_assert that the smallest indexed object is larger than the probe window. - scan.hpp unrolls with NLOHMANN_VIEW_REPEAT_FIRST_8/SECOND_8. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Encode JSON_VIEW_NO_SIMD and JSON_VIEW_USE_SSSE3 in the ABI namespace Both macros select between definitions of the same inline functions, so translation units that disagree on them violated the ODR. Like the other ABI-affecting macros, they now add a tag to the inline namespace (_vns and _vssse3), and the docs replace the "Define consistently" warning with the usual ABI compatibility note. From gregmarr's review of #5628. nlohmann_json.natvis covers twice as many tags now, so it lists four times as many namespaces (14.7 MB instead of 3.4 MB). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Do not include type_traits.hpp directly in the object index json.hpp, which object_index.hpp already includes, provides it; included directly, the json_view amalgamation (which only treats nlohmann/json.hpp as external) copied the json internals into json_view.hpp a second time, so the fuzzers, which include both single headers, failed with redefinitions (make_void, integer_sequence, priority_tag, ...). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Compare keys with key_equals() in the object hash index As the linear lookups do since the second review round of #5622. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
4c3a3eb5b5 |
Add dump() and comparisons to json_view (#5624)
* Add dump() and comparisons to json_view Add basic_json_view::dump() and the comparison operators, and read floats from the parser's digit layout instead of rescanning the token. dump(indent, indent_char, ensure_ascii, number_format) writes a value the way ordered_json::parse(text).dump() writes it for the same arguments: members in document order, all of them should a key occur more than once; strings escaped by the same rules, using the library's scanning kernels; floats written with the library's to_chars conversion, so the output equals basic_json's byte for byte; integers copied from the source, where they are already canonical, except -0, which parse() reads as 0. There is no error_handler argument, because the view only holds valid UTF-8. number_format::source copies numbers exactly as they appear in the source (e.g. "1.50", "1E2", "-0"), which basic_json cannot provide. operator<< takes the indentation from the stream width, as for basic_json. The writer walks iteratively, so nesting depth is limited by memory only. operator== and operator!= compare two views, or a view and a basic_json value in either order, by the rules basic_json's operator== uses: numbers compare by value across their types, objects compare by their members with duplicate keys resolved as parse() resolves them, member order matters only where the object type keeps one, and discarded views compare as discarded basic_json values do, including under JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON. Nothing is materialized except single scalars. While parsing, the view now records where the integer digits, the fraction digits, and the exponent of a float token are, so floats and doubles with at most 19 digits are read from that layout with the library's decimal_to_float() instead of rescanning the token. Both round correctly, so the values are those of parse(). get<double>(), materialize(), dump(), and the comparisons all use it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Avoid raw string with escapes inside CHECK macro (MSVC C2017) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Size the dump buffer of a small value by its own extent The source extent of a value was read from the next node, falling back to the rest of the document when that node held a decoded string. dump() of a small value could thus allocate a buffer as large as the document. Skip a few such nodes, cap the fallback estimate, and shrink a buffer that is much larger than its output. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Hold the documents of the dump and comparison tests in names root() of a temporary document is deleted: its views would dangle. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Do not shrink the output of dump() finish() copied the whole output when the buffer was more than twice as large as the result (citm dump +11%). The tighter source_extent() estimate already keeps the buffer of a small value small. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Document and test first-wins lookups next to dump() and == dump() writes every member and == resolves duplicate keys as parse() does, whereas lookups find the first member of a duplicate key. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix the clang-tidy 22 findings in json_view and its tests Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Split the dump and comparison tests off unit-json_view.cpp The MinGW linker of the Windows clang jobs cannot link object files with more than 32767 sections ("relocation truncated to fit: IMAGE_REL_AMD64_REL32 against `.rdata'"). unit-json_view.cpp reaches that limit as the stack grows, so its "json_view dump" and "json_view comparison" test cases move into unit-json_view_dump.cpp. The test generator and has_duplicate_keys() that both files use move into json_view_test_helpers.hpp. The new file mentions JSON_HAS_CPP_17, so it is built for C++17 like the file it was split from. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make json_view.hpp pass include-what-you-use ci_single_binaries runs IWYU with --error on every header. For json_view.hpp it suggested adding <array> (std::array is used), the headers that json.hpp already provides (abi_config, abi_macros, input_adapters, json_pointer, cpp_future, string_concat, value_t, json_fwd), and <version> for std::nullptr_t, and removing <cstddef>. - include <array> - keep <cstddef> (nullptr_t, size_t; IWYU attributes them to <version> and <cstring>) - tell IWYU not to suggest the headers that json.hpp provides: the amalgamated json_view.hpp only includes json.hpp, so including them here would duplicate their definitions Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Follow the renames from the review of the view builder The review of #5620 renamed document_data's tape/tape_size/tape_cap to nodes/node_count/node_capacity and made the decode arena a std::vector<char>; adapt the code of this change to it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Keep the stream includes of json_view.hpp for IWYU json_view.hpp uses std::istream and std::ostream itself, but IWYU sees them through the exported json.hpp and asked to remove both includes, which fails ci_single_binaries (single_json_view). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the review of json_view dump() and comparisons From gregmarr's review of #5624: - The output buffer takes string literals without a length. - write_float() names the IEEE single/double condition once, as the library's serializer does. - equal() checks the types first and compares with !=; the reference to the top frame is noted as dangling after pop_back(). - dump.md: one paragraph per case in the notes. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Exclude all json_view test files from Infer's reports The same std::unique_ptr false positive (USE_AFTER_DELETE) also shows for two json_documents parsed in one lambda in unit-json_view_dump.cpp (ci_infer). It affects any test that holds several documents, so the exclusion now covers tests/src/unit-json_view*.cpp; ASan and Valgrind cover these tests. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Allow the string literal parameter of the view serializer's put() for clang-tidy The overload takes the literal by array reference so that its length is a template parameter, like scan_literal() and the C array overloads of to_json() and from_json(). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Bind the serializer's frame only after the check for its end Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
43e97b629b |
Add element access, iteration, values, and JSON pointers to json_view (#5622)
* Add element access, iteration, values, and JSON pointers to json_view Give basic_json_view the read-only access functions of basic_json: operator[] and at() with keys and indices, front()/back(), find(), contains(), count(), begin()/end() and cbegin()/cend(), items() with structured bindings from C++17 on, and type_name(). Exceptions have the ids and messages of the const functions of basic_json. Where basic_json has undefined behavior the view answers safely: operator[] with a missing key or an out-of-range index returns a discarded view, and front()/back() of an empty container throw invalid_iterator.214. Objects are iterated in document order, and all members are visited; duplicate-key lookups find the first member (as yyjson and simdjson do), while parse(), materialize(), and the map conversions keep the last value, as parse() does. Keys of up to 16 bytes are compared with two overlapping loads. Add value conversions: get<T>()/get_to() for arithmetic types, bool, nullptr_t, strings (std::basic_string copied, string_view_t without a copy), BasicJsonType, views, std::vector, and maps with string keys; get_string() for the string without a copy; number_token() for the number exactly as written in the source; value() with keys and JSON pointers; and operator[]/at()/ contains() with JSON pointers. Everything else, including types with from_json(), goes through materialize() of that subtree. get<T>() of arithmetic types is inlined down to the conversion, so reading an integer needs no call. detail::json_pointer_access exposes a pointer's reference tokens to code outside basic_json. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make view lookups last-wins and chained access safe * Lookups (operator[], at, find, contains, count, value, JSON pointers) return the last member of a duplicate key, as materialize() and parse() keep it. * operator[] on a discarded view returns a discarded view instead of throwing, so v["a"]["b"] is safe for a missing "a". * operator[] and at() take any integer type (not only int and size_t), fixing ambiguous calls with unsigned, long, std::int64_t, ... * Fix the operator[] documentation, which claimed a discarded view for a type mismatch where type_error.305 is thrown. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Replace the removed operator bool of basic_json_view in the header and its tests A view is tested with is_discarded(); the lookups in at(), value() and contains(json_pointer) and the unit tests no longer rely on the explicit conversion to bool. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use named documents in the json_view tests that called root() on a temporary root() of an rvalue document is deleted, because the views would dangle. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Test discarded views with is_discarded() in the operator[] docs and examples The explicit conversion to bool of basic_json_view is gone. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Return the first member of duplicate keys from lookups again Looking up the last member of a duplicate key cannot stop at a match, so every lookup scanned the whole object (1.6 to 3.4 times slower for small objects). operator[](key), at, find, value, contains, count, and JSON pointer resolution return the first member again, as yyjson and simdjson do; materialize() and get<map>() keep the last value, as parse(). The documentation says so in the feature page and on each lookup page, and explains how to get the value parse() would give. The integer index templates and the discarded chaining of operator[] stay. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Do not force-inline the view's functions on MSVC __forceinline makes MSVC report C4714 for function templates it cannot inline (get<std::string>), an error under /WX. The forced inlining is only a performance hint, so use plain inline there. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make json_view.hpp pass include-what-you-use Mark the includes that are needed by design (json.hpp, the macro unscope, <tuple> for the tuple_size specialization), take size_t from <cstring>, and drop the forward declaration of basic_json_document that the friend declaration makes redundant. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Avoid GCC useless-cast warnings in the integer index tests Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make json_view.hpp pass include-what-you-use ci_single_binaries runs IWYU with --error on every header. For json_view.hpp it suggested adding <array> (std::array is used), the headers that json.hpp already provides (abi_config, abi_macros, input_adapters, json_pointer, cpp_future, string_concat, value_t, json_fwd), and <version> for std::nullptr_t, and removing <cstddef>. - include <array> - keep <cstddef> (nullptr_t, size_t; IWYU attributes them to <version> and <cstring>) - tell IWYU not to suggest the headers that json.hpp provides: the amalgamated json_view.hpp only includes json.hpp, so including them here would duplicate their definitions Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix the clang-tidy 22 findings in json_view and its tests The same changes as on the dump branch, where they were first made, so that this branch passes clang-tidy on its own. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Report one-character non-numeric array indices like basic_json in the view Develop's #5800 made basic_json report a JSON pointer array index such as "/a" as parse_error.109 instead of out_of_range.404, as longer ones were; the view's array_index() follows, with "-" and the empty token still unresolved. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the review of json_view element access From gregmarr's review of #5622: - count() counts every member with the key, so count(key) > 1 detects duplicate keys; it was contains() as 0/1 before. - get_to() passes types that get<T>() does not convert directly to from_json with the existing value, as basic_json::get_to() does, so that a from_json which sets only the fields present keeps the others. - array_index() checks the empty token and "-" first; the results are unchanged. - Docs: no "if an exception is thrown" where a view never changes anything; the borrowed source must also stay unmodified; items() on a temporary view is safe; back()/front() notes shortened; the basic_json see-also entries say how the view's results can differ. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Count matching keys as unsigned in the json_view access test The conditional added 1 or 0 as int to a std::size_t, which GCC rejects with -Werror=sign-conversion (ci_test_standards_gcc). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the second review round of json_view element access From gregmarr's review of #5622: - begin()/end(): "a null value or a discarded view iterates as an empty range", singular like the primitive case before it. - The class page's list of function groups has no trailing commas. - document_data::key_equals() compares a key node with a string, for the key comparisons that were spelled out in each lookup. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Write the negated enable_if conditions of json_view with negation<> With a ! or && in the condition, astyle spaces the whole template header (template < ... >); detail::negation and a named trait keep it compact, as the library writes such conditions elsewhere. From gregmarr's review of #5630. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Keep detail::negation out of json_view.hpp's enable_ifs include-what-you-use asks json_view.hpp to include detail/meta/type_traits.hpp for it, which the single header must not do (the amalgamation would duplicate json's internals). The two conditions of value() go through a trait in value.hpp, like the others. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
122d718330 |
Add json_document and json_view: node index, parser, and document (#5620)
* Add json_document and json_view: node index, parser, and document Add json_document and json_view, a read-only, zero-copy index of a JSON text, as the first public slice of the zero-copy view (#5295). A parse produces a flat array of 16-byte nodes in document order, one per value and one per object key. Strings stay in the source text; escaped strings are decoded into an arena. Integers are converted while their digits are in the cache; floats keep only their digit layout and are converted on read. Containers store the size of their subtree, so a reader can step over one in constant time. A document makes a handful of allocations, however many values it has. The parser accepts exactly what json::parse accepts, with every combination of ignore_comments and ignore_trailing_commas, with and without a trailing NUL, and under JSON_STRICT_NUL_HANDLING. It is portable C++11 and does not depend on byte order. basic_json_document adds parse, parse_copy, accept, read (reuses a document's memory), root, is_discarded, source, owns_source, node_count, memory_usage, and shrink_to_fit. basic_json_view adds type, the is_* queries, operator bool, size, empty, materialize, and source_offset. A parse error throws the same exception basic_json::parse would throw for the same input, message and position included. detail::abi_config keeps JSON_STRICT_NUL_HANDLING and JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON readable after json.hpp undefines them, in the ABI namespace so they always match the basic_json in use. A NUL byte that ends a // comment is the end of the input, as in parse() since #5696. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix document_data for old Clang (3.4-3.6) Drop the empty braced NSDMIs of the std::string members: old Clang rejects the defaulted constructor when it is used by a member initializer before the end of the class definition. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Exclude libstdc++'s string_view comparison from the sign-change check basic_string_view::_S_compare stores the difference of two lengths in a signed difference_type on purpose, which -fsanitize=integer reports for every comparison with a shorter view (test-json_view_cpp17). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Reject integer lengths in json_document::parse parse(ptr, len) compiled: len converted to allow_exceptions, and ptr was read as a C string, past the end of a buffer without a terminating NUL. Delete the overloads of parse, parse_copy, accept, and read that take an integer other than bool where the flags are expected. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Copy const rvalue strings and document the accepted inputs json_document::parse(std::move(const_string)) failed to compile with "no matching read_kind": only a non-const rvalue std::string can be moved from. Treat a const rvalue as a copied byte container. parse() does not accept everything BasicJsonType::parse() does: a FILE* and pointers to or arrays of wide characters are rejected at compile time. List the supported inputs instead. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Remove the conversion to bool from json_view explicit operator bool meant "refers to a value", which silently differs from what a basic_json converts to. Use !v.is_discarded() instead. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Delete json_document::root() on temporary documents auto v = json_document::parse(text).root() compiled and left the view dangling. Delete the overload for rvalue documents, take a named document in the tests, and document the lifetime rule. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Store node integers by halves on big-endian targets The non-little-endian path of the node writer wrote the integer's native word over len and next, so len got the high half there. Compose and split the value explicitly (len is the low half, next the high half); the little-endian path stays a plain memcpy. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Check the node array size for overflow reserve(n) and the growth of the index computed n * sizeof(node) without a check, which wraps around on 32-bit targets for inputs of about 1 GiB and allocates a too small array. Throw std::bad_alloc for a count beyond the address space and clamp the growth step to it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * State the exact input size limit of json_document The check rejects inputs of 0xFFFFFFF0 bytes or more, but the exception message and the documentation said 4 GiB. Name the limit once (max_input_size), and state 4 GiB minus 16 bytes in the message and the documentation. Test the limit with a container that only claims the size. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Remove the unused legacy_discarded_value_comparison from abi_config Nothing reads it: the view does not compare values. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Align the banner comment of json_view.hpp Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fuzz json_document with exact-size buffers and parse options The fuzzer only parsed a std::string with default options. Also parse an exact-size byte vector, which has no NUL after its last byte and takes the bounds-checked path, and derive ignore_comments and ignore_trailing_commas from the first input byte, comparing against json::parse and json::accept with the same options. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Give document_data a user-provided constructor Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix clang-tidy findings in unit-json_view_builder.cpp Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Annotate intentional patterns in unit-json_view.cpp for clang-tidy Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Suppress Flawfinder's read() finding on the deleted overload Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Check the steps of the deep-nesting test separately Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make max_input_size a function (GCC -Wunused-const-variable) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make json_view.hpp pass include-what-you-use ci_single_binaries runs IWYU with --error on every header. For json_view.hpp it suggested adding <array> (std::array is used), the headers that json.hpp already provides (abi_config, abi_macros, input_adapters, json_pointer, cpp_future, string_concat, value_t, json_fwd), and <version> for std::nullptr_t, and removing <cstddef>. - include <array> - keep <cstddef> (nullptr_t, size_t; IWYU attributes them to <version> and <cstring>) - tell IWYU not to suggest the headers that json.hpp provides: the amalgamated json_view.hpp only includes json.hpp, so including them here would duplicate their definitions - export json.hpp, keep macro_unscope.hpp, and drop the unused forward declaration of the document class Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Read the node array base after emit() in the view builder's open() emit() moves the node array when it grows, and the subtraction read base in the same expression, so the order was unspecified. MSVC Release builds without forced inlining read the old base; the container index then pointed outside the array and close() wrote out of bounds. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Silence a clang-tidy use-after-move finding in the json_view test const_text is const, so std::move does not move from it; the second call is part of the const rvalue test. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the review of the view builder and document Changes promised in the replies to the review of #5620: - read() reuses the owned copy: a copied input (an rvalue byte container, a stream, FILE*, wide characters, an iterator range) is appended to the cleared owned buffer instead of a fresh std::string being move-assigned over it. A moved-in std::string still replaces it. - The error replay runs the library parser with a SAX handler that stores nothing and throws the reported exception, instead of BasicJsonType::parse(), which built a DOM up to the error. - Pointers to and arrays of wide characters, and FILE*, take the input adapter path (converted to UTF-8 into an owned buffer) instead of failing a static_assert. Wide pointers are NUL-terminated. - Streams are read in blocks through rdbuf() into the buffer, instead of character by character through the input adapter; eofbit is set at the end, as by the library's stream adapter. - tape/tape_size/tape_cap are now nodes/node_count/node_capacity. - The builder's members get descriptive, m_-prefixed names. - The shallow frame stack is a std::array (in a wrapper with a user-provided constructor: -Weffc++ wants the member initialized, and value-initializing the 64 frames costs up to 30 % on small documents). - The value dispatch macro has no NEXT parameter; the switch is left with break, and the macro is undefined after its last use. - literal() and digits_exceed() deduce the length from the string literal; each literal has one helper; the two `if (!is_float)` blocks are merged. - arena_ensure() sits right before the writes; the decode arena is a std::vector<char>. - The builder records the deepest nesting, and materialize() sizes its stack from it once (growing it only if a subtree is deeper). - Comment fixes (hex4, slow_string, the NUL rule, put_utf8, 0 - m, the arena resize, grow()) and formatting (macro backslashes, digit cases, one power of ten per line, value_t assertion next to is_container()). - build_with's template parameters follow the builder's order. Greg's idea of keeping the source offset in `off` and the arena offset in `next` for escaped strings was measured and not adopted: string access got 7-18 % slower with a select, and 3.5-18 % slower with a branch-free field pick (Apple M-series, clang -O3), parsing was unchanged. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Apply the review's wording fixes to the json_view documentation - Copying is disabled because of its cost, not because of two documents borrowing the same buffer; the unique_ptr follows from move-only. - Inputs: streams, FILE*, and wide characters (strings, arrays, pointers) are all supported and owned; point to parse_copy() for owned copies. - The error replay only runs for failing input, builds no values, and is skipped with allow_exceptions = false. - read() writes copied inputs into the previous owned copy. - Views can dangle like std::string_view, and why there is no shared/weak pointer design. - The 4 GiB limit (16-byte nodes, 16-byte scanner steps), streams being read to the end first, which macros apply, why materialize() has no source positions, and wording nits (accept() vs basic_json::accept(), is_binary, is_discarded, see-also lists, size table, "back into"). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Say that json_view converts integers while parsing Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address the review: null inline nodes, trait spelling, and max() in json_view - inline_nodes is null when the document has no inline nodes, instead of pointing past the end of the allocation; shrink_to_fit() no longer passes it to memcpy() for an empty node array - is_byte_char and is_wide_char use conjunction/disjunction, which astyle leaves unspaced - append_stream() uses (std::max) for the count read Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Include materialize.hpp in the view builder test The test calls detail::view::materialize(), which only the single header pulled in; the multiple-header build (JSON_TEST_USING_MULTIPLE_HEADERS) failed with "'materialize' is not a member of detail::view". Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Rename emit() in the view builder for Qt compatibility Qt defines emit as an empty macro, so a Qt header included before json_view.hpp broke the declaration of the builder's emit(), see issue #5865. It is now called push_node(). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Do not copy an empty run into an unallocated arena memcpy() must not be passed a null pointer even for zero bytes, which arena_run() did for an empty run while the arena was still empty (ci_test_clang_sanitizer: "null pointer passed as argument 1" in builder.hpp). Only the slow path can see such a run. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Exclude the view builder test from Infer's reports Infer's std::unique_ptr model confuses the values that the test's build() helper returns by value and reports USE_AFTER_DELETE for one of them after the destructor of an unrelated temporary (ci_infer, 12 reports, all in tests/src/unit-json_view_builder.cpp). AddressSanitizer is clean on the same tests. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Skip the deleted-overload checks of json_view on MSVC 2015 MSVC 2015 does not treat selecting a deleted function in decltype as a substitution failure, so is_detected reports the deleted parse/parse_copy/accept/read(ptr, len) overloads as callable and the static_asserts in "integer arguments do not compile" fail (AppVeyor VS2015 jobs). Calling them still fails to compile there. Guard the negative checks as unit-delete_deprecated_functions.cpp does. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
4da932f518 |
Make parsing from std::istream and FILE* fast (#5828)
* Make parsing from std::istream and FILE* fast
Squashed onto develop
|
||
|
|
cc8334113c |
Do not use Qt's keyword macros as identifiers (#5866)
* Do not use Qt's keyword macros as identifiers The prefix tree used by unflatten() (#5836) had a member named slots, which Qt defines as an empty macro, so including a Qt header before this library failed to compile. Rename it to table and add a test that includes the library with Qt's keyword macros (slots, signals, emit, foreach, forever) defined. Fixes #5865 Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Keep the Qt keyword macros in the test from failing -Wunused-macros Clang (-Werror) rejected the macros that the test defines but the library must not use, and clang-tidy asked for parentheses around the arguments of the Q_FOREACH imitation, where the variable is a declaration. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
ce28c722bc |
Allow the same type for number_integer_t and number_unsigned_t (#5815)
* Allow the same type for number_integer_t and number_unsigned_t basic_json did not compile with NumberUnsignedType == NumberIntegerType because overloads on both types collided. Such a basic_json now stores every integer as number_integer: the colliding overloads take a placeholder type, unsigned C++ integers are converted to number_integer_t, and value_t::number_unsigned maps to number_integer. Also fixes two problems this configuration would hit: the unsigned integer parser accepted values that wrap around to negative numbers, and dump() overflowed when computing the absolute value of the minimum. A repeated NumberFloatType gets a static_assert. Refs #2573 Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use json::with_integers_t in the test and the docs Signed-off-by: Niels Lohmann <mail@nlohmann.me> * ✅ skip patch test on GCC 5 to avoid internal compiler error Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix CI: name the unsigned overload type through template parameters basic_json used number_unsigned_overload_t<basic_json> while the class was still incomplete. MSVC rejected it as a recursive alias declaration and GCC 4.9, 5 and 7 crashed with an internal compiler error. basic_json now uses number_unsigned_overload_type<NumberIntegerType, NumberUnsignedType>, which also makes the GCC 5 workaround in the patch test unnecessary. Infer reported a null dereference for the number_unsigned case in from_json, which cannot happen for a basic_json whose number_unsigned_t is number_integer_t; assert it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address review: conjunction/negation trait, astyle-friendly alias, docs table order Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
ca7740fef2 |
Move elements when converting rvalue containers to JSON (#5837)
* Move elements when converting rvalue containers to JSON Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Simplify the rvalue to_json traits Use negation<disjunction<...>> instead of a conjunction of negations and keep the template argument lists compact (astyle only keeps the spaced '< ... >' form when it is written that way). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
4e294f4b18 |
Clarify that double is only the default floating-point type in the docs (#5830)
Follow-up to review comments on #5825: number_float_t uses double precision only by default, and the stated limits apply to double. Also say "default type for X_t" instead of "default value for X_t". Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
ccc005c012 |
Fix contradictions between the documentation, the README, and the library (#5825)
- Discarded values: the legacy macro only changes <= and >=; != is true by default - Out-of-range numbers are rejected while parsing, not stored as NaN - merge_diff round trip: point to the ordered_json caveat - ensure_ascii example shows the escaped output - out_of_range.405 is thrown for "remove"/"move" on the root, not "add" - CBOR stores binary subtypes as tags - Integer/float comparison uses exact values, not conversion - diff, flatten, and the binary writers are depth-bounded - FAQ: max_digits10 for serialization, trailing commas are supported - out_of_range.407 is still thrown by to_bon8 - FetchContent_MakeAvailable needs CMake 3.14 - json_fwd.hpp contents, operator< link, RFC 7396 for merge patch - README: dump() wording, merge_diff, MSYS2/build2, patch comment typos, operator[] link, embedded CMake example aligned with the docs Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
00170dab38 |
Bump jsdom from 30.1.1 to 30.1.2 in /docs/mkdocs/scripts/mermaid (#5820)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 30.1.1 to 30.1.2. - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](https://github.com/jsdom/jsdom/compare/v30.1.1...v30.1.2) --- updated-dependencies: - dependency-name: jsdom dependency-version: 30.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
7651248315 |
Bump mkdocs-llmstxt from 0.5.0 to 0.5.1 in /docs/mkdocs (#5817)
Bumps [mkdocs-llmstxt](https://github.com/pawamoy/mkdocs-llmstxt) from 0.5.0 to 0.5.1. - [Release notes](https://github.com/pawamoy/mkdocs-llmstxt/releases) - [Changelog](https://github.com/pawamoy/mkdocs-llmstxt/blob/main/CHANGELOG.md) - [Commits](https://github.com/pawamoy/mkdocs-llmstxt/compare/0.5.0...0.5.1) --- updated-dependencies: - dependency-name: mkdocs-llmstxt dependency-version: 0.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
99d4d1097d |
Do not self-host shields.io badges in the documentation (#5821)
The privacy plugin downloads img.shields.io badges at build time; when shields.io times out, mkdocs build --strict aborts and the ci_test_build_documentation job fails until it is restarted. Exclude the host like repology.org; the version badges stay current this way. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
91a7a94cc6 |
Write doubles with the shortest digits (Żmij), digits in registers (#5634)
* Write doubles with the shortest digits (Żmij), digits in registers Write doubles with the conversion of Zmij by Victor Zverovich (MIT), ported to C++11 (detail/conversions/zmij.hpp). It finds the shortest decimal that reads back as the same double, and the closest one if there are several. Grisu2, used until now, is fast but not always shortest: it sometimes writes a 17th digit where 16 suffice, or a last digit that is not the closest. The layout is unchanged (1.5, 100.0, 1e+100, -0.0); float keeps Grisu2. Digits are converted eight at a time with the BCD conversion of Xiang JunBo, as in Zmij, and written with one byte swap per eight digits and fixed-size moves instead of per-digit loops. Leading and trailing zeros are counted from those bytes. to_chars() uses a local buffer when the caller's is shorter than the 41 bytes this may write. The powers of ten come from the number-parsing table, adjusted where it holds values rounded up, and extended with Zmij's compressed tables beyond 10^308. write_shortest() converts its 16 digits in one vector register (SSE2 on x86-64, NEON on 64-bit Arm, both baseline) and inserts the decimal point inside the register, avoiding a store-forwarding stall that cost about 25% of the time to write a double. dump() writes floats and integers straight into the serializer's write buffer instead of copying them from a member buffer, and small integers eight digits at a time. read_eight_bytes() and parse_eight_digits() are marked always-inline, which GCC had been calling out of line in the number-parsing loops. Of one million random doubles, about 0.14% are now written with different digits, always to a value that still reads back as the same double. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix CI findings in the Zmij writer and its tests - bit_ops.hpp: include macro_scope.hpp (JSON_HEDLEY_ALWAYS_INLINE); fixes IWYU - to_chars.hpp: C4100 for the unused parameter in release builds, clang-tidy sign comparison, cpplint runtime/int, GCC -Wstrict-overflow (unsigned abs) - unit-to_chars.cpp: parse with the library instead of strtod (MinGW's strtod rounds some 16/17 digit inputs wrongly); no floating-point std::to_chars with icpc Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Select the Zmij conversion by a trait, not by the double overload The non-template overloads for double asserted binary64 doubles wherever json.hpp was included, so the library no longer compiled where double is not IEEE 754 binary64 (AVR, -fshort-double). A trait now picks Zmij for any binary64 type, including a long double of that format (MSVC, Apple Arm), and Grisu2 for the others. Remove the unused write_short_decimal, powers_of_ten_16, zmij::decimal, zmij::to_decimal, and shortest_digits(double). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Credit Zmij's authors in to_chars.hpp, the README, and the license page Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Silence MSVC C4127 for a platform-constant check in the to_chars test Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
5b4c8f9b00 |
Speed up the lexer: own float parser, string scan, and \u table (#5738)
* Speed up the lexer: own float parser, string scan, and \u table Give the library its own correctly rounded float converter for binary32 and binary64 (IEEE 754), and speed up the lexer's string and escape scanning. The converter splits a number token into sign, significand, and decimal exponent, then tries Clinger's fast path, then a templated Eisel-Lemire step, and falls back to an exact big-integer digit comparison for tokens with more than 19 significant digits whose two candidate values round differently. This replaces std::from_chars and strtod/strtof for both formats, so parsed values no longer depend on the C/C++ library or the current locale. The strtold fallback kept for other long double formats (x87, binary128) now also copies a multi-byte decimal point correctly, fixing #5660. eisel_lemire() and decimal_to_float() are always inlined so callers keep the whole conversion in their hot loop. The string-scanning kernels in string_scan.hpp find a stop byte with the trailing-zero count of the SWAR mask instead of a byte loop, and scalar_string_bulk_run() validates a run of multi-byte UTF-8 sequences one after another instead of re-searching after each one. get_codepoint() decodes a contiguous \uXXXX escape with one table lookup per byte instead of four range-checked get() calls; the streaming path and all error positions are unchanged. Adds 508 generated hard float-parsing cases with expected binary32 and binary64 bits, and kernel-comparison tests for the string scans and the escape table against byte-by-byte references. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix CI warnings in own float parser - pow5_table.hpp: pow5_128_largest_power was unused in this branch's own code (GCC -Werror=unused-const-variable); tie it to the table size with a static_assert instead of removing it, since a later branch in the stack (json-view/23-zmij) uses it. - number_parse.hpp: rename the local variable `copy` to `buffer` to satisfy cpplint's build/include_what_you_use check. - unit-class_lexer.cpp: extend the NOLINT list on the seeded mt19937 with bugprone-random-generator-seed, and parenthesize `8 * sizeof(Bits) - 1` for clang-tidy. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Load string scan words with memcpy and use MSVC bit-scan intrinsics Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Reword float conversion notes for the string type and number_float_t docs Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix clang-tidy 22 findings in unit-class_lexer.cpp Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Mark the unsigned long of the MSVC bit scans for cpplint Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate the amalgamated headers Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Drop the position updates in the bulk \u path, which #5809 made unused Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address review: std::any_of in has_nonzero_digit, comment punctuation Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use data() instead of c_str() in the multi-byte decimal point path Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
7461a199b5 |
Drop the class wrapper from the C++20 comparison operator signatures in the docs (#5814)
* Drop the class wrapper from the C++20 comparison operator signatures in the docs
The signature boxes of operator<=> and the C++20 half of operator== wrapped
the member declarations in an incomplete "class basic_json { ... };". The
trailing const already marks them as members, and no other page uses such a
wrapper.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Drop the class wrapper from the json_pointer comparison signatures too
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
|
||
|
|
aa9620fb15 |
Skip the indentation after a newline 8 bytes at a time (#5810)
Pretty-printed JSON indents every line with a run of spaces, which skip_whitespace() read one character at a time. For contiguous input (bulk_scan) the lexer now skips the spaces after a newline 8 bytes at a time directly in the input buffer, including the leading spaces of the last, partial word. This bypasses get(), which is safe because bulk_scan implies the lazy position from the previous commit: nothing is counted per character. Compared to lazy positions alone, pretty-printed input (twitter, citm_catalog with indent 2 and 4) parses up to 13% faster and accept() gets up to 30% faster (GCC 13 and clang 18 on x86-64, Apple clang 21 on arm64). Minified input is unchanged within noise. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
f23830b65e |
Derive the lexer position lazily for seekable input (#5809)
* Derive the lexer position lazily for seekable input The lexer counted the read position on every character: two increments and a newline check per get(), all on members kept in memory. For seekable input (pointers, strings, other random-access byte ranges) the position can be derived instead: chars_read_total is the adapter's read count (including reads at EOF) minus a pending unget, and line and column are recomputed from the consumed input only when get_position() is called, i.e. on parse errors. JSON_DIAGNOSTIC_POSITIONS uses the new O(1) get_chars_read_total(). Stream, file, wide-string and user-defined adapters keep the eager counters. Parsing pretty-printed input gets 8-12% faster and accept() 12-27% (canada, citm_catalog, twitter; clang 21 arm64 and GCC 13 x86-64). Error messages, byte offsets, SAX positions and diagnostic positions are unchanged (differential comparison against develop on 548k inputs). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Move the std::vector<std::byte> binary type tests out of unit-regression3 The #4804/#4209 tests instantiated a second basic_json specialization (with_binary_t<std::vector<std::byte>>), including its parser and CBOR reader. With clang 18, the C++20 object of unit-regression3.cpp had 32656 COFF sections on develop; the lazy position helpers pushed it to 32975, past what the MinGW linker of the Windows clang jobs handles ("relocation truncated to fit: IMAGE_REL_AMD64_REL32 against .rdata"). unit-custom-binary-type.cpp already instantiates the same type, so the tests move there; unit-regression3.cpp drops to 27616 sections. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Report the parse errors of the position test via SAX The test caught json::parse_error, so it aborted in the ci_test_noexceptions build, where JSON_NOEXCEPTION turns the throw into std::abort(). sax_parse() hands the error position and the exception object to parse_error() without throwing, so the test now records them there and runs in every configuration. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
40a62947d3 |
support JSON Merge Patch (RFC 7396) diff creation (#4965)
* support JSON Merge Patch (RFC 7396) diff creation The JSON merge patch document format describes the set of modifications to a resource's content, that more closely mimics the syntax of the resource being modified. However, and in contrast to JSON Patch (RFC 6902), a JSON Merge Patch cannot express certain modifications, e.g., changing an array element at a specific index, or setting a specific object value to null. The null value in a JSON Merge Patch is used to remove the key from the object. The diff algorithm is not part of the RFC 7396, but it was tested against all examples provided, plus additional cases on how null values are handled. Signed-off-by: Luís Murta <luis@murta.dev> * improve algorithm efficiency Signed-off-by: Luís Murta <luis@murta.dev> * fix inconsistent nulls and empty arrays Also add CHECKs for the patch, documentation and run `make amalgamate`. Signed-off-by: Luís Murta <luis@murta.dev> * documentation cleanups Signed-off-by: Luís Murta <luis@murta.dev> * add an iterative fallback to merge_diff Bound the recursion depth like diff() and merge_patch(), and test values nested past the bound. Signed-off-by: Luís Murta <luis@murta.dev> * address the remaining review comments Signed-off-by: Luís Murta <luis@murta.dev> * move multi-line raw strings out of CHECK macros GCC 4.8/5, ICPC and NVHPC mis-tokenize multi-line raw string literals inside macro arguments, breaking the build or the parsed JSON. Signed-off-by: Luís Murta <luis@murta.dev> --------- Signed-off-by: Luís Murta <luis@murta.dev> |
||
|
|
eb8899a29c |
Restore v3.12.0 support for custom object key types (#5795)
* Restore v3.12.0 support for custom object key types Custom object_t types whose key_type is not string_t compiled with v3.12.0 for several APIs that unreleased changes broke: - to_bson failed for every custom key type (#5553 kept a const string_t* to the key); the nested entry's header is now written where the entry is found. - Copying deep values (and parse, merge_patch, update, insert) required operator== on keys (#5389); keys without one are now paired via find(). - to_cbor/to_msgpack required an implicit conversion to string_t (#5746, #5328); keys without one go through a temporary basic_json again. - at() required a conversion to string_t for its error message (#5727); other keys are passed to concat() unchanged again. The new unit-custom-object-key-type.cpp covers five key types with different capabilities. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use the with_object_t alias for the custom object key test types Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Avoid floating-point equality in custom key type test GCC with -Werror=float-equal rejects comparing the double value with ==. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Write the head of nested BSON elements in one helper Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Suppress bugprone-return-const-ref-from-parameter in key_for_message The reference is only passed to concat() within the full-expression that holds the key, like the similar helpers in binary_writer.hpp. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Make the value of the custom test key types private clang-tidy (cppcoreguidelines-non-private-member-variables-in-classes) rejects the protected member; the derived key types use a protected accessor instead. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Pass keys with data() and size() unchanged into the at() miss message key_for_message() converted every key that string_t can be constructed from, so a miss on a string_t or string_view key copied it before concat() copied it again. Keys that concat() can append through data() and size() are now passed through; only other keys (string literals, key types that just convert to string_t) are converted. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
11ef352511 |
Point users to update(…, true), JSON Pointer defaults, and built-in std::optional (#5804)
A code search of client code found many hand-written versions of functionality the library already has: recursive object merges (update(j, true) since 3.10.5), dotted-path getters (value() and contains() with a JSON Pointer), get_or helpers (value() throws for a member that is present but null), and adl_serializer specializations for std::optional (supported since 3.12.0). - modifying_values.md: describe both modes of update(), add a defaults + user settings recipe, and stop recommending Merge Patch for recursive merges. - merge_patch.md: note that null deletes keys, so a merge patch is not a general deep merge; link update(). - default_value.md: add "Nested values" (value/contains with a JSON Pointer, building a pointer from a dotted path with operator/=) and a warning that null and mistyped members are not missing. - value.md: note that a null member is converted, not replaced by the default. - json_pointer.md: link value/contains/at with JSON Pointers. - arbitrary_types.md: note that std::optional needs no serializer. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
74a03dec84 |
Throw type_error.321 for discarded values in to_bon8 (#5802)
write_bon8_value silently skipped discarded values, but the array/object count marker still counted them, so [1, discarded] produced 82 91: a marker announcing two elements followed by one. Throw type_error.321 like the other binary writers do, at any nesting level. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
6197341a21 |
Clean up non-code files (#5801)
* Clean up README, contribution guide, and repository metadata - REUSE.toml: fix the Hedley path and SPDX id (CC0-1.0), mark the docset icons as the public-domain JSON logo - CITATION.cff: v3.12.0 was released on 2025-04-11 - FILES.md: list all workflows, describe the Meson option defaults - README: ctest -LE, table of contents, typos, stale Android/MinGW advice, moved links, merge duplicate Thanks entries, list the analysis tools used in CI - CONTRIBUTING: iterative parser, json_literals.hpp is generated, links - .gitignore: backups and release outputs; .gitattributes: mark generated files - labeler: label other build systems and .github documentation - MODULE.bazel: add the module version Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Clean up CI, CMake, Makefile, and Bazel files - CMakeLists.txt: avoid VERSION_GREATER_EQUAL, which CMake < 3.7 lacks - ci.cmake: test JSON_DisableTupleReferenceConversion in ci_cmake_flags, remove unused variables and unreachable per-compiler targets, look up Clang tools consistently, forward CMAKE_CXX_FLAGS to ci_module_cpp20, format json_literals.hpp and remove backups in ci_test_amalgamation - BUILD.bazel: add json_literals.hpp to the single-header target - workflows: format json_literals.hpp before copying it, drop the obsolete natvis --version plumbing, name natvis and macro_builder in failure messages, drop the duplicate amalgamation job, install Valgrind only where needed, republish docs on version bumps, fix stale names - Makefile: complete .PHONY and help, check-amalgamation always restores the checked-in files, natvis uses its own venv, macro_builder_check installs astyle, clean removes the fuzzer binaries - remove tools/amalgamate/config_json_view.json (json_view.hpp is not on develop yet) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix inaccuracies in the documentation - version history: json_base_class_t (3.11.3), JSON_HAS_CPP_11 (3.10.0), JSON_HAS_RANGES exclusions, define-type macros, ABI tags - releases: 3.12.0 raised the minimum CMake version - from_*: the (ptr, len) overloads are deleted, not removed, in 4.0.0 - contains/count/find: document the deleted integral overloads - add JSON_HAS_RANGE_VIEW_CONVERSION and list the JSON_HAS_* macros in the macro overview - mention BON8 and error_handler where binary formats are listed - broken links, outdated URLs, warning count, Hunter v0.26.12 - copy_markdown_source hook: expand snippets in the Markdown copies Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Pass /EHsc to the Windows C++20 module build ci_module_cpp20 now forwards CMAKE_CXX_FLAGS to the module build. The Windows workflow sets CMAKE_CXX_FLAGS, which replaces CMake's MSVC defaults including /EHsc, so <chrono> failed with C4530 under /WX. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
2cca04ae6f |
Report one-character non-numeric array indices like longer ones (#5800)
* Report one-character non-numeric array indices like longer ones
A JSON pointer reference token that is not a number but has only one
character (e.g. "/a/x") was reported as out_of_range.404 ("unresolved
reference token"), because the "is not a number" check only ran for
tokens longer than one character; "/a/xy" got parse_error.109. Both now
throw parse_error.109. "-" and the empty token are still reported as
out_of_range.404. As a consequence, value(json_pointer, default) on an
array now throws for "/x" as it already did for "/xy".
Also document why ordered_map::erase's destroy/placement-new loop on
pair<const Key, T> is kept despite [basic.life]/8 before C++20.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Document the one-character array index change
Add 3.13.0 version-history entries to at, operator[], value, patch,
patch_inplace, and unflatten, and describe in exceptions.md which array
indices throw parse_error.109 and which out_of_range.404.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
|
||
|
|
07ec1a4e31 |
Generate the docset index and pages with Python (#5799)
Replace the hand-maintained docs/docset/docSet.sql and the bash/sed Makefile recipe with docs/docset/generate_docset.py: - The search index is generated from the mkdocs.yml nav and each page's H1 and declaration. Pages documenting several entities (e.g. JSON_HAS_CPP_11..26) get one entry per name; all non-API pages become guides. New API pages no longer need a manual entry. - Page titles are set from the index names. - The docset is self-contained: the mermaid loader no longer points to https://json.nlohmann.me/assets/..., the repository widget no longer queries api.github.com, remaining remote images are downloaded, and the build fails if any remote resource load remains. - The CSS that hides the site navigation now uses Material's classes; the element selectors lost against them, so the header was shown. check_structure.py's docset check is replaced by running the generator in `make style_check`. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
d540750f21 |
Use the with_*_t aliases in the remaining tests and docs (#5790)
#5787 missed the instantiations spelled as `basic_json <` (astyle's formatting) or ending in the CustomBaseClass argument. Convert them, including the binary_t.md example pointed out in review. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
69a0c1b82c |
Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328)
* avoid allocating temporary basic_json for CBOR and MessagePack object keys Signed-off-by: alexprabhat99 <alexpbara@gmail.com> * add size() to the custom object key test type UBJSON and BJData access object keys through size() and c_str() directly, so the key type now provides both and the comment says why. Signed-off-by: alexprabhat99 <alexpbara@gmail.com> * address review: drop key size()/c_str(), test keys below the depth limit Nothing in the library calls size() or c_str() on an object key, so the test key type only keeps data(), which JSON_DIAGNOSTICS needs. The CBOR and MessagePack custom key tests now also nest objects deeper than detail::recursion_depth_limit(), so keys written by write_cbor_iterative and write_msgpack_iterative are covered as well. Signed-off-by: alexprabhat99 <alexpbara@gmail.com> --------- Signed-off-by: alexprabhat99 <alexpbara@gmail.com> |
||
|
|
d33068da73 |
Address review comments on the API stability docs and a test comment (#5784)
* Address review comments on #5775 and #5779 Allow new defaulted parameters and new default arguments in the API stability rules, mention the macro opt-in, and drop the redundant recompile advice. Describe test-diagnostics-optimized as the regression test for the fixed #5742. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Document what counts as a breaking change in the API stability rules Spell out the 3.x compatibility rules in the roadmap: new defaulted parameters, new default arguments, noexcept/constexpr, template parameters, parse and dump results, accepted input, key iteration order, iterator invalidation, implicit conversions, to_json/from_json lookup, json_sax, value_t enumerators, and documented macros, CMake options and headers. Also list std::hash values as not part of the public API, and link the macro overview from the section. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
d8dfc0d0f9 |
Fix unused-result warnings in the contains and parse_error examples (#5788)
contains(json_pointer) is marked JSON_HEDLEY_WARN_UNUSED_RESULT since #5477, and parse() has been for longer. The contains example ignored the result in two try blocks waiting for a parse_error that contains() never throws, so they printed nothing; print the result for those pointers instead. Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
3d7f554927 |
Use the with_*_t aliases in tests, examples, and docs (#5787)
* Use the with_*_t aliases in tests, examples, and docs Replace spelled-out basic_json<...> instantiations that only change one or two template parameters with nlohmann::json::with_*_t (or ordered_json::with_*_t when the object type is ordered_map). Types that change all three number types chain with_integers_t and with_float_t. The raw basic_json<...> spelling stays where the template parameter list itself is the subject: the alias tests in unit-udt.cpp, explicit instantiations, and the ordered_json/compile-time docs. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix unit-large_json for clang and JSON_DIAGNOSTICS Two test problems from #5781 broke CI on develop: CAPTURE(depth); trips clang's -Wextra-semi-stmt, and the type_error.321 messages did not account for the diagnostics path prefix. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Use static_cast in unit-hash for clang-tidy #5772 added functional casts that clang-tidy reports as C-style casts (google-readability-casting). Also append a char instead of a one-character string in unit-large_json. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Declare the expected message prefix const in unit-large_json Without JSON_DIAGNOSTICS the prefix was never modified, which clang-tidy reports (misc-const-correctness). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
ed8ba0201f |
Install CMake package config files with Meson, and add Meson options (#5587)
* Install CMake package config files with Meson, and add Meson options Squashed onto develop from: - Install CMake package config files with Meson - meson: Indent code inside an if block - meson: set a minimum Meson version - meson: use `override_dependency()` to set dependencies - meson: use `install_subdir` for headers - meson: set the C++ standard to C++11 - meson: handle single header and multiheader the same way CMake does - meson: add support for the GlobalUDLs option - meson: add support for the ImplictConversions option - Add meson information to FILES.md - Complete the Meson options and match CMake's compile definitions - Add the JSON_* definitions to the CMake pkg-config file - Document the Meson options and check them in CI - Fix the Meson CMake target for includedir or datadir outside the prefix - Avoid //include in Meson-generated CMake target for prefix / - Add DisableTupleReferenceConversion to Meson and the CMake pkg-config file - Check in CI that Meson and pkg-config offer the CMake options - Remove accidentally committed Python bytecode Co-authored-by: Dylan Baker <dylan@pnwbakers.com> Signed-off-by: Dylan Baker <dylan@pnwbakers.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add the StrictBinaryUTF8 and DeleteDeprecatedFunctions Meson options JSON_StrictBinaryUTF8 (#5741) and JSON_DeleteDeprecatedFunctions (#5755) arrived with develop but were missing from the Meson build and the pkg-config file, so check_build_options failed. Both Meson options default to false and add JSON_STRICT_BINARY_UTF8=1 and JSON_DELETE_DEPRECATED_FUNCTIONS=1 to the dependency, the pkg-config file, and the generated CMake target; CMake's pkg-config file now carries both definitions too. The ci_meson_install job sets and checks them in its non-default install. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Dylan Baker <dylan@pnwbakers.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: Dylan Baker <dylan@pnwbakers.com> |
||
|
|
a5f5d3059b |
Make std::hash<basic_json> consistent with operator== for numbers (#5772)
* Make std::hash<basic_json> consistent with operator== for numbers operator== converts between number_integer, number_unsigned, and number_float before comparing, so json(0), json(0U), and json(0.0) all compare equal. hash() folded the specific value_t into the result for each of the three numeric cases, giving each a distinct hash and breaking the standard Hash requirement that a == b implies hash(a) == hash(b). A std::unordered_set could therefore hold all three as separate elements even though they compare equal. hash() now treats all three numeric variants the same way: it converts the value to number_float_t and combines it with a single shared type tag, so any two numbers operator== considers equal hash identically regardless of which internal type actually holds them. Updated the accompanying test to check this consistency directly (including via an actual unordered_set) instead of asserting that 0, 0U, and 0.0 hash differently, since that assumption was the bug. Also corrected the function's own doc comment and the std::hash API docs, which described the old behavior as intended. Fixes #5400 Signed-off-by: Afonso Januário <afonso-januario@hotmail.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Remove now-unused number_integer_t/number_unsigned_t typedefs in hash() Merging the three numeric branches into one that only reads number_float_t left these two aliases unused, which several CI configurations treat as a build error under -Wunused-local-typedefs. Signed-off-by: Afonso Januário <afonso-januario@hotmail.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Mark the unordered_set in the hash regression test const clang-tidy's misc-const-correctness check flagged it: the set is never mutated after construction, only read via size(). Signed-off-by: Afonso Januário <afonso-januario@hotmail.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Normalize -0.0 in number hashes and test range ends operator== compares numbers exactly since #5459, so equal numbers share one value and convert to the same number_float_t. Update the comment accordingly, map -0.0 to 0.0 before hashing (std::hash need not do that), and test -0.0 and the ends of the integer ranges. Show hash(0.0) in the docs example and note the change in the version history. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Clarify hash documentation after review - Say "may hash differently" for null, false, and numbers, since a collision across types is possible. - Name the storage types (signed integer, unsigned integer, floating-point number) instead of example literals. - Explain that the hash survives converting an integer to number_float_t but not the lossy conversion back, and that unequal numbers may share a hash. - State that the example hash values are illustrative only and vary by platform, compiler, compiler version, and library version. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Afonso Januário <afonso-januario@hotmail.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: Afonso Januário <afonso-januario@hotmail.com> |
||
|
|
3c465beb61 |
Add tests for error_handler_t::keep in dump() (#4555)
Squashed onto develop from: - Add error_handler_t::keep to copy invalid UTF-8 bytes unchanged - Mention error_handler_t::keep in the README Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
069ace74af |
Round-trip BJData ND-array annotations exactly (single precision, key order) (#5707)
Squashed onto develop from: - Round-trip BJData ND-array annotations exactly (single precision, key order) Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
e4e7d657ef |
Document the API stability guarantee in the roadmap (#5775)
* Document what is not covered by the API stability guarantee Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Move the API stability guarantee to the roadmap Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Note that exceptions to the API stability rules are documented in the release notes Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
1c754cfe31 |
Copy a pair-shaped array value under JSON_BRACE_INIT_COPY_SEMANTICS (#5701)
With JSON_BRACE_INIT_COPY_SEMANTICS enabled, single-element brace
initialization from a JSON value decided whether to copy the value or
build an object by inspecting the value's runtime shape: a two-element
array whose first element is a string, such as ["key", 42], was turned
into an object instead of being copied. This made the behavior depend
on the element's content, and it did not distinguish an existing value
of this shape from a nested braced pair written in the source, such as
the inner {"key", "value"} of {{"key", "value"}}.
json_ref now records whether it was constructed from a braced list
(true only for the std::initializer_list<json_ref> constructor used
for nested braced lists) or from a value. The initializer-list
constructor uses this to copy or move a single non-braced-list element
before deciding whether the list describes an object, so a JSON value
is always copied regardless of its shape, while a braced pair written
in the source still creates an object.
Fixes #5662.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
|
||
|
|
ff6f3d7d4a |
Reject nested indefinite-length CBOR string chunks (#5766)
* fix(cbor): reject nested indefinite string chunks Signed-off-by: Joseph.Demarest <joseph@demarest.dev> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address review comments on nested indefinite-length CBOR strings Rename is_chunk to inside_indefinite, update the stale test section names, and use lowercase comments like the surrounding code. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Joseph.Demarest <joseph@demarest.dev> Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: Joseph.Demarest <joseph@demarest.dev> |
||
|
|
675e519966 |
Allow SAX parsing of tagged CBOR (#5740)
* Allow SAX parsing of tagged CBOR Signed-off-by: Tyagiquamar <mohdquamartyagi@gmail.com> * Consolidate sax_parse overloads with default tag_handler parameter Signed-off-by: Tyagiquamar <mohdquamartyagi@gmail.com> * Add version history entry for tag_handler in sax_parse documentation --------- Signed-off-by: Tyagiquamar <mohdquamartyagi@gmail.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
1a4c9dea73 |
Fix the standalone release tarball; update compiler list and CITATION (#5734)
Squashed onto develop from: - Make the json.tar.xz release archive configure standalone - Update the supported compiler list and the CITATION.cff repository link - Add json_fwd.hpp to the Bazel singleheader-json target - Document SwiftPM's #include <json.hpp> form and add CI coverage - Migrate REUSE metadata from deprecated .reuse/dep5 to REUSE.toml Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
162e13b86f |
Add with_*_t alias templates to create basic_json types with changed template parameters (#5758)
* Add helper types to make it easier to create a basic_json type with modified template parameters Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Rename with_changed_*_t aliases to with_*_t and merge integer/unsigned aliases Per review discussion on #3898 between gregmarr and nlohmann: - rename with_changed_X_t to with_X_t for brevity - replace the separate with_changed_integer_t/with_changed_unsigned_t aliases with a single with_integers_t<NumberIntegerType2, NumberUnsignedType2> - add @sa doc comment links for the upcoming documentation page Co-authored-by: Raphael Grimm <1005058+barcode@users.noreply.github.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add documentation for the with_*_t member alias templates Add docs/mkdocs/docs/api/basic_json/with_t.md documenting with_object_t, with_array_t, with_string_t, with_boolean_t, with_integers_t, with_float_t, with_allocator_t, with_json_serializer_t, with_binary_t and with_base_class_t, with an accompanying example, and link the page from the basic_json member types list and the mkdocs navigation. Co-authored-by: Raphael Grimm <1005058+barcode@users.noreply.github.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add tests for the with_*_t member alias templates Check with std::is_same that each with_*_t alias produces the expected basic_json type, and that with_string_t keeps nlohmann::ordered_map as the object type when used on ordered_json. Co-authored-by: Raphael Grimm <1005058+barcode@users.noreply.github.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix with_t nav entry and document chaining of the with_*_t aliases Indent the with_t entry in mkdocs.yml so it is listed under basic_json, explain that the aliases can be chained and work on ordered_json, and test both, including json::with_object_t<ordered_map> == ordered_json. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add docset entry for basic_json::with_t Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: barcode <barcode@example.com> Co-authored-by: Raphael Grimm <1005058+barcode@users.noreply.github.com> |
||
|
|
a7d387a762 |
Bump mkdocs-htmlproofer-plugin from 1.5.0 to 1.6.0 in /docs/mkdocs (#5771)
Bumps [mkdocs-htmlproofer-plugin](https://github.com/manuzhang/mkdocs-htmlproofer-plugin) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/manuzhang/mkdocs-htmlproofer-plugin/releases) - [Commits](https://github.com/manuzhang/mkdocs-htmlproofer-plugin/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: mkdocs-htmlproofer-plugin dependency-version: 1.6.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> |
||
|
|
d41887511b |
Bump source-map-js from 1.2.1 to 1.2.2 in /docs/mkdocs/scripts/mermaid (#5769)
Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](https://github.com/7rulnik/source-map-js/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
0490778fc3 |
Replace retired macOS 14 runner and test all available Xcode versions (#5757)
* Replace retired macOS 14 runner and test all available Xcode versions GitHub retires the macos-14 image on 2026-11-02 (brownouts from 2026-10-05). Xcode 15 is not available on any remaining hosted runner, so drop the macos-14 job and its documented compilers. Also test the Xcode versions that the images provide but CI did not use (26.1.1-26.3 on macos-15, 26.4.1-26.6 on a new macos-26 job), and pin GCC 16 explicitly next to gcc:latest. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Document new Xcode and GCC versions in the supported compilers table Versions taken from the CI logs of this PR (Xcode 26.1.1-26.6) and from the gcc:16 image (same digest as gcc:16.2.0 and gcc:latest). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
5379e04ce4 |
Throw type_error.321 when serializing discarded values to binary formats (#5761)
* Throw type_error.321 when serializing discarded values to binary formats The CBOR, MessagePack, UBJSON, BJData, and BSON writers silently skipped the payload of a value_t::discarded value nested in an array or object, while still writing its slot in the element/member count (and, for BSON, its entry header), producing a binary document whose declared size does not match what was actually written. Throw type_error.321 instead, for a discarded value anywhere in the tree, including at the top level. Rewritten from the original PR against the current (non-recursive option aside) binary_writer.hpp, which has changed substantially since this was first proposed; the out_of_range.412 MessagePack size check and unrelated test reformatting from that PR are dropped as out of scope here. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Document and test type_error.321 for discarded binary values Add docs for the new exception (home/exceptions.md and the Exceptions sections of to_cbor/to_msgpack/to_ubjson/to_bjdata/to_bson) and test coverage for a discarded value nested in an array or object, nested deeper, and (for UBJSON/BJData) inside an optimized same-type array, for each of CBOR, MessagePack, UBJSON, BJData, and BSON. Adjust the three pre-existing "discarded" tests that asserted the old silent behavior (empty/short output) to expect type_error.321 instead. Co-authored-by: ameliabarnabyhub <312084480+ameliabarnabyhub@users.noreply.github.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-authored-by: ameliabarnabyhub <ameliabarnabyhub@users.noreply.github.com> Co-authored-by: ameliabarnabyhub <312084480+ameliabarnabyhub@users.noreply.github.com> |
||
|
|
8a142bc436 |
Fix CI on develop after #5600, #5607, and #5755 (#5764)
* Fix CI on develop after #5600, #5607, and #5755 - binary_reader: cast the result of -1 - number back to number_integer_t, because a number_integer_t narrower than int is promoted to int, which GCC's -Warith-conversion rejects (ci_test_gcc, ci_test_standards_gcc) - JSON_DELETE_DEPRECATED_FUNCTIONS: declare the deleted stream operators as function templates at namespace scope, because GCC < 5 rejects deleted friend functions ("can't initialize friend function") and Clang 7-9 report a redefinition when a class template has a deleted friend function - docs: give the examples of JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS "Example:" titles and add the page to the docset (style_check) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Ignore libstdc++'s <format> sign change in the sanitizer job libstdc++ 14's <format> initializes a size_t parameter with -1 (GCC bug 119429), so every std::format call fails ci_test_clang_sanitizer under -fsanitize=integer (test-std-format_cpp20). Exclude only the implicit-integer-sign-change check and only that header via -fsanitize-ignorelist. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix the AppVeyor (MSVC 2015-2019) build - binary_reader: emit_signed/emit_unsigned pass integers that do not fit the number types to emit_float as long double, because MSVC's <cmath> has no integer overloads of std::isfinite (C2668 'fpclassify'), from #5607 - scalar comparisons: the friend operators take the JSON type for their noexcept from their parameter, because MSVC 2015/2017 take basic_json as the class template there (C3203) and MSVC 2019 16.0 does not see member types or template parameters, from #5751 - unit-conversions2: skip the !is_nothrow_constructible static_assert for std::optional on MSVC 2017, which evaluates the conditional noexcept as true (C2607), from #5754 Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Re-amalgamate Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Avoid MSVC 2015's C4800 for enums with underlying type bool MSVC 2015 warns about any conversion to bool (C4800), even with an explicit cast, so the enum conversions from #5754 (#5671) failed the AppVeyor build with /WX. Convert to bool by comparing with zero via the new detail::bool_aware_static_cast, and keep doctest from printing the enum in the test. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Skip the #5650 allocator test on MSVC 2015 debug builds MSVC 2015's debug STL constructs the containers' debug proxies through the allocator in noexcept constructors, so countdown_allocator's failing construction crashes test-allocator (SIGSEGV) instead of throwing std::bad_alloc. Use the guard #5585 uses for the same reason. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Skip deleted-function detection checks on MSVC 2015 MSVC 2015 does not treat selecting a deleted function in decltype as a substitution failure, so the detection traits in unit-delete_deprecated_functions (#5755) and the integral-key checks in unit-element_access2 (#5657) report deleted overloads as callable there. Calling them still fails to compile. Skip those checks for _MSC_VER < 1910, and use the stream operators for real in the runtime section, so MSVC 2015 still compiles them with the macro set. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Split the Visual Studio 2017 AppVeyor jobs in two The VS 2017 jobs hit AppVeyor's 60-minute limit per job while still compiling the tests (77 of about 108 test targets after 58 minutes). They pass /std:c++17 for everything anyway, so build only the C++17 variant of each test (JSON_TestStandards=17), and split the unit test files across two jobs each with the new JSON_TestShard=<index>/<count> option, which keeps every <count>-th test file starting at <index>. The extra variants of single test files are built in shard 0 only. CMAKE_OPTIONS is no longer quoted in appveyor.yml, so that it can hold more than one option. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix std::terminate when converting std::optional with MSVC 2017 MSVC 2017 evaluates std::is_nothrow_assignable<json&, const T&> as true even if T's to_json throws, so to_json(json&, const std::optional<T>&) was noexcept there and the exception from #5642's test called std::terminate instead of propagating. Make that conversion never noexcept on MSVC 2017; all other compilers keep the exact condition. The static_asserts on the condition are skipped for MSVC 2017; the runtime check that the exception propagates still runs there. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |
||
|
|
23d3b373e1 |
Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions (#5755)
* Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions Defining JSON_DELETE_DEPRECATED_FUNCTIONS to 1 (or the CMake option JSON_DeleteDeprecatedFunctions) declares every deprecated function as deleted instead of deprecated, so that code that is not ready for 4.0.0 no longer compiles. A deleted function still takes part in overload resolution, so from_*(ptr, len) cannot silently bind len to the strict parameter of from_*(InputType&&, bool); the roadmap now plans to keep these overloads deleted in 4.0.0 instead of removing them. The legacy discarded-value comparison is left to its own macro. Also update the 4.0 roadmap: add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION and JSON_DELETE_DEPRECATED_FUNCTIONS to the macro table, add the from_bjdata/from_bon8 (ptr, len) overloads to the deprecated functions, document the macro in the migration guide, and fix the docs style check findings (example titles, missing docset entry for JSON_STRICT_BINARY_UTF8). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Declare each deprecated function once and guard only its body Instead of repeating every deprecated declaration in an #if JSON_DELETE_DEPRECATED_FUNCTIONS branch, keep one declaration (with its deprecation attribute) and switch only between "= delete;" and the function body. Suggested by @gregmarr in the review. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me> |