diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 5b9e3fd53..000000000 --- a/.clang-format +++ /dev/null @@ -1,84 +0,0 @@ -#AccessModifierOffset: 2 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -#AlignConsecutiveBitFields: false -AlignConsecutiveDeclarations: false -AlignConsecutiveMacros: false -AlignEscapedNewlines: Right -#AlignOperands: AlignAfterOperator -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Empty -AllowShortCaseLabelsOnASingleLine: false -#AllowShortEnumsOnASingleLine: true -AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: Empty -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: false -BinPackParameters: false -#BitFieldColonSpacing: Both -BreakBeforeBraces: Custom # or Allman -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: Always - AfterEnum: true - AfterFunction: true - AfterNamespace: false - AfterStruct: true - AfterUnion: true - AfterExternBlock: false - BeforeCatch: true - BeforeElse: true - #BeforeLambdaBody: false - #BeforeWhile: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeComma -BreakStringLiterals: false -ColumnLimit: 0 -CompactNamespaces: false -ConstructorInitializerIndentWidth: 2 -Cpp11BracedListStyle: true -PointerAlignment: Left -FixNamespaceComments: true -IncludeBlocks: Preserve -#IndentCaseBlocks: false -IndentCaseLabels: true -IndentGotoLabels: false -IndentPPDirectives: BeforeHash -IndentWidth: 4 -KeepEmptyLinesAtTheStartOfBlocks: false -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ReflowComments: false -SortIncludes: true -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: c++11 -TabWidth: 4 -UseTab: Never diff --git a/.clang-tidy b/.clang-tidy index 339360b08..c3a1244c3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,10 +1,19 @@ +# TODO: The first three checks are only removed to get the CI going. They have to be addressed at some point. + Checks: '*, + + -portability-template-virtual-member-function, + -bugprone-use-after-move, + -hicpp-invalid-access-moved, + -altera-id-dependent-backward-branch, -altera-struct-pack-align, -altera-unroll-loops, -android-cloexec-fopen, + -boost-use-ranges, -bugprone-easily-swappable-parameters, -cert-err58-cpp, + -clang-analyzer-webkit.NoUncountedMemberChecker, -concurrency-mt-unsafe, -cppcoreguidelines-avoid-const-or-ref-data-members, -cppcoreguidelines-avoid-do-while, @@ -44,7 +53,10 @@ Checks: '*, -modernize-concat-nested-namespaces, -modernize-type-traits, -modernize-use-constraints, + -modernize-use-designated-initializers, -modernize-use-nodiscard, + -modernize-use-ranges, + -modernize-use-std-numbers, -modernize-use-trailing-return-type, -performance-enum-size, -readability-function-cognitive-complexity, diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 770b8173e..30eb5784c 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -2,45 +2,131 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mail@nlohmann.me. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[mail@nlohmann.me](mailto:mail@nlohmann.me). +All complaints will be reviewed and investigated promptly and fairly. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4d33c67bf..ad9820fcb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,71 +1,222 @@ -[![Issue Stats](http://issuestats.com/github/nlohmann/json/badge/pr?style=flat)](http://issuestats.com/github/nlohmann/json) [![Issue Stats](http://issuestats.com/github/nlohmann/json/badge/issue?style=flat)](http://issuestats.com/github/nlohmann/json) +# Contribution Guidelines -# How to contribute +Thank you for your interest in contributing to this project! What began as an exercise to explore the exciting features +of C++11 has evolved into a [widely-used](https://json.nlohmann.me/home/customers/) JSON library. I truly appreciate all +the contributions from the community, whether it's proposing features, identifying bugs, or fixing mistakes! To ensure +that our collaboration is efficient and effective, please follow these guidelines. -This project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers. +Feel free to discuss or suggest improvements to this document +[by submitting a pull request](https://github.com/nlohmann/json/edit/develop/.github/CONTRIBUTING.md). -To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new/choose) or a pull request if you find a way to improve it! +## Ways to Contribute -## Private reports +There are multiple ways to contribute. -Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to . +### Reporting an issue -## Prerequisites - -Please [create an issue](https://github.com/nlohmann/json/issues/new/choose), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. - -## Describe your issue +Please [create an issue](https://github.com/nlohmann/json/issues/new/choose), assuming one does not already exist, and +describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. Clearly describe the issue: -- If it is a bug, please describe how to **reproduce** it. If possible, attach a complete example which demonstrates the error. Please also state what you **expected** to happen instead of the error. -- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it. -- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket. +- If it is a bug, please describe how to **reproduce** it. If possible, attach a _complete example_ which demonstrates + the error. Please also state what you **expected** to happen instead of the error. +- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use + it. +- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste + the (relevant part of) the error messages to the ticket. -Please stick to the provided issue template ([bug report](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/bug.yml) if possible. For questions, feature or support requests, please [open a discussion](https://github.com/nlohmann/json/discussions/new). +Please stick to the provided issue template +[bug report](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/bug.yaml) if possible. -## Files to change +### Reporting a security vulnerability -:exclamation: Before you make any changes, note the single-header files [`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) and [`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp) are **generated** from the source files in the [`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). Please **do not** edit the files `single_include/nlohmann/json.hpp` and `single_include/nlohmann/json_fwd.hpp` directly, but change the `include/nlohmann` sources and regenerate the files by executing `make amalgamate`. +You can report a security vulnerability according to our +[security policy](https://github.com/nlohmann/json/security/policy). -To make changes, you need to edit the following files: +### Discussing a new feature -1. [`include/nlohmann/*`](https://github.com/nlohmann/json/tree/develop/include/nlohmann) - These files are the sources of the library. Before testing or creating a pull request, execute `make amalgamate` to regenerate `single_include/nlohmann/json.hpp` and `single_include/nlohmann/json_fwd.hpp`. +For questions, feature or support requests, please +[open a discussion](https://github.com/nlohmann/json/discussions/new). If you find a proposed answer satisfactory, +please use the "Mark as answer" button to make it easier for readers to see what helped and for the community to filter +for open questions. -2. [`tests/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/tests/src) - These files contain the [doctest](https://github.com/onqtam/doctest) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code. Before creating a pull request, execute `make pretty` to make sure that the style is correct, as this will be checked by the CI. +### Proposing a fix or an improvement - If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with +Join an ongoing discussion or comment on an existing issue before starting to code. This can help to avoid duplicate +efforts or other frustration during the later review. - ```sh - $ mkdir build - $ cd build - $ cmake .. - $ cmake --build . - $ ctest - ``` +Create a [pull request](https://github.com/nlohmann/json/pulls?q=sort%3Aupdated-desc+is%3Apr+is%3Aopen) against the +`develop` branch and follow the pull request template. In particular, - The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you open a pull request. +- describe the changes in detail, both the what and why, +- reference existing issues where applicable, +- add tests to maintain 100% test coverage, +- update the documentation as needed, and +- ensure the source code is amalgamated. +We describe all points in detail below. -## Note +All contributions (including pull requests) must agree to the +[Developer Certificate of Origin (DCO) version 1.1](https://developercertificate.org). This is exactly the same one +created and used by the Linux kernel developers and posted on http://developercertificate.org/. This is a developer's +certification that he or she has the right to submit the patch for inclusion into the project. -- If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind. -- There is a Makefile target `make pretty` which runs [Artistic Style](http://astyle.sourceforge.net) to fix indentation. If possible, run it before opening the pull request. Otherwise, we shall run it afterward. +## How to... -## Please don't +### Describe your changes -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. -- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for this kind of bug). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. -- Please refrain from proposing changes that would **break [JSON](https://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - - We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments. - - We do not preserve the **insertion order of object elements**. The [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". To this end, this library does not preserve insertion order of name/value pairs. (In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default.) Note this behavior conforms to the standard, and we shall not change it to any other order. If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map). +This library is primarily maintained as a spare-time project. As such, I can not make any guarantee how quickly changes +are merged and released. Therefore, it is very important to make the review as smooth as possible by explaining not only +_what_ you changed, but _why_. This rationale can be very valuable down the road when improvements or bugs are discussed +years later. -- Please do not open pull requests that address **multiple issues**. +### Reference existing issues + +[Link a pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue) +to clarify that a fix is forthcoming and which issue can be closed after merging. Only few cases (e.g., fixing typos) +don’t require prior discussions. + +### Write tests + +The library has an extensive test suite that currently covers [100 %](https://coveralls.io/github/nlohmann/json) of the +library's code. These test are crucial to maintain API stability and give future contributors confidence that they do +not accidentally break things. As Titus Winters aptly put it: + +> If you liked it, you should have put a test on it. + +#### Run the tests + +First, ensure the test suite runs before making any changes: + +```sh +$ cmake -S. -B build +$ cmake --build build -j 10 +$ ctest --test-dir build -j 10 +``` + +The test suite should report: + +``` +100% tests passed, 0 tests failed out of 98 +``` + +#### Add tests + +The tests are located in [`tests/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/tests/src) and contain +[doctest assertions](https://github.com/doctest/doctest/blob/master/doc/markdown/assertions.md) like `CHECK`. The tests +are structured along the features of the library or the nature of the tests. Usually, it should be clear from the +context which existing file needs to be extended, and only very few cases require creating new test files. + +When fixing a bug, edit `unit-regression2.cpp` and add a section referencing the fixed issue. + +#### Exceptions + +When you test exceptions, please use `CHECK_THROWS_WITH_AS` which also takes the `what()` argument of the thrown +exception into account. + +#### Coverage + +If test coverage decreases, an automatic warning comment will be posted on the pull request. You can access a code +coverage report as artifact to the “Ubuntu” workflow. + +### Update the documentation + +The [main documentation](https://json.nlohmann.me) of the library is generated from the files +[`docs/mkdocs/docs`](https://github.com/nlohmann/json/blob/develop/docs/mkdocs/docs). This folder contains dedicated +pages for [certain features](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/features), a list of +[all exceptions](https://github.com/nlohmann/json/blob/develop/docs/mkdocs/docs/home/exceptions.md), and an +[extensive API documentation](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/api) with details on every +public API function. + +Build the documentation locally using: + +```shell +make install_venv -C docs/mkdocs +make serve -C docs/mkdocs +``` + +The documentation will then available at . See the documentation of +[mkdocs](https://www.mkdocs.org) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) for more +information. + +### Amalgamate the source code + +The single-header files +[`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) and +[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp) +are **generated** from the source files in the +[`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). **Do not** edit the +files directly; instead, modify the include/nlohmann sources and regenerate the files by executing: + +```shell +make amalgamate +``` + +## Recommended documentation + +- The library’s [README file](https://github.com/nlohmann/json/blob/master/README.md) is an excellent starting point to + understand its functionality. +- The [documentation page](https://json.nlohmann.me) is the reference documentation of the library. +- [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) is the reference for the JavaScript Object Notation (JSON) + Data Interchange Format. + +## Please don't... + +Certain contributions are not helpful. + +### Break the public API + +We take pride in the library being used by +[numerous customers across various industries](https://json.nlohmann.me/home/customers/). They all rely on the +guarantees provided by [semantic versioning](https://semver.org). Please do not change the library such that the public +API of the 3.x.y version is broken. This includes: + +- Changing function signatures (altering parameter types, return types, number of parameters) or changing the const-ness + of member functions. +- Removing functions. +- Renaming functions or classes. +- Changing exception handling. +- Changing exception ids. +- Changing access specifiers. +- Changing default arguments. + +Although these guidelines may seem restrictive, they are essential for maintaining the library’s utility. + +Breaking changes may be introduced when they are guarded with a feature macro such as +[`JSON_USE_IMPLICIT_CONVERSIONS`](https://json.nlohmann.me/api/macros/json_use_implicit_conversions/) which allows to +selectively change the behavior of the library. In next steps, the current behavior can then be deprecated. Using +feature macros then allows users to test their code against the library in the next major release. + +### Break C++11 language conformance + +This library is designed to work with C++11 and later. This means that any +[supported C++11 compiler](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers) should compile +the library without problems. Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual +Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. + +Please do not add features that do not work with the mentioned supported compilers. Please guard features from C++14 and +later against the respective [`JSON_HAS_CPP_14`](https://json.nlohmann.me/api/macros/json_has_cpp_11/) macros. + +### Break JSON conformance + +Please refrain from proposing changes that would **break [JSON](https://datatracker.ietf.org/doc/html/rfc8259) +conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this +extension. ## Wanted -The following areas really need contribution: +The following areas really need contribution and are always welcomed: -- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the bleeding-edge versions Clang. -- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser with hand coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for parsing. -- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency is not everything, speed and memory consumption are very important characteristics for C++ developers, so having proper comparisons would be interesting. +- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the + bleeding-edge versions Clang. +- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser + with hand coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That + said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep + the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for + parsing. +- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency + is not everything, speed and memory consumption are very important characteristics for C++ developers, so having + proper comparisons would be interesting. + +We look forward to your contributions and collaboration to enhance the library! diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a6c972e81..27bd6810a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ github: nlohmann -custom: http://paypal.me/nlohmann +custom: https://paypal.me/nlohmann diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index f7acdf18b..82d90da5d 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -13,7 +13,7 @@ body: Note that this form is for bug reports only. Please [open a discussion](https://github.com/nlohmann/json/discussions/new) - for questions, feature requests, or support requests + for questions, feature requests, or support requests. - type: textarea id: summary attributes: @@ -76,7 +76,7 @@ body: label: Library version description: > Which version of the library did you use? If it is a released version, - please enter the version number (e.g., 3.11.3). Otherwise, please enter + please enter the version number (e.g., 3.12.0). Otherwise, please enter the commit hash. If you got the library from another source as the GitHub repository (e.g., via a package manager), please also state this. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c9c7cb793..4bb90e753 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,19 +1,9 @@ [Describe your pull request here. Please read the text below the line, and make sure you follow the checklist.] -* * * - -## Pull request checklist +- [ ] The changes are described in detail, both the what and why. +- [ ] If applicable, an [existing issue](https://github.com/nlohmann/json/issues) is referenced. +- [ ] The [Code coverage](https://coveralls.io/github/nlohmann/json) remained at 100%. A test case for every new line of code. +- [ ] If applicable, the [documentation](https://json.nlohmann.me) is updated. +- [ ] The source code is amalgamated by running `make amalgamate`. Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md) for detailed information. - -- [ ] Changes are described in the pull request, or an [existing issue is referenced](https://github.com/nlohmann/json/issues). -- [ ] The test suite [compiles and runs](https://github.com/nlohmann/json/blob/develop/README.md#execute-unit-tests) without error. -- [ ] [Code coverage](https://coveralls.io/github/nlohmann/json) is 100%. Test cases can be added by editing the [test suite](https://github.com/nlohmann/json/tree/develop/test/src). -- [ ] The source code is amalgamated; that is, after making changes to the sources in the `include/nlohmann` directory, run `make amalgamate` to create the single-header files `single_include/nlohmann/json.hpp` and `single_include/nlohmann/json_fwd.hpp`. The whole process is described [here](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#files-to-change). - -## Please don't - -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. -- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for this kind of bug). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. -- Please refrain from proposing changes that would **break [JSON](https://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. -- Please do not open pull requests that address **multiple issues**. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 4d010ebda..ea7e8810f 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -2,4 +2,24 @@ ## Reporting a Vulnerability -Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to . You can use [this key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69) for encryption. +We value the security of our users and appreciate your efforts to responsibly disclose vulnerabilities. If you have +identified a security vulnerability in this repository, please use the GitHub Security Advisory +["Report a Vulnerability"](https://github.com/nlohmann/json/security/advisories/new) tab. + +Until it is published, this draft security advisory will only be visible to the maintainers of this project. Other +users and teams may be added once the advisory is created. + +We will send a response indicating the next steps in handling your report. After the initial reply to your report, we +will keep you informed of the progress towards a fix and full announcement and may ask for additional information or +guidance. + +For vulnerabilities in third-party dependencies or modules, please report them directly to the respective maintainers. + +## Additional Resources + +- Explore security-related topics and contribute to tools and projects through + [GitHub Security Lab](https://securitylab.github.com/). +- Learn more about responsible disclosure and reporting vulnerabilities in GitHub at + [About coordinated disclosure of security vulnerabilities](https://docs.github.com/en/code-security/repository-security-advisories/about-coordinated-disclosure-of-security-vulnerabilities). + +We sincerely thank you for contributing to the security and integrity of this project! diff --git a/.github/config.yml b/.github/config.yml index 7a8f41e6d..4e3217479 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -6,7 +6,7 @@ sentimentBotToxicityThreshold: .7 # *Required* Comment to reply with sentimentBotReplyComment: > - Please be sure to review the [code of conduct](https://github.com/nlohmann/json/blob/develop/CODE_OF_CONDUCT.md) and be respectful of other users. cc/ @nlohmann + Please be sure to review the [code of conduct](https://github.com/nlohmann/json/blob/develop/.github/CODE_OF_CONDUCT.md) and be respectful of other users. cc/ @nlohmann # Configuration for request-info - https://github.com/behaviorbot/request-info @@ -17,3 +17,6 @@ requestInfoReplyComment: > # *OPTIONAL* Label to be added to Issues and Pull Requests with insufficient information given requestInfoLabelToAdd: "state: needs more info" + +checkIssueTemplate: true +checkPullRequestTemplate: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..d517ed984 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: pip + directory: /docs/mkdocs + schedule: + interval: daily + + - package-ecosystem: pip + directory: /tools/astyle + schedule: + interval: daily + + - package-ecosystem: pip + directory: /tools/generate_natvis + schedule: + interval: daily + + - package-ecosystem: pip + directory: /tools/serve_header + schedule: + interval: daily + + - package-ecosystem: pip + directory: /cmake/requirements + schedule: + interval: daily diff --git a/.github/external_ci/appveyor.yml b/.github/external_ci/appveyor.yml index 126ed99b3..5c6b47a34 100644 --- a/.github/external_ci/appveyor.yml +++ b/.github/external_ci/appveyor.yml @@ -41,7 +41,7 @@ environment: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 configuration: Release platform: x86 - CXX_FLAGS: "/permissive- /std:c++latest /utf-8 /W4 /WX" + CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX" CMAKE_OPTIONS: "" GENERATOR: Visual Studio 15 2017 @@ -62,7 +62,7 @@ environment: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 configuration: Release platform: x64 - CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /W4 /WX" + CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX" CMAKE_OPTIONS: "" GENERATOR: Visual Studio 15 2017 diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index d30c78be7..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 30 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: "state: stale" -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/.github/workflows/check_amalgamation.yml b/.github/workflows/check_amalgamation.yml index 0fadb5206..906a5c5b7 100644 --- a/.github/workflows/check_amalgamation.yml +++ b/.github/workflows/check_amalgamation.yml @@ -3,18 +3,24 @@ name: "Check amalgamation" on: pull_request: -permissions: read-all +permissions: + contents: read jobs: save: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + - name: Save PR number run: | mkdir -p ./pr echo ${{ github.event.number }} > ./pr/number echo ${{ github.event.pull_request.user.login }} > ./pr/author - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pr path: pr/ @@ -25,29 +31,29 @@ jobs: MAIN_DIR: ${{ github.workspace }}/main INCLUDE_DIR: ${{ github.workspace }}/main/single_include/nlohmann TOOL_DIR: ${{ github.workspace }}/tools/tools/amalgamate - ASTYLE_FLAGS: > - --style=allman --indent=spaces=4 --indent-modifiers --indent-switches --indent-preproc-block - --indent-preproc-define --indent-col1-comments --pad-oper --pad-header --align-pointer=type - --align-reference=type --add-brackets --convert-tabs --close-templates --lineend=linux --preserve-date - --formatted steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + - name: Checkout pull request - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: main ref: ${{ github.event.pull_request.head.sha }} - name: Checkout tools - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: tools ref: develop - name: Install astyle run: | - sudo apt-get update - sudo apt-get install astyle + python3 -mvenv venv + venv/bin/pip3 install -r $MAIN_DIR/tools/astyle/requirements.txt - name: Check amalgamation run: | @@ -60,11 +66,11 @@ jobs: python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s . python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s . echo "Format (1)" - astyle $ASTYLE_FLAGS --suffix=none --quiet $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp + ${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp diff $INCLUDE_DIR/json.hpp~ $INCLUDE_DIR/json.hpp diff $INCLUDE_DIR/json_fwd.hpp~ $INCLUDE_DIR/json_fwd.hpp - astyle $ASTYLE_FLAGS $(find docs/examples include tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort) + ${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=orig $(find docs/examples include tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort) echo Check find $MAIN_DIR -name '*.orig' -exec false {} \+ diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 0fd355bce..256d4986d 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -8,22 +8,27 @@ jobs: Fuzzing: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + - name: Build Fuzzers id: build - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@57fe4475324c5506adbfecdcdd2917f65c86ee9e # master with: oss-fuzz-project-name: 'json' dry-run: false language: c++ - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@57fe4475324c5506adbfecdcdd2917f65c86ee9e # master with: oss-fuzz-project-name: 'json' fuzz-seconds: 300 dry-run: false language: c++ - name: Upload Crash - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 93923a182..b7af3212b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -11,13 +11,13 @@ on: - cron: '0 19 * * 1' workflow_dispatch: -permissions: - contents: read - concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: CodeQL-Build: @@ -26,19 +26,24 @@ jobs: security-events: write steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14 with: languages: c-cpp # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14 diff --git a/.github/workflows/comment_check_amalgamation.yml b/.github/workflows/comment_check_amalgamation.yml index 2ab5ebb97..4308ed10e 100644 --- a/.github/workflows/comment_check_amalgamation.yml +++ b/.github/workflows/comment_check_amalgamation.yml @@ -5,7 +5,8 @@ on: types: - completed -permissions: {} +permissions: + contents: read jobs: comment: @@ -17,8 +18,13 @@ jobs: issues: read pull-requests: write steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + - name: 'Download artifact' - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6.4.0 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -40,7 +46,7 @@ jobs: - run: unzip pr.zip - name: 'Comment on PR' - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975 # v6.4.0 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 000000000..70f08cee3 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,27 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - name: 'Checkout Repository' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: 'Dependency Review' + uses: actions/dependency-review-action@ce3cf9537a52e8119d91fd484ab5b8a807627bf8 # v4.6.0 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 11925e1af..a71bd0f49 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -4,7 +4,8 @@ on: pull_request_target: types: [opened, synchronize] -permissions: {} +permissions: + contents: read jobs: label: @@ -15,6 +16,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: srvaroa/labeler@master + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: srvaroa/labeler@e216fb40e2e6d3b17d90fb1d950f98bee92f65ce # master env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 9ac1fe3fa..dc99a2dde 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -9,24 +9,60 @@ on: pull_request: workflow_dispatch: -permissions: - contents: read - concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: - xcode_1: - runs-on: macos-11 +# macos-11 is deprecated +# macos-11: +# runs-on: macos-11 +# strategy: +# matrix: +# xcode: ['11.7', '12.4', '12.5.1', '13.0'] +# env: +# DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer +# +# steps: +# - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 +# - name: Run CMake +# run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON +# - name: Build +# run: cmake --build build --parallel 10 +# - name: Test +# run: cd build ; ctest -j 10 --output-on-failure + +# macos-12 is deprecated (https://github.com/actions/runner-images/issues/10721) +# macos-12: +# runs-on: macos-12 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md +# strategy: +# matrix: +# xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1'] +# env: +# DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer +# +# steps: +# - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 +# - name: Run CMake +# run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON +# - name: Build +# run: cmake --build build --parallel 10 +# - name: Test +# run: cd build ; ctest -j 10 --output-on-failure + + macos-13: + runs-on: macos-13 # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md strategy: matrix: - xcode: ['11.7', '12.4', '12.5.1', '13.0'] + xcode: ['14.1', '14.2', '14.3', '14.3.1', '15.0.1', '15.1', '15.2'] env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON - name: Build @@ -34,16 +70,33 @@ jobs: - name: Test run: cd build ; ctest -j 10 --output-on-failure - xcode_2: - runs-on: macos-12 + macos-14: + runs-on: macos-14 # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md strategy: matrix: - xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1'] + xcode: ['15.3', '15.4'] env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Run CMake + run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON + - name: Build + run: cmake --build build --parallel 10 + - name: Test + run: cd build ; ctest -j 10 --output-on-failure + + macos-15: + runs-on: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md + strategy: + matrix: + xcode: ['16.0', '16.1', '16.2'] + env: + DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON - name: Build @@ -55,10 +108,10 @@ jobs: runs-on: macos-latest strategy: matrix: - standard: [11, 14, 17, 20, 23] + standard: [11, 14, 17, 20, 23, 26] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_TestStandards=${{ matrix.standard }} - name: Build diff --git a/.github/workflows/publish_documentation.yml b/.github/workflows/publish_documentation.yml index 5a32d13a4..c0e85ab10 100644 --- a/.github/workflows/publish_documentation.yml +++ b/.github/workflows/publish_documentation.yml @@ -10,23 +10,28 @@ on: - docs/examples/** workflow_dispatch: -permissions: - contents: read - # we don't want to have concurrent jobs, and we don't want to cancel running jobs to avoid broken publications concurrency: group: documentation cancel-in-progress: false +permissions: + contents: read + jobs: publish_documentation: + permissions: + contents: write + if: github.repository == 'nlohmann/json' runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit - - name: Install and update PlantUML - run: sudo apt-get update ; sudo apt-get install -y plantuml + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install virtual environment run: make install_venv -C docs/mkdocs @@ -35,7 +40,7 @@ jobs: run: make build -C docs/mkdocs - name: Deploy documentation - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs/mkdocs/site diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 000000000..a95e5fa85 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,81 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["develop"] + +permissions: + contents: read + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + # To allow GraphQL ListCommits to work + issues: read + pull-requests: read + # To detect SAST tools + checks: read + + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - name: "Checkout code" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14 + with: + sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..f00a973d7 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,34 @@ +name: 'Comment and close stale issues and PR' +on: + schedule: + - cron: '0 0 * * *' + +permissions: + contents: read + +jobs: + stale: + runs-on: ubuntu-latest + + permissions: + issues: write + pull-requests: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + with: + stale-issue-label: 'state: stale' + stale-pr-label: 'state: stale' + exempt-issue-labels: 'pinned,security' + stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days without activity. If this issue is still relevant, please add a comment or remove the "stale" label. Otherwise, it will be closed in 10 days. Thank you for helping us prioritize our work!' + stale-pr-message: 'This pull request has been marked as stale because it has had no activity for 30 days. While we won’t close it automatically, we encourage you to update or comment if it is still relevant. Keeping pull requests active and up-to-date helps us review and merge changes more efficiently. Thank you for your contributions!' + close-issue-message: 'This issue has been closed after being marked as stale for 10 days without any further activity. If this was done in error or the issue is still relevant, please feel free to reopen it or create a new issue. We appreciate your understanding and contributions.' + days-before-stale: 90 + days-before-pr-stale: 30 + days-before-close: 10 + days-before-pr-close: -1 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 35fb9573c..87d0d7996 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -8,7 +8,7 @@ on: - release/* pull_request: workflow_dispatch: - + permissions: contents: read @@ -17,52 +17,44 @@ concurrency: cancel-in-progress: true jobs: - ci_test_clang: - runs-on: ubuntu-latest - container: silkeh/clang:dev - steps: - - name: Install git and unzip - run: apt-get update ; apt-get install -y git unzip - - uses: actions/checkout@v3 - - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 - - name: Run CMake - run: cmake -S . -B build -DJSON_CI=On - - name: Build - run: cmake --build build --target ci_test_clang - ci_test_gcc: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.4.0 + container: gcc:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build run: cmake --build build --target ci_test_gcc - ci_static_analysis: + ci_infer: runs-on: ubuntu-latest container: ghcr.io/nlohmann/json-ci:v2.4.0 - strategy: - matrix: - target: [ci_cppcheck, ci_test_valgrind, ci_test_amalgamation, ci_test_single_header, ci_single_binaries, ci_infer] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build - run: cmake --build build --target ${{ matrix.target }} + run: cmake --build build --target ci_infer ci_static_analysis_ubuntu: runs-on: ubuntu-latest strategy: matrix: - target: [ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata] + target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind] steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - name: Install Valgrind + run: sudo apt-get update ; sudo apt-get install -y valgrind + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -73,13 +65,13 @@ jobs: container: silkeh/clang:dev strategy: matrix: - target: [ci_clang_tidy, ci_test_clang_sanitizer, ci_clang_analyze] + target: [ci_test_clang, ci_clang_tidy, ci_test_clang_sanitizer, ci_clang_analyze, ci_single_binaries] steps: - - name: Install git, clang-tools, and unzip - run: apt-get update ; apt-get install -y git clang-tools unzip - - uses: actions/checkout@v3 + - name: Install git, clang-tools, iwyu (ci_single_binaries), and unzip + run: apt-get update ; apt-get install -y git clang-tools iwyu unzip + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -90,13 +82,13 @@ jobs: container: ubuntu:focal strategy: matrix: - target: [ci_cmake_flags, ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls] + target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls] steps: - name: Install build-essential - run: apt-get update ; apt-get install -y build-essential unzip wget git - - uses: actions/checkout@v3 + run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -104,37 +96,59 @@ jobs: ci_test_coverage: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.4.0 - permissions: - contents: read - checks: write steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Install dependencies and de_DE locale + run: | + sudo apt-get clean + sudo apt-get update + sudo apt-get install -y build-essential cmake lcov ninja-build make locales gcc-multilib g++-multilib + sudo locale-gen de_DE + sudo update-locale - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build run: cmake --build build --target ci_test_coverage - name: Archive coverage report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: code-coverage-report path: ${{ github.workspace }}/build/html - name: Publish report to Coveralls - uses: coverallsapp/github-action@master + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ${{ github.workspace }}/build/json.info.filtered.noexcept + ci_test_compilers_gcc_old: + runs-on: ubuntu-latest + strategy: + matrix: + compiler: ['4.8', '4.9', '5', '6'] + container: ghcr.io/nlohmann/json-ci:v2.4.0 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Run CMake + run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_compiler_g++-${{ matrix.compiler }} + ci_test_compilers_gcc: runs-on: ubuntu-latest strategy: matrix: - compiler: ['4', '5', '6', '7', '8', '9', '10', '11', '12', 'latest'] + # older GCC docker images (4, 5, 6) fail to check out code + compiler: ['7', '8', '9', '10', '11', '12', '13', '14', 'latest'] container: gcc:${{ matrix.compiler }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -144,14 +158,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - compiler: ['3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', 'latest'] + compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest'] container: silkeh/clang:${{ matrix.compiler }} steps: - name: Install unzip and git run: apt-get update ; apt-get install -y unzip git - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10 run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV" if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }} @@ -160,27 +174,16 @@ jobs: - name: Build run: cmake --build build --target ci_test_compiler_default - ci_test_compilers: - runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.4.0 - strategy: - matrix: - compiler: [g++-4.8] - steps: - - uses: actions/checkout@v3 - - name: Run CMake - run: cmake -S . -B build -DJSON_CI=On - - name: Build - run: cmake --build build --target ci_test_compiler_${{ matrix.compiler }} - ci_test_standards_gcc: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.4.0 + container: gcc:latest strategy: matrix: - standard: [11, 14, 17, 20, 23] + standard: [11, 14, 17, 20, 23, 26] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -191,23 +194,28 @@ jobs: container: silkeh/clang:latest strategy: matrix: - standard: [11, 14, 17, 20, 23] + standard: [11, 14, 17, 20, 23, 26] + stdlib: [libcxx, libstdcxx] steps: - name: Install git and unzip run: apt-get update ; apt-get install -y git unzip - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get latest CMake and ninja - uses: lukka/get-cmake@v3.27.7 + uses: lukka/get-cmake@28983e0d3955dba2bb0a6810caae0c6cf268ec0c # v4.0.0 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - - name: Build + - name: Build with libc++ + run: cmake --build build --target ci_test_clang_libcxx_cxx${{ matrix.standard }} + if: ${{ matrix.stdlib == 'libcxx' }} + - name: Build with libstdc++ run: cmake --build build --target ci_test_clang_cxx${{ matrix.standard }} + if: ${{ matrix.stdlib == 'libstdcxx' }} ci_cuda_example: runs-on: ubuntu-latest container: ghcr.io/nlohmann/json-ci:v2.4.0 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -217,7 +225,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/nlohmann/json-ci:v2.2.0 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -225,23 +233,18 @@ jobs: . /opt/intel/oneapi/setvars.sh cmake --build build --target ci_icpc - ci_reuse_compliance: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - - name: Install REUSE tool - run: python -m pip install reuse - - name: Run REUSE lint - run: reuse lint - ci_test_documentation: runs-on: ubuntu-latest strategy: matrix: - target: [ci_test_examples, ci_test_api_documentation] + target: [ci_test_examples, ci_test_build_documentation] steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 7ddd4be25..4e21d995d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -24,9 +24,9 @@ jobs: architecture: [x64, x86] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up MinGW - uses: egor-tensin/setup-mingw@v2 + uses: egor-tensin/setup-mingw@84c781b557efd538dec66bde06988d81cd3138cf # v2.2.0 with: platform: ${{ matrix.architecture }} version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14 @@ -45,7 +45,7 @@ jobs: architecture: [Win32, x64] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX" if: matrix.build_type == 'Release' @@ -61,7 +61,7 @@ jobs: runs-on: windows-2019 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -G "Visual Studio 16 2019" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX" - name: Build @@ -77,7 +77,7 @@ jobs: architecture: [Win32, x64] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -G "Visual Studio 17 2022" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX" if: matrix.build_type == 'Release' @@ -93,7 +93,7 @@ jobs: runs-on: windows-2022 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -G "Visual Studio 17 2022" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX" - name: Build @@ -108,7 +108,7 @@ jobs: version: [11, 12, 13, 14, 15] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Clang run: curl -fsSL -o LLVM${{ matrix.version }}.exe https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ matrix.version }}.0.0/LLVM-${{ matrix.version }}.0.0-win64.exe ; 7z x LLVM${{ matrix.version }}.exe -y -o"C:/Program Files/LLVM" - name: Run CMake @@ -125,7 +125,7 @@ jobs: architecture: [Win32, x64] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run CMake run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -T ClangCL -DJSON_BuildTests=On - name: Build diff --git a/.gitignore b/.gitignore index bfd52b4c6..03fe8147e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,6 @@ *.gcda .DS_Store -.wsjcpp-logs/* -.wsjcpp/* - /.idea /cmake-build-* @@ -26,12 +23,11 @@ /tests/parse_*_fuzzer # documentation -/docs/docset/docSet.dsidx /docs/docset/JSON_for_Modern_C++.docset/ /docs/docset/JSON_for_Modern_C++.tgz +/docs/docset/docSet.dsidx +/docs/mkdocs/.cache/ /docs/mkdocs/docs/__pycache__/ -/docs/mkdocs/docs/examples/ -/docs/mkdocs/docs/images/json.gif /docs/mkdocs/site/ /docs/mkdocs/venv/ @@ -41,4 +37,11 @@ /serve_header.yml # Swift Package Manager build directory -/.build \ No newline at end of file +/.build + +venv + +nlohmann_json.spdx + +# Bazel-related +MODULE.bazel.lock diff --git a/.lgtm.yml b/.lgtm.yml deleted file mode 100644 index b62f9fb37..000000000 --- a/.lgtm.yml +++ /dev/null @@ -1,4 +0,0 @@ -path_classifiers: - thirdparty: - - /tools/amalgamate - - /tools/cpplint diff --git a/.reuse/README.md b/.reuse/README.md deleted file mode 100644 index 29c2b67a1..000000000 --- a/.reuse/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# REUSE Software - -This directory contains supporting files to make the project compliant with the REUSE specification. - -The root `Makefile` contains a target `reuse` that updates copyright headers and checks for compliance. - -See for more information. diff --git a/.reuse/dep5 b/.reuse/dep5 index 315cae923..06b1d37c1 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -4,11 +4,15 @@ Upstream-Contact: Niels Lohmann Source: https://github.com/nlohmann/json Files: * -Copyright: 2013-2022 Niels Lohmann +Copyright: 2013-2025 Niels Lohmann License: MIT +Files: include/nlohmann/thirdparty/hedley.hpp +Copyright: 2016-2021 Evan Nemerson +License: CC0 + Files: tests/thirdparty/doctest/* -Copyright: 2016-2021 Viktor Kirilov +Copyright: 2016-2023 Viktor Kirilov License: MIT Files: tests/thirdparty/fifo_map/* @@ -16,7 +20,7 @@ Copyright: 2015-2017 Niels Lohmann License: MIT Files: tests/thirdparty/Fuzzer/* -Copyright: 2003-2022, LLVM Project. +Copyright: 2003-2022 LLVM Project. License: Apache-2.0 Files: tests/thirdparty/imapdl/* @@ -27,6 +31,6 @@ Files: tools/amalgamate/* Copyright: 2012 Erik Edlund License: BSD-3-Clause -Files: tools/gdb_pretty_printer +Files: tools/gdb_pretty_printer/* Copyright: 2020 Hannes Domani License: MIT diff --git a/.reuse/templates/json.jinja2 b/.reuse/templates/json.jinja2 index 9f7df2a39..095e3def9 100644 --- a/.reuse/templates/json.jinja2 +++ b/.reuse/templates/json.jinja2 @@ -1,6 +1,6 @@ __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.11.3 +| | |__ | | | | | | version 3.12.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json {% for copyright_line in copyright_lines %} diff --git a/.reuse/templates/json_support.jinja2 b/.reuse/templates/json_support.jinja2 index f12832cb8..e239bb766 100644 --- a/.reuse/templates/json_support.jinja2 +++ b/.reuse/templates/json_support.jinja2 @@ -1,6 +1,6 @@ __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (supporting code) -| | |__ | | | | | | version 3.11.3 +| | |__ | | | | | | version 3.12.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json {% for copyright_line in copyright_lines %} diff --git a/BUILD.bazel b/BUILD.bazel index 15d84f16b..de0ff7145 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,20 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_license//rules:license.bzl", "license") + +package( + default_applicable_licenses = [":license"], +) + +exports_files([ + "LICENSE.MIT", +]) + +license( + name = "license", + license_kinds = ["@rules_license//licenses/spdx:MIT"], + license_text = "LICENSE.MIT", +) + cc_library( name = "json", hdrs = [ @@ -40,6 +57,7 @@ cc_library( "include/nlohmann/detail/output/serializer.hpp", "include/nlohmann/detail/string_concat.hpp", "include/nlohmann/detail/string_escape.hpp", + "include/nlohmann/detail/string_utils.hpp", "include/nlohmann/detail/value_t.hpp", "include/nlohmann/json.hpp", "include/nlohmann/json_fwd.hpp", @@ -51,3 +69,12 @@ cc_library( visibility = ["//visibility:public"], alwayslink = True, ) + +cc_library( + name = "singleheader-json", + hdrs = [ + "single_include/nlohmann/json.hpp", + ], + includes = ["single_include"], + visibility = ["//visibility:public"], +) diff --git a/CITATION.cff b/CITATION.cff index fd3b76713..8a70c17bc 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -7,8 +7,8 @@ authors: email: mail@nlohmann.me website: https://nlohmann.me title: "JSON for Modern C++" -version: 3.11.3 -date-released: 2023-11-28 +version: 3.12.0 +date-released: 2025-04-07 license: MIT repository-code: "https://github.com/nlohmann" url: https://json.nlohmann.me diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a49dc47e..88ef6f661 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 3.1...3.14) +cmake_minimum_required(VERSION 3.5...4.0) ## ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.11.3 LANGUAGES CXX) +project(nlohmann_json VERSION 3.12.0 LANGUAGES CXX) ## ## MAIN_PROJECT CHECK @@ -40,7 +40,8 @@ endif() option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT}) option(JSON_CI "Enable CI build targets." OFF) option(JSON_Diagnostics "Use extended diagnostic messages." OFF) -option(JSON_GlobalUDLs "Place use-defined string literals in the global namespace." ON) +option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF) +option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON) option(JSON_ImplicitConversions "Enable implicit conversions." ON) option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF) option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF) @@ -57,7 +58,11 @@ endif () ## include(GNUInstallDirs) -set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) +if (NOT DEFINED NLOHMANN_JSON_TARGET_NAME) + # Allow overriding the target name when using FetchContent / add_subdirectory. + set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) +endif() + set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" CACHE INTERNAL "") set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") @@ -77,19 +82,27 @@ else() endif() if (NOT JSON_ImplicitConversions) - message(STATUS "Implicit conversions are disabled") + message(STATUS "Implicit conversions are disabled (JSON_USE_IMPLICIT_CONVERSIONS=0)") endif() if (JSON_DisableEnumSerialization) - message(STATUS "Enum integer serialization is disabled") + message(STATUS "Enum integer serialization is disabled (JSON_DISABLE_ENUM_SERIALIZATION=0)") endif() if (JSON_LegacyDiscardedValueComparison) - message(STATUS "Legacy discarded value comparison enabled") + message(STATUS "Legacy discarded value comparison enabled (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1)") endif() if (JSON_Diagnostics) - message(STATUS "Diagnostics enabled") + message(STATUS "Diagnostics enabled (JSON_DIAGNOSTICS=1)") +endif() + +if (JSON_Diagnostic_Positions) + message(STATUS "Diagnostic positions enabled (JSON_DIAGNOSTIC_POSITIONS=1)") +endif() + +if (NOT JSON_GlobalUDLs) + message(STATUS "User-defined string literals are not put in the global namespace (JSON_USE_GLOBAL_UDLS=0)") endif() if (JSON_SystemInclude) @@ -115,6 +128,7 @@ target_compile_definitions( $<$>:JSON_USE_IMPLICIT_CONVERSIONS=0> $<$:JSON_DISABLE_ENUM_SERIALIZATION=1> $<$:JSON_DIAGNOSTICS=1> + $<$:JSON_DIAGNOSTIC_POSITIONS=1> $<$:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1> ) @@ -141,6 +155,7 @@ endif() CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + @ONLY ) ## @@ -206,4 +221,5 @@ if(JSON_Install) FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION ${NLOHMANN_JSON_PKGCONFIG_INSTALL_DIR} ) + include(CPack) endif() diff --git a/ChangeLog.md b/ChangeLog.md index 656d68bcf..2274fb455 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,9 +1,340 @@ # Changelog All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [3.11.2](https://github.com/nlohmann/json/releases/tag/3.11.2) (2022-08-12) +## [unreleased](https://github.com/nlohmann/json/releases/tag/unreleased) (2024-12-22) -[Full Changelog](https://github.com/nlohmann/json/compare/v3.11.1...3.11.2) +[Full Changelog](https://github.com/nlohmann/json/compare/v3.11.3...unreleased) + +- Impossible de read json file create with nlohmann::ordered\_json::dump [\#4556](https://github.com/nlohmann/json/issues/4556) +- Error C2039 : 'json\_sax\_dom\_callback\_parser': is not a member of 'nlohmann::json\_abi\_v3\_11\_3::detail' [\#4529](https://github.com/nlohmann/json/issues/4529) +- `json_fwd.hpp` don't define default template arguments for ordered\_map [\#4518](https://github.com/nlohmann/json/issues/4518) +- new repo version seems stop create any the ingress-nginx controller with opentelemetry-cpp.git [\#4515](https://github.com/nlohmann/json/issues/4515) +- Error converting to/from scoped enumerations [\#4499](https://github.com/nlohmann/json/issues/4499) +- Default initialized iterators are not comparable [\#4493](https://github.com/nlohmann/json/issues/4493) +- Bug json.exception.type\_error.302 [\#4492](https://github.com/nlohmann/json/issues/4492) +- tests fail to build with clang-19 and libc++ due to unsupported `std::char_traits` [\#4490](https://github.com/nlohmann/json/issues/4490) +- Brace-Initialization Fails with json::parse and Key Access on Linux [\#4488](https://github.com/nlohmann/json/issues/4488) +- Crash when parsing nullptr [\#4485](https://github.com/nlohmann/json/issues/4485) +- Namespace macros are not respected in many instances [\#4484](https://github.com/nlohmann/json/issues/4484) +- ohos model to json string garbage characters [\#4481](https://github.com/nlohmann/json/issues/4481) +- Missing newlines in deserialized string [\#4479](https://github.com/nlohmann/json/issues/4479) +- Latest tag not available on NuGet [\#4478](https://github.com/nlohmann/json/issues/4478) +- Invalid union access for get\_ref/get\_ptr with unsigned integer [\#4475](https://github.com/nlohmann/json/issues/4475) +- /accesswallet [\#4469](https://github.com/nlohmann/json/issues/4469) +- struct reflect json with error C2440 [\#4467](https://github.com/nlohmann/json/issues/4467) +- Compiler error when using macro NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE [\#4463](https://github.com/nlohmann/json/issues/4463) +- Issue when dumping a vector of derived classes [\#4462](https://github.com/nlohmann/json/issues/4462) +- whit std::wstring compile error [\#4460](https://github.com/nlohmann/json/issues/4460) +- Inconsisten operator\[\] [\#4458](https://github.com/nlohmann/json/issues/4458) +- json parse enclosing json object with \[\] [\#4457](https://github.com/nlohmann/json/issues/4457) +- \[bug\] nlohmann::json constructor behaves improperly [\#4450](https://github.com/nlohmann/json/issues/4450) +- parse OOM [\#4449](https://github.com/nlohmann/json/issues/4449) +- Library Cannot Parse JSON File It Wrote [\#4448](https://github.com/nlohmann/json/issues/4448) +- Unexpected Integer Conversion of JSON Values on ARM64 [\#4447](https://github.com/nlohmann/json/issues/4447) +- Structure declared in natvis file template doesn't seem to match current structure of `basic_json<>` [\#4438](https://github.com/nlohmann/json/issues/4438) +- A lot of EOT in json file [\#4436](https://github.com/nlohmann/json/issues/4436) +- CVE-2024-34062 [\#4429](https://github.com/nlohmann/json/issues/4429) +- CVE-2024-39689 [\#4428](https://github.com/nlohmann/json/issues/4428) +- CVE-2024-5569 [\#4427](https://github.com/nlohmann/json/issues/4427) +- CVE-2024-37891 [\#4426](https://github.com/nlohmann/json/issues/4426) +- Tornado vulnerabilities [\#4425](https://github.com/nlohmann/json/issues/4425) +- CVE-2024-35195 [\#4424](https://github.com/nlohmann/json/issues/4424) +- CVE-2024-22195, CVE-2024-34064 [\#4423](https://github.com/nlohmann/json/issues/4423) +- CVE-2024-3651 [\#4422](https://github.com/nlohmann/json/issues/4422) +- CVE-2024-22190 [\#4421](https://github.com/nlohmann/json/issues/4421) +- CVE-2024-39705 [\#4420](https://github.com/nlohmann/json/issues/4420) +- Failing to read complex Unicode string embedded in JSON [\#4417](https://github.com/nlohmann/json/issues/4417) +- Unable to parse JSON string from snake case to camel case [\#4399](https://github.com/nlohmann/json/issues/4399) +- Crashes when I try to use ‘json::at\(\)’ on a properly structured, non null, and correctly constructed ‘.json’ file [\#4387](https://github.com/nlohmann/json/issues/4387) +- JSON\_BuildTests fail when JSON\_DisableEnumSerialization is set to ON [\#4384](https://github.com/nlohmann/json/issues/4384) +- JSON can't parse a simple data [\#4383](https://github.com/nlohmann/json/issues/4383) +- json.exception.type\_error.302 [\#4373](https://github.com/nlohmann/json/issues/4373) +- iteration\_proxy has limited usefulness in C++20 range views [\#4371](https://github.com/nlohmann/json/issues/4371) +- Clone is long due to large history [\#4370](https://github.com/nlohmann/json/issues/4370) +- Can't use nlohmann on Linux [\#4363](https://github.com/nlohmann/json/issues/4363) +- CodeQL suppressions lack justification [\#4361](https://github.com/nlohmann/json/issues/4361) +- \[json.exception.parse\_error.101\] parse error at line 1, column 4520: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '".\? [\#4352](https://github.com/nlohmann/json/issues/4352) +- Cannot unflatten json object [\#4349](https://github.com/nlohmann/json/issues/4349) +- Json parsed from raw string does not interpret lists of objects like json parsed from file [\#4341](https://github.com/nlohmann/json/issues/4341) +- natvis not updated to 3.11.3 [\#4340](https://github.com/nlohmann/json/issues/4340) +- Wrong function name in documentation example [\#4334](https://github.com/nlohmann/json/issues/4334) +- git ref got interpreted as number [\#4332](https://github.com/nlohmann/json/issues/4332) +- Is float valid number been limited? [\#4322](https://github.com/nlohmann/json/issues/4322) +- Crash when construct a new json object [\#4321](https://github.com/nlohmann/json/issues/4321) +- gdb-pretty-print broken since m\_data added [\#4309](https://github.com/nlohmann/json/issues/4309) +- Docs have incorrect info for `update()` [\#4307](https://github.com/nlohmann/json/issues/4307) +- CBOR data cannot be decoded [\#4301](https://github.com/nlohmann/json/issues/4301) +- Inconsistent behaviour of json construction using `std::initializer_list` [\#4299](https://github.com/nlohmann/json/issues/4299) +- Assertion failed when accessing non-existing object with const json object [\#4297](https://github.com/nlohmann/json/issues/4297) +- Validatable release artifacts are not sufficient for packaging \(trying to run tests\) [\#4296](https://github.com/nlohmann/json/issues/4296) +- ordered json pointer corruption [\#4289](https://github.com/nlohmann/json/issues/4289) +- Incorrect floating point parsing [\#4285](https://github.com/nlohmann/json/issues/4285) +- Segfault on parse when using "\#pragma pack \(push, 1\)" [\#4284](https://github.com/nlohmann/json/issues/4284) +- Simple example with nlohmann::ordered\_json doesn't compile [\#4282](https://github.com/nlohmann/json/issues/4282) +- Program crashes with ordered\_json, but works fine with json [\#4279](https://github.com/nlohmann/json/issues/4279) +- JSON parses as array when assigned in initializer list. [\#4278](https://github.com/nlohmann/json/issues/4278) +- Can't run `make amalgamate` [\#4275](https://github.com/nlohmann/json/issues/4275) +- Parsing the unicode string got the wrong result [\#4272](https://github.com/nlohmann/json/issues/4272) +- Issue with including \ [\#4241](https://github.com/nlohmann/json/issues/4241) +- Exception when trying to insert my json object inside json file [\#4239](https://github.com/nlohmann/json/issues/4239) +- `to_json` is erroneously converting enums with underlying unsigned types to signed numbers [\#4236](https://github.com/nlohmann/json/issues/4236) +- Build failure on macOS Sonoma 14.1.1 [\#4228](https://github.com/nlohmann/json/issues/4228) +- Deprecation warning on save action in check-amalgamation CI step [\#4227](https://github.com/nlohmann/json/issues/4227) +- 3.11.3: test suite fails in 4 units [\#4224](https://github.com/nlohmann/json/issues/4224) +- Exception thrown when dumping utf-8 characters when using std::string [\#4213](https://github.com/nlohmann/json/issues/4213) +- patch\_inplace assumes StringType is std::string [\#4134](https://github.com/nlohmann/json/issues/4134) +- Getting a weak-vtables warning with clang on ubuntu 22.04 [\#4087](https://github.com/nlohmann/json/issues/4087) +- SAX interface unexpectedly gets locale-altered float representation. [\#4084](https://github.com/nlohmann/json/issues/4084) +- Feat: hash pin github workflow dependencies [\#4058](https://github.com/nlohmann/json/issues/4058) +- compiler error using clang-16.0.5 when using gcc-13.1 standard library [\#4051](https://github.com/nlohmann/json/issues/4051) +- Missing requirement on `plantuml` binary package [\#4026](https://github.com/nlohmann/json/issues/4026) +- Compile failure for macos 10.10 SDK + darwin14 [\#3991](https://github.com/nlohmann/json/issues/3991) +- Test suite does not compile with C++20 and Clang 17 [\#3979](https://github.com/nlohmann/json/issues/3979) +- `modernize-avoid-c-arrays` clang-tidy warning when using `NLOHMANN_JSON_SERIALIZE_ENUM` macro [\#3924](https://github.com/nlohmann/json/issues/3924) +- JSON\_DIAGNOSTICS trigger assertion [\#3915](https://github.com/nlohmann/json/issues/3915) +- Compiler warning 'array-bounds' on g++12.2.0 on Ubuntu 22.10 kinetic with RelWithDebugInfo [\#3808](https://github.com/nlohmann/json/issues/3808) +- The MSVC team recently test JSON project failed to run test on release configuration on windows\_x64. [\#3542](https://github.com/nlohmann/json/issues/3542) +- Bad JSON diff when removing object in array of object [\#3146](https://github.com/nlohmann/json/issues/3146) +- Limit AppVeyor use [\#3089](https://github.com/nlohmann/json/issues/3089) +- pkgconfig integration wrongly rendered if tests are run [\#2907](https://github.com/nlohmann/json/issues/2907) +- Compile error for json in template and variadic macros. [\#2794](https://github.com/nlohmann/json/issues/2794) +- How to Serialize derived class to JSON object? [\#2199](https://github.com/nlohmann/json/issues/2199) +- \[C++17\] Allow std::optional to convert to nlohmann::json [\#1749](https://github.com/nlohmann/json/issues/1749) + +- Fix typo in nlohmann\_define\_derived\_type.md [\#4565](https://github.com/nlohmann/json/pull/4565) ([gregmarr](https://github.com/gregmarr)) +- Add ONLY\_SERIALIZE for NLOHMANN\_DEFINE\_DERIVED\_TYPE\_\* macros [\#4562](https://github.com/nlohmann/json/pull/4562) ([EinarsNG](https://github.com/EinarsNG)) +- Suppress modernize-use-integer-sign-comparison [\#4558](https://github.com/nlohmann/json/pull/4558) ([nlohmann](https://github.com/nlohmann)) +- Bump actions/upload-artifact from 4.4.3 to 4.5.0 [\#4557](https://github.com/nlohmann/json/pull/4557) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Clean up CI [\#4553](https://github.com/nlohmann/json/pull/4553) ([nlohmann](https://github.com/nlohmann)) +- \[StepSecurity\] ci: Harden GitHub Actions [\#4551](https://github.com/nlohmann/json/pull/4551) ([step-security-bot](https://github.com/step-security-bot)) +- Fix token permissions warnings [\#4550](https://github.com/nlohmann/json/pull/4550) ([nlohmann](https://github.com/nlohmann)) +- Add step to build the documentation [\#4549](https://github.com/nlohmann/json/pull/4549) ([nlohmann](https://github.com/nlohmann)) +- Bump mkdocs-material from 9.5.48 to 9.5.49 in /docs/mkdocs [\#4548](https://github.com/nlohmann/json/pull/4548) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Move reuse dependency to requirements.txt file [\#4547](https://github.com/nlohmann/json/pull/4547) ([nlohmann](https://github.com/nlohmann)) +- Clean up [\#4546](https://github.com/nlohmann/json/pull/4546) ([nlohmann](https://github.com/nlohmann)) +- ⬆️ Bump ossf/scorecard-action from 2.3.3 to 2.4.0 [\#4545](https://github.com/nlohmann/json/pull/4545) ([dependabot[bot]](https://github.com/apps/dependabot)) +- ⬆️ Bump lukka/get-cmake from 3.31.0 to 3.31.2 [\#4544](https://github.com/nlohmann/json/pull/4544) ([dependabot[bot]](https://github.com/apps/dependabot)) +- ⬆️ Bump github/codeql-action from 2.27.9 to 3.27.9 [\#4543](https://github.com/nlohmann/json/pull/4543) ([dependabot[bot]](https://github.com/apps/dependabot)) +- ⬆️ Bump watchdog from 2.1.7 to 6.0.0 in /tools/serve\_header [\#4542](https://github.com/nlohmann/json/pull/4542) ([dependabot[bot]](https://github.com/apps/dependabot)) +- ⬆️ Bump pyyaml from 6.0 to 6.0.2 in /tools/serve\_header [\#4541](https://github.com/nlohmann/json/pull/4541) ([dependabot[bot]](https://github.com/apps/dependabot)) +- ⬆️ Bump actions/github-script from 6.4.0 to 7.0.1 [\#4540](https://github.com/nlohmann/json/pull/4540) ([dependabot[bot]](https://github.com/apps/dependabot)) +- \[StepSecurity\] Apply security best practices [\#4539](https://github.com/nlohmann/json/pull/4539) ([step-security-bot](https://github.com/step-security-bot)) +- Set parents after insert call [\#4537](https://github.com/nlohmann/json/pull/4537) ([nlohmann](https://github.com/nlohmann)) +- Allow patch and diff to be used with arbitrary string types [\#4536](https://github.com/nlohmann/json/pull/4536) ([nlohmann](https://github.com/nlohmann)) +- Add more package managers [\#4533](https://github.com/nlohmann/json/pull/4533) ([nlohmann](https://github.com/nlohmann)) +- Replace EOF with char\_traits [\#4532](https://github.com/nlohmann/json/pull/4532) ([nlohmann](https://github.com/nlohmann)) +- Fix return value of get\_ptr for unsigned integers [\#4525](https://github.com/nlohmann/json/pull/4525) ([nlohmann](https://github.com/nlohmann)) +- Add more GCC warning flags [\#4524](https://github.com/nlohmann/json/pull/4524) ([nlohmann](https://github.com/nlohmann)) +- Update licenses [\#4521](https://github.com/nlohmann/json/pull/4521) ([nlohmann](https://github.com/nlohmann)) +- json start/end position implementation [\#4517](https://github.com/nlohmann/json/pull/4517) ([sushshring](https://github.com/sushshring)) +- Overwork documentation [\#4516](https://github.com/nlohmann/json/pull/4516) ([nlohmann](https://github.com/nlohmann)) +- Allow comparing default initialized iterators [\#4512](https://github.com/nlohmann/json/pull/4512) ([nlohmann](https://github.com/nlohmann)) +- fix: integer parsed as float when EINTR set in errno [\#4506](https://github.com/nlohmann/json/pull/4506) ([StuartGorman](https://github.com/StuartGorman)) +- Make SAX output locale-independent [\#4505](https://github.com/nlohmann/json/pull/4505) ([nlohmann](https://github.com/nlohmann)) +- Skip enum tests when JSON\_DisableEnumSerialization=ON [\#4504](https://github.com/nlohmann/json/pull/4504) ([nlohmann](https://github.com/nlohmann)) +- Fix weak-vtables warning [\#4500](https://github.com/nlohmann/json/pull/4500) ([nlohmann](https://github.com/nlohmann)) +- Suppress warnings in NLOHMANN\_JSON\_SERIALIZE\_ENUM [\#4497](https://github.com/nlohmann/json/pull/4497) ([nlohmann](https://github.com/nlohmann)) +- Add comment for \#4494 [\#4496](https://github.com/nlohmann/json/pull/4496) ([nlohmann](https://github.com/nlohmann)) +- Add test for libstdc++ [\#4495](https://github.com/nlohmann/json/pull/4495) ([nlohmann](https://github.com/nlohmann)) +- Another desperate try to fix the CI [\#4489](https://github.com/nlohmann/json/pull/4489) ([nlohmann](https://github.com/nlohmann)) +- Possible fix for \#4485 [\#4487](https://github.com/nlohmann/json/pull/4487) ([jordan-hoang](https://github.com/jordan-hoang)) +- Update CONTRIBUTING.md [\#4486](https://github.com/nlohmann/json/pull/4486) ([zerocukor287](https://github.com/zerocukor287)) +- Allow overriding the CMake target name [\#4483](https://github.com/nlohmann/json/pull/4483) ([iboB](https://github.com/iboB)) +- Update is\_structured.md [\#4472](https://github.com/nlohmann/json/pull/4472) ([thetimr](https://github.com/thetimr)) +- Add CPack support [\#4459](https://github.com/nlohmann/json/pull/4459) ([zjyhjqs](https://github.com/zjyhjqs)) +- CMake: generate a pkg-config file that follow pkg-config conventions [\#4456](https://github.com/nlohmann/json/pull/4456) ([dcbaker](https://github.com/dcbaker)) +- Update natvis to reflect 3.11.3 and the current structure of basic\_json [\#4451](https://github.com/nlohmann/json/pull/4451) ([gmyers18](https://github.com/gmyers18)) +- Docs: fix typos of 'whether' in `operator_{gt,le,lt}.md` [\#4412](https://github.com/nlohmann/json/pull/4412) ([tsnl](https://github.com/tsnl)) +- Remove alwayslink=True Bazel flag [\#4396](https://github.com/nlohmann/json/pull/4396) ([mering](https://github.com/mering)) +- Optimize binary `get_number` implementation by reading multiple bytes at once [\#4391](https://github.com/nlohmann/json/pull/4391) ([TianyiChen](https://github.com/TianyiChen)) +- Make iterator\_proxy\_value a forward\_iterator \(\#4371\) [\#4372](https://github.com/nlohmann/json/pull/4372) ([captaincrutches](https://github.com/captaincrutches)) +- Add lgtm explanation [\#4362](https://github.com/nlohmann/json/pull/4362) ([nlohmann](https://github.com/nlohmann)) +- chore: fix some typos in comments [\#4345](https://github.com/nlohmann/json/pull/4345) ([laterlaugh](https://github.com/laterlaugh)) +- Fix gdb pretty printer [\#4343](https://github.com/nlohmann/json/pull/4343) ([MrJia1997](https://github.com/MrJia1997)) +- Fix for incorrect function name in documentation example [\#4342](https://github.com/nlohmann/json/pull/4342) ([alexprabhat99](https://github.com/alexprabhat99)) +- Fixed an error in the `Custom data source` example. [\#4335](https://github.com/nlohmann/json/pull/4335) ([philip-paul-mueller](https://github.com/philip-paul-mueller)) +- Updated exception handling to catch const reference in out\_of\_range [\#4331](https://github.com/nlohmann/json/pull/4331) ([LeilaShcheglova](https://github.com/LeilaShcheglova)) +- \#4307 Updated docx to 3.10.5 from 3.10.4 [\#4310](https://github.com/nlohmann/json/pull/4310) ([AniketDhemare](https://github.com/AniketDhemare)) +- Align astyle flags in Makefile with CI [\#4277](https://github.com/nlohmann/json/pull/4277) ([serge-s](https://github.com/serge-s)) +- Suppress Clang-Tidy warnings [\#4276](https://github.com/nlohmann/json/pull/4276) ([nlohmann](https://github.com/nlohmann)) +- Remove broken link from CONTRIBUTING.md [\#4274](https://github.com/nlohmann/json/pull/4274) ([serge-s](https://github.com/serge-s)) +- Fix version in json\_has\_static\_rtti.md [\#4269](https://github.com/nlohmann/json/pull/4269) ([ALF-ONE](https://github.com/ALF-ONE)) +- Add support of multi-dim C-style array member of struct. [\#4262](https://github.com/nlohmann/json/pull/4262) ([peng-wang-cn](https://github.com/peng-wang-cn)) +- Docs: Fix wrong code usage in the Value access section of `json_pointer.md` [\#4255](https://github.com/nlohmann/json/pull/4255) ([Fallen-Breath](https://github.com/Fallen-Breath)) +- Fix `to_json` for enums when the enum has an unsigned underlying type. [\#4237](https://github.com/nlohmann/json/pull/4237) ([TheJCAB](https://github.com/TheJCAB)) +- feat: Rebase `feature/optional` to `develop` [\#4036](https://github.com/nlohmann/json/pull/4036) ([fsandhei](https://github.com/fsandhei)) +- Add NLOHMANN\_DEFINE\_DERIVED\_TYPE\_\* macros [\#4033](https://github.com/nlohmann/json/pull/4033) ([rotolof](https://github.com/rotolof)) + +## [v3.11.3](https://github.com/nlohmann/json/releases/tag/v3.11.3) (2023-11-28) + +[Full Changelog](https://github.com/nlohmann/json/compare/v3.11.2...v3.11.3) + +- Parser and constructor resolve integer types differently [\#4207](https://github.com/nlohmann/json/issues/4207) +- README.md overuses `template` keyword before `get` function [\#4205](https://github.com/nlohmann/json/issues/4205) +- Exception SIGSEGV - Segmentation violation signal on file parsing \(v3.11.2, linux, doctest\) [\#4193](https://github.com/nlohmann/json/issues/4193) +- In highly nested functions, passing json into a function leads to a segmentation fault/bus error [\#4186](https://github.com/nlohmann/json/issues/4186) +- why a single-object json file appears in an array [\#4183](https://github.com/nlohmann/json/issues/4183) +- Initializing `json` by direct initialization and copy initialization invokes different constructors [\#4174](https://github.com/nlohmann/json/issues/4174) +- Deprecation warning about std::char\_traits\ [\#4163](https://github.com/nlohmann/json/issues/4163) +- LLVM 16.0.6 issues warning for literal operators when Wdeprecated-literal-operator [\#4129](https://github.com/nlohmann/json/issues/4129) +- GCC compiler warning about violating the C++ One Definition Rule \[-Wodr\] [\#4116](https://github.com/nlohmann/json/issues/4116) +- error: building nlohmann-json:arm64-osx failed with: BUILD\_FAILED [\#4091](https://github.com/nlohmann/json/issues/4091) +- dump\(\): Non-conforming with JSON-spec escape of strings? [\#4088](https://github.com/nlohmann/json/issues/4088) +- Compiling in visual studio 2022 gives a warning [\#4081](https://github.com/nlohmann/json/issues/4081) +- Upgrade CMake minimum version [\#4076](https://github.com/nlohmann/json/issues/4076) +- \ character in the content of a string cause error in parser.? [\#4067](https://github.com/nlohmann/json/issues/4067) +- JSON Parsing Freeze Issue on Nintendo Switch [\#4066](https://github.com/nlohmann/json/issues/4066) +- Clang++ compilation fails on extremely small example [\#4061](https://github.com/nlohmann/json/issues/4061) +- how about open a new repository for header only version? [\#4060](https://github.com/nlohmann/json/issues/4060) +- json::count returns only 0 or 1 [\#4052](https://github.com/nlohmann/json/issues/4052) +- std::function error [\#4050](https://github.com/nlohmann/json/issues/4050) +- Json package not compiling properly [\#4042](https://github.com/nlohmann/json/issues/4042) +- Explicit conversion example in docs should use `template get` [\#4038](https://github.com/nlohmann/json/issues/4038) +- Improve wording of parse\_error exception [\#4037](https://github.com/nlohmann/json/issues/4037) +- Parse error on valid JSON file [\#4028](https://github.com/nlohmann/json/issues/4028) +- Empty JSON object returns size of 1 [\#4027](https://github.com/nlohmann/json/issues/4027) +- Help needed to fix CI [\#4025](https://github.com/nlohmann/json/issues/4025) +- Security vulnerabilities detected: CVE-2022-24439, WS-2022-0438, WS-2022-0437 [\#4020](https://github.com/nlohmann/json/issues/4020) +- multithreading use from\_msgpack leading very slow [\#4016](https://github.com/nlohmann/json/issues/4016) +- Error with sol for Lua: items\(\) is not a recognized container [\#4012](https://github.com/nlohmann/json/issues/4012) +- Parser does not read non ascii characters : ŞÜİĞ [\#4007](https://github.com/nlohmann/json/issues/4007) +- malloc\(\): unaligned fastbin chunk detected [\#3999](https://github.com/nlohmann/json/issues/3999) +- try/catch block doesn't work while accessing const json& array. [\#3998](https://github.com/nlohmann/json/issues/3998) +- a bug about list [\#3995](https://github.com/nlohmann/json/issues/3995) +- heap corruption when i use nlohmann::json::accept function to check a valid json [\#3994](https://github.com/nlohmann/json/issues/3994) +- Exception on gcc but not apple clang [\#3986](https://github.com/nlohmann/json/issues/3986) +- Can't support convert the type? std::string json\_str = R"\({"value": "3.1415"}\)"; float value = j\["value"\].get\\(\); [\#3984](https://github.com/nlohmann/json/issues/3984) +- `#pragma once` not supported with C++20 modules in clang [\#3974](https://github.com/nlohmann/json/issues/3974) +- const array\_t::operator\[\] results in buffer overflow / segv on nullptr on out of bounds access [\#3973](https://github.com/nlohmann/json/issues/3973) +- Set minimal permissions to Github Workflows [\#3971](https://github.com/nlohmann/json/issues/3971) +- Parsing array error [\#3968](https://github.com/nlohmann/json/issues/3968) +- why I can return tuple as json? [\#3961](https://github.com/nlohmann/json/issues/3961) +- type must be number, but is null [\#3956](https://github.com/nlohmann/json/issues/3956) +- Class Composition of json members produces incorrect json when constructing with initialization list [\#3955](https://github.com/nlohmann/json/issues/3955) +- exit without error message [\#3948](https://github.com/nlohmann/json/issues/3948) +- NLOHMANN\_DEFINE\_TYPE\_INTRUSIVE doesn't work with "json\_fwd.hpp" [\#3946](https://github.com/nlohmann/json/issues/3946) +- Dangerous use of pull\_request\_target [\#3945](https://github.com/nlohmann/json/issues/3945) +- Test \#7: test-bjdata\_cpp11 ............................\*\*\*Failed [\#3941](https://github.com/nlohmann/json/issues/3941) +- Memory leak detection with basic usage of NLOHMANN\_JSON\_SERIALIZE\_ENUM [\#3939](https://github.com/nlohmann/json/issues/3939) +- Parse doesnt work [\#3936](https://github.com/nlohmann/json/issues/3936) +- Clean up badges [\#3935](https://github.com/nlohmann/json/issues/3935) +- \[json.exception.type\_error.305\] cannot use operator\[\] with a string argument with array [\#3931](https://github.com/nlohmann/json/issues/3931) +- GCC 13 build failures [\#3927](https://github.com/nlohmann/json/issues/3927) +- Exception throw even though code is inside try/catch [\#3926](https://github.com/nlohmann/json/issues/3926) +- Please fix failing tests [\#3923](https://github.com/nlohmann/json/issues/3923) +- Security vulnerability in dependency: future 0.18.2 [\#3922](https://github.com/nlohmann/json/issues/3922) +- json pretty printer causes python exceptions on non-json types [\#3919](https://github.com/nlohmann/json/issues/3919) +- how does a normal basic\_json\<\> object cuase assertion `false` [\#3918](https://github.com/nlohmann/json/issues/3918) +- The library can not parse JSON generate by Chome DevTools Protocol [\#3903](https://github.com/nlohmann/json/issues/3903) +- Typo in `cmake/test.cmake` [\#3902](https://github.com/nlohmann/json/issues/3902) +- Parser adds wrapping array when compiled with GCC [\#3897](https://github.com/nlohmann/json/issues/3897) +- when i use for\(auto iter& : jsonObject\) it occure some error [\#3893](https://github.com/nlohmann/json/issues/3893) +- Check Drone CI [\#3890](https://github.com/nlohmann/json/issues/3890) +- Json::accept\(std::ifstream\) [\#3884](https://github.com/nlohmann/json/issues/3884) +- \[json.exception.parse\_error.101\] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '\[', '{', or a literal [\#3882](https://github.com/nlohmann/json/issues/3882) +- Memory leak when exception is thrown in adl\_serializer::to\_json [\#3881](https://github.com/nlohmann/json/issues/3881) +- building with cmake [\#3880](https://github.com/nlohmann/json/issues/3880) +- \[json.exception.type\_error.316\] invalid UTF-8 byte at index 0: 0xB6 [\#3879](https://github.com/nlohmann/json/issues/3879) +- Visual Studio 2015 C2664 error std::pair\< [\#3867](https://github.com/nlohmann/json/issues/3867) +- I want the data field to be empty serialized and deserialized to each other [\#3866](https://github.com/nlohmann/json/issues/3866) +- Generated natvis is invalid XML [\#3858](https://github.com/nlohmann/json/issues/3858) +- Json Arrays have inconsistent nesting levels across different OSs [\#3854](https://github.com/nlohmann/json/issues/3854) +- Occur error when parse character '\' [\#3844](https://github.com/nlohmann/json/issues/3844) +- Proccess crash as soon as I parse json [\#3843](https://github.com/nlohmann/json/issues/3843) +- json::parse and constructor with the same json generates different type [\#3842](https://github.com/nlohmann/json/issues/3842) +- json::accept return false on valid JSON [\#3838](https://github.com/nlohmann/json/issues/3838) +- decode\(state, codep, byte\) generates warnings. [\#3837](https://github.com/nlohmann/json/issues/3837) +- Arithmetic operators are not working as expected [\#3832](https://github.com/nlohmann/json/issues/3832) +- array\_index does not catch std::invalid\_argument exception from std::stoull [\#3831](https://github.com/nlohmann/json/issues/3831) +- 3.11.2: test suite is failing in two units [\#3828](https://github.com/nlohmann/json/issues/3828) +- Compile Error on g++ using get\(\) function [\#3827](https://github.com/nlohmann/json/issues/3827) +- nlohmann::json::parse can't handle the "€" symbol. [\#3825](https://github.com/nlohmann/json/issues/3825) +- When reading a non-existent key, I unexpectedly get a value. Is it the wrong way I use it? [\#3811](https://github.com/nlohmann/json/issues/3811) +- Code analysis warning string\_concat.hpp C26800: Use of a moved from object [\#3805](https://github.com/nlohmann/json/issues/3805) +- The code used to build with 3.10.2 but fails now [\#3804](https://github.com/nlohmann/json/issues/3804) +- Inconsistent Behaviour of NaN & Null Values [\#3799](https://github.com/nlohmann/json/issues/3799) +- json\_fwd.hpp doesn't work [\#3796](https://github.com/nlohmann/json/issues/3796) +- Compilation fails in MSVC 22 [\#3787](https://github.com/nlohmann/json/issues/3787) +- parsing json with missing key throws exception [\#3784](https://github.com/nlohmann/json/issues/3784) +- Allow to disable inline namespaces completley [\#3746](https://github.com/nlohmann/json/issues/3746) +- double free or Assertion failed! [\#3729](https://github.com/nlohmann/json/issues/3729) +- Amalgated json\_fwd.hpp not included in include.zip [\#3727](https://github.com/nlohmann/json/issues/3727) +- INT64\_MIN/MAX not defined for newer g++ [\#3722](https://github.com/nlohmann/json/issues/3722) +- Compilation error with JSON\_DIAGNOSTICS enabled [\#3717](https://github.com/nlohmann/json/issues/3717) +- class-level enum not serialized as string via NLOHMANN\_JSON\_SERIALIZE\_ENUM [\#3715](https://github.com/nlohmann/json/issues/3715) +- Local copy given by operator\[\] or at\(\) [\#3704](https://github.com/nlohmann/json/issues/3704) +- nlohmann::to\_json method not acting as expected with nlohmann::adl\_serializer specialization. [\#3340](https://github.com/nlohmann/json/issues/3340) +- braced-init-list: array vs other constructor [\#2583](https://github.com/nlohmann/json/issues/2583) + +- JSON for Modern C++ 3.11.3 [\#4222](https://github.com/nlohmann/json/pull/4222) ([nlohmann](https://github.com/nlohmann)) +- Update documentation for the next release [\#4216](https://github.com/nlohmann/json/pull/4216) ([nlohmann](https://github.com/nlohmann)) +- Fix failing CI checks [\#4215](https://github.com/nlohmann/json/pull/4215) ([colbychaskell](https://github.com/colbychaskell)) +- Fix CI \(again\) [\#4196](https://github.com/nlohmann/json/pull/4196) ([nlohmann](https://github.com/nlohmann)) +- fix cmake header path in install with custom CMAKE\_INSTALL\_INCLUDEDIR [\#4194](https://github.com/nlohmann/json/pull/4194) ([bebuch](https://github.com/bebuch)) +- Add more specific error message when attempting to parse empty input [\#4180](https://github.com/nlohmann/json/pull/4180) ([colbychaskell](https://github.com/colbychaskell)) +- Fix char\_traits deprecation warning [\#4179](https://github.com/nlohmann/json/pull/4179) ([colbychaskell](https://github.com/colbychaskell)) +- Fix MinGW CI [\#4175](https://github.com/nlohmann/json/pull/4175) ([scribam](https://github.com/scribam)) +- Fix spellcheck issue [\#4173](https://github.com/nlohmann/json/pull/4173) ([mwestphal](https://github.com/mwestphal)) +- Fix source highlighting in user defined type macros docs [\#4169](https://github.com/nlohmann/json/pull/4169) ([ZeronSix](https://github.com/ZeronSix)) +- Fix deprecation warning [\#4161](https://github.com/nlohmann/json/pull/4161) ([nlohmann](https://github.com/nlohmann)) +- Fix CI [\#4160](https://github.com/nlohmann/json/pull/4160) ([nlohmann](https://github.com/nlohmann)) +- Update index.md [\#4159](https://github.com/nlohmann/json/pull/4159) ([miny1233](https://github.com/miny1233)) +- Update index.md [\#4149](https://github.com/nlohmann/json/pull/4149) ([HO-COOH](https://github.com/HO-COOH)) +- Correct a typo in serve\_header/README.md [\#4143](https://github.com/nlohmann/json/pull/4143) ([felixonmars](https://github.com/felixonmars)) +- Fixed init-list construction when size\_type is not int [\#4140](https://github.com/nlohmann/json/pull/4140) ([tomalakgeretkal](https://github.com/tomalakgeretkal)) +- Update CODEOWNERS [\#4126](https://github.com/nlohmann/json/pull/4126) ([tarolling](https://github.com/tarolling)) +- Accept NEW CMake policies up to CMake 3.14 [\#4112](https://github.com/nlohmann/json/pull/4112) ([craigscott-crascit](https://github.com/craigscott-crascit)) +- Fix typo in afl\_driver.cpp [\#4109](https://github.com/nlohmann/json/pull/4109) ([eltociear](https://github.com/eltociear)) +- Capture exceptions by const& in docs. [\#4099](https://github.com/nlohmann/json/pull/4099) ([iwanders](https://github.com/iwanders)) +- Fix CI, again [\#4083](https://github.com/nlohmann/json/pull/4083) ([nlohmann](https://github.com/nlohmann)) +- Fix Clang-Tidy warnings [\#4047](https://github.com/nlohmann/json/pull/4047) ([nlohmann](https://github.com/nlohmann)) +- Fix compile error with \_HAS\_STATIC\_RTTI=0 [\#4046](https://github.com/nlohmann/json/pull/4046) ([ALF-ONE](https://github.com/ALF-ONE)) +- Add to CONTRIBUTING.md that `make pretty` is required for test updates. [\#4045](https://github.com/nlohmann/json/pull/4045) ([gregmarr](https://github.com/gregmarr)) +- Added to tests the file unit-algorithm.cpp \(c++ 11\) functions from algorithm library [\#4044](https://github.com/nlohmann/json/pull/4044) ([Tomerkm](https://github.com/Tomerkm)) +- Use template get instead of get in examples [\#4039](https://github.com/nlohmann/json/pull/4039) ([tusooa](https://github.com/tusooa)) +- Support Apple's Swift Package Manager [\#4010](https://github.com/nlohmann/json/pull/4010) ([aleksproger](https://github.com/aleksproger)) +- Add Vcpkg port version badge [\#3988](https://github.com/nlohmann/json/pull/3988) ([njakob](https://github.com/njakob)) +- Fix CI + new Doctest [\#3985](https://github.com/nlohmann/json/pull/3985) ([nlohmann](https://github.com/nlohmann)) +- Set minimal permissions to Github Workflows [\#3972](https://github.com/nlohmann/json/pull/3972) ([joycebrum](https://github.com/joycebrum)) +- Refactor amalgamation workflow to avoid dangerous use of pull\_request\_target [\#3969](https://github.com/nlohmann/json/pull/3969) ([joycebrum](https://github.com/joycebrum)) +- Fix typo in test.cmake [\#3951](https://github.com/nlohmann/json/pull/3951) ([theevilone45](https://github.com/theevilone45)) +- tests/unit-iterators2: use std::ranges::equals for range comparisons [\#3950](https://github.com/nlohmann/json/pull/3950) ([ArsenArsen](https://github.com/ArsenArsen)) +- 3935, removed lgtm badge and added Cirrus CI badge [\#3937](https://github.com/nlohmann/json/pull/3937) ([haadfida](https://github.com/haadfida)) +- ⬆️ Bump future from 0.18.2 to 0.18.3 in /docs/mkdocs [\#3934](https://github.com/nlohmann/json/pull/3934) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Change 2022 to 2023 [\#3932](https://github.com/nlohmann/json/pull/3932) ([floriansegginger](https://github.com/floriansegginger)) +- PrettyPrinter: Check if match is valid before accessing group [\#3920](https://github.com/nlohmann/json/pull/3920) ([Finkman](https://github.com/Finkman)) +- Fix CI issues [\#3906](https://github.com/nlohmann/json/pull/3906) ([barcode](https://github.com/barcode)) +- Prevent memory leak when exception is thrown in adl\_serializer::to\_json [\#3901](https://github.com/nlohmann/json/pull/3901) ([barcode](https://github.com/barcode)) +- custom allocators: define missing 'rebind' type [\#3895](https://github.com/nlohmann/json/pull/3895) ([trofi](https://github.com/trofi)) +- Try old MinGW script [\#3892](https://github.com/nlohmann/json/pull/3892) ([nlohmann](https://github.com/nlohmann)) +- Upgrade Python packages [\#3891](https://github.com/nlohmann/json/pull/3891) ([nlohmann](https://github.com/nlohmann)) +- Fix warning about moved from object [\#3889](https://github.com/nlohmann/json/pull/3889) ([nlohmann](https://github.com/nlohmann)) +- Remove a magic number [\#3888](https://github.com/nlohmann/json/pull/3888) ([nlohmann](https://github.com/nlohmann)) +- Add migration guide [\#3887](https://github.com/nlohmann/json/pull/3887) ([nlohmann](https://github.com/nlohmann)) +- Clang 15 [\#3876](https://github.com/nlohmann/json/pull/3876) ([nlohmann](https://github.com/nlohmann)) +- Bump certifi from 2022.6.15 to 2022.12.7 in /docs/mkdocs [\#3872](https://github.com/nlohmann/json/pull/3872) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Fix natvis XML [\#3863](https://github.com/nlohmann/json/pull/3863) ([nlohmann](https://github.com/nlohmann)) +- Fix pipeline [\#3862](https://github.com/nlohmann/json/pull/3862) ([nlohmann](https://github.com/nlohmann)) +- Add CIFuzz CI GitHub action [\#3845](https://github.com/nlohmann/json/pull/3845) ([DavidKorczynski](https://github.com/DavidKorczynski)) +- Add serialization-only user defined type macros [\#3816](https://github.com/nlohmann/json/pull/3816) ([ZeronSix](https://github.com/ZeronSix)) +- Bump joblib from 1.1.0 to 1.2.0 in /docs/mkdocs [\#3781](https://github.com/nlohmann/json/pull/3781) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Fix some typos for n-dimensional arrays [\#3767](https://github.com/nlohmann/json/pull/3767) ([striezel](https://github.com/striezel)) +- Fix 'declaration hides global declaration' warning [\#3751](https://github.com/nlohmann/json/pull/3751) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Fix typos in .md files [\#3748](https://github.com/nlohmann/json/pull/3748) ([tocic](https://github.com/tocic)) +- Update Codacy link [\#3740](https://github.com/nlohmann/json/pull/3740) ([nlohmann](https://github.com/nlohmann)) +- Add missing files to release artifacts [\#3728](https://github.com/nlohmann/json/pull/3728) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Add dark mode toggle to documentation [\#3726](https://github.com/nlohmann/json/pull/3726) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Add clang-tools to required tools for ci\_static\_analysis\_clang [\#3724](https://github.com/nlohmann/json/pull/3724) ([nlohmann](https://github.com/nlohmann)) +- Replace limit macros with std::numeric\_limits [\#3723](https://github.com/nlohmann/json/pull/3723) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Add missing \ include [\#3719](https://github.com/nlohmann/json/pull/3719) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Add Bazel build support [\#3709](https://github.com/nlohmann/json/pull/3709) ([Vertexwahn](https://github.com/Vertexwahn)) +- Use official Clang/GCC containers [\#3703](https://github.com/nlohmann/json/pull/3703) ([nlohmann](https://github.com/nlohmann)) +- Add 'Check amalgamation' workflow [\#3693](https://github.com/nlohmann/json/pull/3693) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) +- Allow custom base class as node customization point [\#3110](https://github.com/nlohmann/json/pull/3110) ([barcode](https://github.com/barcode)) + +## [v3.11.2](https://github.com/nlohmann/json/releases/tag/v3.11.2) (2022-08-12) + +[Full Changelog](https://github.com/nlohmann/json/compare/v3.11.1...v3.11.2) - MSVC natvis visualizer does not work after introduction of inline ABI namespace [\#3696](https://github.com/nlohmann/json/issues/3696) - The use of parenthesis gives compilation errors in some situations [\#3682](https://github.com/nlohmann/json/issues/3682) @@ -145,7 +476,7 @@ All notable changes to this project will be documented in this file. This projec - Fix warning [\#3634](https://github.com/nlohmann/json/pull/3634) ([nlohmann](https://github.com/nlohmann)) - Add license header to new files [\#3633](https://github.com/nlohmann/json/pull/3633) ([nlohmann](https://github.com/nlohmann)) - Add a unit test including windows.h [\#3631](https://github.com/nlohmann/json/pull/3631) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) -- Fixed latest build error in msvc platform [\#3630](https://github.com/nlohmann/json/pull/3630) ([KsaNL](https://github.com/KsaNL)) +- Fixed latest build error in msvc platform [\#3630](https://github.com/nlohmann/json/pull/3630) ([Lioncky](https://github.com/Lioncky)) - Add regression tests for \#3204 and \#3333 [\#3629](https://github.com/nlohmann/json/pull/3629) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) - Fix patch::add creating nonexistent parents [\#3628](https://github.com/nlohmann/json/pull/3628) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) - Adjust JSON Pointer examples [\#3622](https://github.com/nlohmann/json/pull/3622) ([nlohmann](https://github.com/nlohmann)) @@ -178,7 +509,7 @@ All notable changes to this project will be documented in this file. This projec - Use REUSE framework [\#3546](https://github.com/nlohmann/json/pull/3546) ([nlohmann](https://github.com/nlohmann)) - Use `std::iterator_traits` to extract `iterator_category` [\#3544](https://github.com/nlohmann/json/pull/3544) ([Mike-Leo-Smith](https://github.com/Mike-Leo-Smith)) - BJData dimension length can not be string\_t::npos, fix \#3541 [\#3543](https://github.com/nlohmann/json/pull/3543) ([fangq](https://github.com/fangq)) -- Allow disabling default enum conversions [\#3536](https://github.com/nlohmann/json/pull/3536) ([zxey](https://github.com/zxey)) +- Allow disabling default enum conversions [\#3536](https://github.com/nlohmann/json/pull/3536) ([richardhozak](https://github.com/richardhozak)) - Add to\_json\(\) for std::vector\::reference [\#3534](https://github.com/nlohmann/json/pull/3534) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) - CI: Enable 32bit unit test \(3\) [\#3532](https://github.com/nlohmann/json/pull/3532) ([falbrechtskirchinger](https://github.com/falbrechtskirchinger)) - Use new CI image [\#3528](https://github.com/nlohmann/json/pull/3528) ([nlohmann](https://github.com/nlohmann)) @@ -639,7 +970,6 @@ All notable changes to this project will be documented in this file. This projec - array\_index possible out of range [\#2205](https://github.com/nlohmann/json/issues/2205) - Object deserialized as array [\#2204](https://github.com/nlohmann/json/issues/2204) - Sending to a function a reference to a sub-branch [\#2200](https://github.com/nlohmann/json/issues/2200) -- How to Serialize derived class to JSON object? [\#2199](https://github.com/nlohmann/json/issues/2199) - JSON incorrectly serialized [\#2198](https://github.com/nlohmann/json/issues/2198) - Exception Unhandled out\_of\_range error [\#2197](https://github.com/nlohmann/json/issues/2197) - msgpack serialisation : float is treated as 64bit float, not 32bit float. [\#2196](https://github.com/nlohmann/json/issues/2196) @@ -672,7 +1002,6 @@ All notable changes to this project will be documented in this file. This projec - Compilation failure using Clang on Windows [\#1898](https://github.com/nlohmann/json/issues/1898) - Fail to build when including json.hpp as a system include [\#1818](https://github.com/nlohmann/json/issues/1818) - Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817) -- \[C++17\] Allow std::optional to convert to nlohmann::json [\#1749](https://github.com/nlohmann/json/issues/1749) - How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717) - Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513) - clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119) @@ -1692,7 +2021,7 @@ All notable changes to this project will be documented in this file. This projec - Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins)) - Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu)) - Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu)) -- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel)) +- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([vimpunk](https://github.com/vimpunk)) - Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu)) - Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam)) - Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt)) @@ -1859,8 +2188,8 @@ All notable changes to this project will be documented in this file. This projec - Fix unit tests that were silently skipped or crashed \(depending on the compiler\) [\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo)) - Refactor/no virtual sax [\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu)) - Fixed compiler error in VS 2015 for debug mode [\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani)) -- Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow)) -- meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow)) +- Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([ghost](https://github.com/ghost)) +- meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([ghost](https://github.com/ghost)) - Feature/unordered map conversion [\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu)) - fixed compile error for \#1045 [\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599)) - test \(non\)equality for alt\_string implementation [\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius)) @@ -1869,7 +2198,7 @@ All notable changes to this project will be documented in this file. This projec - fix typo in README [\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg)) - Fix typo [\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13)) - Misc cmake packaging enhancements [\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins)) -- Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow)) +- Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jupjohn](https://github.com/jupjohn)) - Fix trivial typo in comment. [\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan)) - Package Manager: Spack [\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l)) - CMake: 3.8+ is Sufficient [\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l)) @@ -2398,7 +2727,7 @@ All notable changes to this project will be documented in this file. This projec - Fix "not constraint" grammar in docs [\#674](https://github.com/nlohmann/json/pull/674) ([wincent](https://github.com/wincent)) - Add documentation for integration with CMake and hunter [\#671](https://github.com/nlohmann/json/pull/671) ([dan-42](https://github.com/dan-42)) - REFACTOR: rewrite CMakeLists.txt for better inlcude and reuse [\#669](https://github.com/nlohmann/json/pull/669) ([dan-42](https://github.com/dan-42)) -- enable\_testing only if the JSON\_BuildTests is ON [\#666](https://github.com/nlohmann/json/pull/666) ([effolkronium](https://github.com/effolkronium)) +- enable\_testing only if the JSON\_BuildTests is ON [\#666](https://github.com/nlohmann/json/pull/666) ([ilqvya](https://github.com/ilqvya)) - Support moving from rvalues in std::initializer\_list [\#663](https://github.com/nlohmann/json/pull/663) ([himikof](https://github.com/himikof)) - add ensure\_ascii parameter to dump. \#330 [\#654](https://github.com/nlohmann/json/pull/654) ([ryanjmulder](https://github.com/ryanjmulder)) - Rename BuildTests to JSON\_BuildTests [\#652](https://github.com/nlohmann/json/pull/652) ([olegendo](https://github.com/olegendo)) @@ -2917,11 +3246,11 @@ All notable changes to this project will be documented in this file. This projec - Keyword 'inline' is useless when member functions are defined in headers [\#87](https://github.com/nlohmann/json/pull/87) ([ahamez](https://github.com/ahamez)) - Remove useless typename [\#86](https://github.com/nlohmann/json/pull/86) ([ahamez](https://github.com/ahamez)) - Avoid warning with Xcode's clang [\#85](https://github.com/nlohmann/json/pull/85) ([ahamez](https://github.com/ahamez)) -- Fix typos [\#73](https://github.com/nlohmann/json/pull/73) ([aqnouch](https://github.com/aqnouch)) +- Fix typos [\#73](https://github.com/nlohmann/json/pull/73) ([maqnouch](https://github.com/maqnouch)) - Replace `default_callback` function with `nullptr` and check for null… [\#72](https://github.com/nlohmann/json/pull/72) ([aburgh](https://github.com/aburgh)) - support enum [\#71](https://github.com/nlohmann/json/pull/71) ([likebeta](https://github.com/likebeta)) - Fix performance regression introduced with the parsing callback feature. [\#69](https://github.com/nlohmann/json/pull/69) ([aburgh](https://github.com/aburgh)) -- Improve the implementations of the comparission-operators [\#63](https://github.com/nlohmann/json/pull/63) ([Florianjw](https://github.com/Florianjw)) +- Improve the implementations of the comparission-operators [\#63](https://github.com/nlohmann/json/pull/63) ([Fiona-J-W](https://github.com/Fiona-J-W)) - Fix compilation of json\_unit with GCC 5 [\#59](https://github.com/nlohmann/json/pull/59) ([dkopecek](https://github.com/dkopecek)) - Parse streams incrementally. [\#40](https://github.com/nlohmann/json/pull/40) ([aburgh](https://github.com/aburgh)) - Feature/small float serialization [\#38](https://github.com/nlohmann/json/pull/38) ([jrandall](https://github.com/jrandall)) diff --git a/FILES.md b/FILES.md new file mode 100644 index 000000000..a7a35f7f2 --- /dev/null +++ b/FILES.md @@ -0,0 +1,239 @@ +# Supporting files + +This file describes the source for supporting files; that is, files that are not part of the library, but define the infrastructure and other aspects of the project. + +- [Continuous Integration](#continuous-integration) +- [GitHub](#github) +- [REUSE](#reuse) +- [Package Managers](#package-managers) + +## Continuous Integration + +### `.cirrus.yml` + +Configuration file for the pipeline at [Cirrus CI](https://cirrus-ci.com/github/nlohmann/json). + +Further documentation: + +- [Writing tasks](https://cirrus-ci.org/guide/writing-tasks/) + +> [!IMPORTANT] +> The filename `.cirrus.yml` and position (root of the repository) are predetermined by Cirrus CI. + +### `.github/external_ci/appveyor.yml` + +Configuration for the pipelines at [AppVeyor](https://ci.appveyor.com/project/nlohmann/json). + +Further documentation: + +- [appveyor.yml reference](https://www.appveyor.com/docs/appveyor-yml/) + +> [!NOTE] +> The filename can be freely configured in the AppVeyor project. + +## GitHub + +### `CITATION.cff` + +A file to configure the citation for the repository which is displayed in the sidebar of the project. + +Further documentation: + +- [About CITATION files](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files) + +> [!IMPORTANT] +> The filename `CITATION.cff` and position (root of the repository) are predetermined by GitHub. + +### `.github/CODE_OF_CONDUCT.md` + +The code of conduct for the project. This is the Markdown version of the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). The code of conduct is linked on the [Community Standards](https://github.com/nlohmann/json/community) page and is mentioned by the Sentiment Bot. + +Further documentation: + +- [Adding a code of conduct to your project](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-code-of-conduct-to-your-project) + +> [!IMPORTANT] +> The filename `.github/CODE_OF_CONDUCT.md` is predetermined by GitHub. + +> [!NOTE] +> The file is part of the documentation and is included in `docs/mkdocs/docs/community/code_of_conduct.md`. + +### `.github/CODEOWNERS` + +The code owners file for the project which is used to select reviewers for new pull requests. + +Further documentation: + +- [About code owners](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) + +> [!IMPORTANT] +> The filename `.github/CODEOWNERS` is predetermined by GitHub. + +### `.github/config.yml` + +Configuration file for [probot](https://probot.github.io/apps/), in particular the [Sentiment Bot](https://probot.github.io/apps/sentiment-bot/) and the [Request Info](https://probot.github.io/apps/request-info/). + +> [!IMPORTANT] +> The filename `.github/config.yml` is predetermined by probot. + +### `.github/CONTRIBUTING.md` + +The contribution guidelines which are linked in the [Community Standards](https://github.com/nlohmann/json/community) and at . + +Further documentation: + +- [Setting guidelines for repository contributors](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors) + +> [!IMPORTANT] +> The filename `.github/CONTRIBUTING.md` is predetermined by GitHub. + +> [!NOTE] +> The file is part of the documentation and is included in `docs/mkdocs/docs/community/contribution_guidelines.md`. + +### `.github/dependabot.yml` + +The configuration of [dependabot](https://github.com/dependabot) which ensures the dependencies (GitHub actions and Python packages used in the CI) remain up-to-date. + +Further documentation: + +- [Configuring Dependabot security updates](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) + +> [!IMPORTANT] +> The filename `.github/dependabot.yml` is predetermined by GitHub. + +### `.github/FUNDING.yml` + +A file to configure the sponsor button of the repository which is displayed in the sidebar of the project. + +Further documentation: + +- [Displaying a sponsor button in your repository](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository) + +> [!IMPORTANT] +> The filename `.github/FUNDING.yml` is predetermined by GitHub. + +### `.github/ISSUE_TEMPLATE/bug.yaml` + +Issue form template for bugs. + +Further documentation: + +- [Configuring issue templates for your repository](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository) + +> [!IMPORTANT] +> The folder `.github/ISSUE_TEMPLATE` is predetermined by GitHub. + +### `.github/ISSUE_TEMPLATE/config.yaml` + +Issue template chooser configuration. The file is used to configure the dialog when a new issue is created. + +Further documentation: + +- [Configuring issue templates for your repository](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository) + +> [!IMPORTANT] +> The filename `.github/ISSUE_TEMPLATE/config.yaml` is predetermined by GitHub. + +### `.github/labeler.yml` + +Configuration file for the "Pull Request Labeler" workflow defined in `workflows/labeler.yml`. This file defines rules how labels are assigned to pull requests based on which files are changed. + +Further documentation: + +- [Label manager for PRs and issues based on configurable conditions](https://github.com/srvaroa/labeler) + +> [!NOTE] +> The filename defaults to `.github/labeler.yml` and can be configured in the workflow. + +### `.github/PULL_REQUEST_TEMPLATE.md` + +The pull request template which prefills new pull requests. + +Further documentation: + +- [Creating a pull request template for your repository](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository) + +> [!IMPORTANT] +> The filename `.github/PULL_REQUEST_TEMPLATE.md` is predetermined by GitHub. + +### `.github/SECURITY.md` + +The goal is to describe how to securely report security vulnerabilities for this repository. The security policy is linked at . + +Further documentation: + +- [Adding a security policy to your repository](https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository) + +> [!IMPORTANT] +> The filename `.github/SECURITY.yml` is predetermined by GitHub. + +> [!NOTE] +> The file is part of the documentation and is included in `docs/mkdocs/docs/community/security_policy.md`. + +### `LICENSE.MIT` + +The license of the project. + +Further documentation: + +- [Adding a license to a repository](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-license-to-a-repository) + +> [!IMPORTANT] +> The filename `LICENSE.MIT` is partly predetermined by GitHub. The root filename must be `LICENSE`. + +## REUSE + +### `.reuse/dep5` + +The file defines the licenses of certain third-party component in the repository. The root `Makefile` contains a target `reuse` that checks for compliance. + +Further documentation: + +- [DEP5](https://reuse.software/spec-3.2/#dep5-deprecated) +- [reuse command-line tool](https://pypi.org/project/reuse/) +- [documentation of linting](https://reuse.readthedocs.io/en/stable/man/reuse-lint.html) +- [REUSE](http://reuse.software) + +> [!IMPORTANT] +> The filename `.reuse/dep5` is predetermined by REUSE. Alternatively, a `REUSE.toml` file can be used. + +### `.reuse/templates` + +Copyright header templates for source files. The root `Makefile` contains a target `reuse` that updates copyright headers with the templates. + +Further information: + +- [reuse command-line tool](https://pypi.org/project/reuse/) +- [documentation on templates](https://reuse.readthedocs.io/en/stable/man/reuse-annotate.html#cmdoption-t) +- [REUSE](http://reuse.software) + +> [!IMPORTANT] +> The folder name `.reuse/templates` is predetermined by REUSE. + +### `LICENSES` + +A folder that contains every license of all licenses files (library and third-party code). + +Further documentation: + +- [REUSE specification](https://reuse.software/spec-3.3/) + +> [!IMPORTANT] +> The folder name `LICENSES` is predetermined by REUSE. + + +## Package Managers + +### `BUILD.bazel` + +The file can be updated by calling + +```shell +make BUILD.bazel +``` + +### `meson.build` + +### `Package.swift` + +### `WORKSPACE.bazel` diff --git a/LICENSE.MIT b/LICENSE.MIT index 1c1f7a690..a1dacc8db 100644 --- a/LICENSE.MIT +++ b/LICENSE.MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2013-2022 Niels Lohmann +Copyright (c) 2013-2025 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..51754e7a3 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,7 @@ +module( + name = "nlohmann_json", + compatibility_level = 1, +) + +bazel_dep(name = "rules_cc", version = "0.0.17") +bazel_dep(name = "rules_license", version = "1.0.0") diff --git a/Makefile b/Makefile index a1b4e7328..9e1c6d78e 100644 --- a/Makefile +++ b/Makefile @@ -43,15 +43,6 @@ all: @echo "run_benchmarks - build and run benchmarks" -########################################################################## -# documentation tests -########################################################################## - -# compile example files and check output -doctest: - $(MAKE) check_output -C docs - - ########################################################################## # benchmarks ########################################################################## @@ -142,33 +133,20 @@ pvs_studio: # Code format and source amalgamation ########################################################################## +ASTYLE=tools/astyle/venv/bin/astyle + +install_astyle: + @test -d tools/astyle/venv || python3 -mvenv tools/astyle/venv ; tools/astyle/venv/bin/pip3 install --quiet --upgrade pip + @test -f $(ASTYLE) || tools/astyle/venv/bin/pip3 install --quiet -r tools/astyle/requirements.txt + @$(ASTYLE) --version + # call the Artistic Style pretty printer on all source files -pretty: - astyle \ - --style=allman \ - --indent=spaces=4 \ - --indent-modifiers \ - --indent-switches \ - --indent-preproc-block \ - --indent-preproc-define \ - --indent-col1-comments \ - --pad-oper \ - --pad-header \ - --align-pointer=type \ - --align-reference=type \ - --add-braces \ - --squeeze-lines=2 \ - --convert-tabs \ - --close-templates \ - --lineend=linux \ - --preserve-date \ - --suffix=none \ - --formatted \ - $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) docs/examples/*.cpp +pretty: install_astyle + $(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) docs/mkdocs/docs/examples/*.cpp # call the Clang-Format on all source files pretty_format: - for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done + for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/mkdocs/docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done # create single header files and pretty print amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) @@ -216,7 +194,7 @@ ChangeLog.md: # Release files ########################################################################## -# Create a tar.gz archive that contains sufficient files to be used as CMake project (e.g., using FetchContent). The +# Create a tar.xz archive that contains sufficient files to be used as CMake project (e.g., using FetchContent). The # archive is created according to the advices of . json.tar.xz: mkdir json @@ -280,6 +258,9 @@ serve_header: ########################################################################## reuse: - pipx run reuse addheader --recursive single_include include -tjson --license MIT --copyright "Niels Lohmann " --year "2013-2022" - pipx run reuse addheader $(TESTS_SRCS) --style=c -tjson_support --license MIT --copyright "Niels Lohmann " --year "2013-2022" + pipx run reuse annotate --recursive single_include include -tjson --license MIT --copyright "Niels Lohmann " --year "2013-2025" --merge-copyrights + pipx run reuse annotate $(TESTS_SRCS) -tjson_support --license MIT --copyright "Niels Lohmann " --year "2013-2025" --merge-copyrights pipx run reuse lint + +spdx: + pipx run reuse spdx --output nlohmann_json.spdx --creator-person "Niels Lohmann" --add-license-concluded diff --git a/Package.swift b/Package.swift index 2f9c4a1f4..2f1e654a2 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "nlohmann-json", platforms: [ - .iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v4) + .iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v4), .visionOS(.v1) ], products: [ .library(name: "json", targets: ["json"]) diff --git a/README.md b/README.md index 910902706..f97afeb41 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![JSON for Modern C++](docs/json.gif)](https://github.com/nlohmann/json/releases) +[![JSON for Modern C++](docs/mkdocs/docs/images/json.gif)](https://github.com/nlohmann/json/releases) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu) @@ -6,19 +6,19 @@ [![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows) [![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://www.codacy.com/gh/nlohmann/json/dashboard?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://app.codacy.com/gh/nlohmann/json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Cirrus CI](https://api.cirrus-ci.com/github/nlohmann/json.svg)](https://cirrus-ci.com/github/nlohmann/json) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) -[![Vcpkg Version](https://img.shields.io/vcpkg/v/nlohmann-json)](https://vcpkg.link/ports/nlohmann-json) [![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) [![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) [![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/nlohmann/json/badge)](https://scorecard.dev/viewer/?uri=github.com/nlohmann/json) [![GitHub Sponsors](https://img.shields.io/badge/GitHub-Sponsors-ff69b4)](https://github.com/sponsors/nlohmann) [![REUSE status](https://api.reuse.software/badge/github.com/nlohmann/json)](https://api.reuse.software/info/github.com/nlohmann/json) [![Discord](https://img.shields.io/discord/1003743314341793913)](https://discord.gg/6mrGXKvX7y) @@ -26,6 +26,7 @@ - [Design goals](#design-goals) - [Sponsors](#sponsors) - [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](https://json.nlohmann.me/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues)) +- [Quick reference](#quick-reference) - [Examples](#examples) - [Read JSON from a file](#read-json-from-a-file) - [Creating `json` objects from JSON literals](#creating-json-objects-from-json-literals) @@ -39,6 +40,7 @@ - [Conversions to/from arbitrary types](#arbitrary-types-conversions) - [Specializing enum conversion](#specializing-enum-conversion) - [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata) +- [Customers](#customers) - [Supported compilers](#supported-compilers) - [Integration](#integration) - [CMake](#cmake) @@ -48,7 +50,6 @@ - [Contact](#contact) - [Thanks](#thanks) - [Used third-party tools](#used-third-party-tools) -- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c) - [Notes](#notes) - [Execute unit tests](#execute-unit-tests) @@ -58,9 +59,9 @@ There are myriads of [JSON](https://json.org) libraries out there, and each may - **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. -- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. +- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. The library is also included in all popular [package managers](https://json.nlohmann.me/integration/package_managers/). -- **Serious testing**. Our code is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). +- **Serious testing**. Our code is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). See the [quality assurance](https://json.nlohmann.me/community/quality_assurance) overview documentation. Other aspects were not so important to us: @@ -70,14 +71,14 @@ Other aspects were not so important to us: See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. - ## Sponsors You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). -### :office: Corporate Sponsor +### :raising_hand: Priority Sponsor -[![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Codacy-logo-black.svg/320px-Codacy-logo-black.svg.png)](https://github.com/codacy/About) +- [Martti Laine](https://github.com/codeclown) +- [Paul Harrington](https://github.com/phrrngtn) ### :label: Named Sponsors @@ -88,20 +89,49 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl - [Steve Wagner](https://github.com/ciroque) - [Lion Yang](https://github.com/LionNatsu) +### Further support + +The development of the library is further supported by JetBrains by providing free access to their IDE tools. + +[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) + Thanks everyone! ## Support :question: If you have a **question**, please check if it is already answered in the [**FAQ**](https://json.nlohmann.me/home/faq/) or the [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) section. If not, please [**ask a new question**](https://github.com/nlohmann/json/discussions/new) there. -:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me). +:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me). -:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/). +:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or have a look at the [quick reference](#quick-reference) below. :bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue. There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for the documentation browsers [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), and [Zeal](https://zealdocs.org) that contains the full [documentation](https://json.nlohmann.me) as offline resource. +## Quick reference + +- **Constructors** [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object) +- **Object inspection**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded) +- **Value access**; [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary) +- **Element access**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back) +- **Lookup**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains) +- **Iterators**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items) +- **Capacity**: [empty](https://json.nlohmann.me/api/basic_json/empty), [size](https://json.nlohmann.me/api/basic_json/size), [max_size](https://json.nlohmann.me/api/basic_json/max_size) +- **Modifiers**: [clear](https://json.nlohmann.me/api/basic_json/clear), [push_back](https://json.nlohmann.me/api/basic_json/push_back), [operator+=](https://json.nlohmann.me/api/basic_json/operator+=), [emplace_back](https://json.nlohmann.me/api/basic_json/emplace_back), [emplace](https://json.nlohmann.me/api/basic_json/emplace), [erase](https://json.nlohmann.me/api/basic_json/erase), [insert](https://json.nlohmann.me/api/basic_json/insert), [update](https://json.nlohmann.me/api/basic_json/update), [swap](https://json.nlohmann.me/api/basic_json/swap) +- **Lexicographical comparison operators**: [operator==](https://json.nlohmann.me/api/basic_json/operator_eq), [operator!=](https://json.nlohmann.me/api/basic_json/operator_ne), [operator<](https://json.nlohmann.me/api/basic_json/operator_lt), [operator>](https://json.nlohmann.me/api/basic_json/operator_gt), [operator<=](https://json.nlohmann.me/api/basic_json/operator_le), [operator>=](https://json.nlohmann.me/api/basic_json/operator_ge), [operator<=>](https://json.nlohmann.me/api/basic_json/operator_spaceship) +- **Serialization / Dumping**: [dump](https://json.nlohmann.me/api/basic_json/dump) +- **Deserialization / Parsing**: [parse](https://json.nlohmann.me/api/basic_json/parse), [accept](https://json.nlohmann.me/api/basic_json/accept), [sax_parse](https://json.nlohmann.me/api/basic_json/sax_parse) +- **JSON Pointer functions**: [flatten](https://json.nlohmann.me/api/basic_json/flatten), [unflatten](https://json.nlohmann.me/api/basic_json/unflatten) +- **JSON Patch functions**: [patch](https://json.nlohmann.me/api/basic_json/patch), [patch_inplace](https://json.nlohmann.me/api/basic_json/patch_inplace), [diff](https://json.nlohmann.me/api/basic_json/diff), [merge_patch](https://json.nlohmann.me/api/basic_json/merge_patch) +- **Static functions**: [meta](https://json.nlohmann.me/api/basic_json/meta), [get_allocator](https://json.nlohmann.me/api/basic_json/get_allocator) +- **Binary formats**: [from_bjdata](https://json.nlohmann.me/api/basic_json/from_bjdata), [from_bson](https://json.nlohmann.me/api/basic_json/from_bson), [from_cbor](https://json.nlohmann.me/api/basic_json/from_cbor), [from_msgpack](https://json.nlohmann.me/api/basic_json/from_msgpack), [from_ubjson](https://json.nlohmann.me/api/basic_json/from_ubjson), [to_bjdata](https://json.nlohmann.me/api/basic_json/to_bjdata), [to_bson](https://json.nlohmann.me/api/basic_json/to_bson), [to_cbor](https://json.nlohmann.me/api/basic_json/to_cbor), [to_msgpack](https://json.nlohmann.me/api/basic_json/to_msgpack), [to_ubjson](https://json.nlohmann.me/api/basic_json/to_ubjson) +- **Non-member functions**: [operator<<](https://json.nlohmann.me/api/operator_ltlt/), [operator>>](https://json.nlohmann.me/api/operator_gtgt/), [to_string](https://json.nlohmann.me/api/basic_json/to_string) +- **Literals**: [operator""_json](https://json.nlohmann.me/api/operator_literal_json) +- **Helper classes**: [std::hash<basic_json>](https://json.nlohmann.me/api/basic_json/std_hash), [std::swap<basic_json>](https://json.nlohmann.me/api/basic_json/std_swap) + +[**Full API documentation**](https://json.nlohmann.me/api/basic_json/) + ## Examples Here are some examples to give you an idea how to use the class. @@ -109,9 +139,8 @@ Here are some examples to give you an idea how to use the class. Beside the examples below, you may want to: → Check the [documentation](https://json.nlohmann.me/)\ -→ Browse the [standalone example files](https://github.com/nlohmann/json/tree/develop/docs/examples) - -Every API function (documented in the [API Documentation](https://json.nlohmann.me/api/basic_json/)) has a corresponding standalone example file. For example, the [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/) function has a matching [emplace.cpp](https://github.com/nlohmann/json/blob/develop/docs/examples/emplace.cpp) example file. +→ Browse the [standalone example files](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples)\ +→ Read the full [API Documentation](https://json.nlohmann.me/api/basic_json/) with self-contained examples for every function ### Read JSON from a file @@ -385,7 +414,7 @@ struct MyIterator { using iterator_category = std::input_iterator_tag; MyIterator& operator++() { - MyContainer.advance(); + target->advance(); return *this; } @@ -394,7 +423,7 @@ struct MyIterator { } reference operator*() const { - return target.get_current(); + return target->get_current(); } MyContainer* target = nullptr; @@ -547,7 +576,6 @@ int fob_present = o.count("fob"); // 0 o.erase("foo"); ``` - ### Conversion from STL containers Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. @@ -803,26 +831,21 @@ Likewise, when calling `template get()` or `get_to(your_type&)`, the Some important things: -* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). -* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. -* When using `template get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) -* In function `from_json`, use function [`at()`](https://json.nlohmann.me/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. -* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +- Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). +- Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. +- When using `template get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) +- In function `from_json`, use function [`at()`](https://json.nlohmann.me/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. +- You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. #### Simplify your life with macros -If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. There are [**several macros**](https://json.nlohmann.me/features/arbitrary_types/#simplify-your-life-with-macros) to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object. -There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: +Which macro to choose depends on whether private member variables need to be accessed, a deserialization is needed, missing values should yield an error or should be replaced by default values, and if derived classes are used. See [this overview to choose the right one for your use case](https://json.nlohmann.me/api/macros/#serializationdeserialization-macros). -- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the namespace of the class/struct to create code for. -- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the class/struct to create code for. This macro can also access private members. +##### Example usage of macros -In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. - -##### Examples - -The `to_json`/`from_json` functions for the `person` struct above can be created with: +The `to_json`/`from_json` functions for the `person` struct above can be created with [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/). In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. ```cpp namespace ns { @@ -830,7 +853,7 @@ namespace ns { } ``` -Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: +Here is another example with private members, where [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/) is needed: ```cpp namespace ns { @@ -839,7 +862,7 @@ namespace ns { std::string street; int housenumber; int postcode; - + public: NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; @@ -973,14 +996,14 @@ struct bad_serializer { template static void to_json(BasicJsonType& j, const T& value) { - // this calls BasicJsonType::json_serializer::to_json(j, value); + // this calls BasicJsonType::json_serializer::to_json(j, value) // if BasicJsonType::json_serializer == bad_serializer ... oops! j = value; } template static void to_json(const BasicJsonType& j, T& value) { - // this calls BasicJsonType::json_serializer::from_json(j, value); + // this calls BasicJsonType::json_serializer::from_json(j, value) // if BasicJsonType::json_serializer == bad_serializer ... oops! value = j.template get(); // oops! } @@ -1026,14 +1049,16 @@ assert(j3.template get() == TS_RUNNING); // undefined json value to enum (where the first map entry above is the default) json jPi = 3.14; -assert(jPi.template get() == TS_INVALID ); +assert(jPi.template get() == TS_INVALID); ``` Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above, + - `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it, and it will default to integer serialization. - It MUST be available (e.g., proper headers must be included) everywhere you use the conversions. Other Important points: + - When using `template get()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully. - If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON. @@ -1108,14 +1133,19 @@ binary.set_subtype(0x10); auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE ``` +## Customers + +The library is used in multiple projects, applications, operating systems, etc. The list below is not exhaustive, but the result of an internet search. If you know further customers of the library, please let me know, see [contact](#contact). + +[![logos of customers using the library](docs/mkdocs/docs/images/customers.png)](https://json.nlohmann.me/home/customers/) ## Supported compilers -Though it's 2023 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: +Though it's 2025 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.8 - 12.0 (and possibly later) -- Clang 3.4 - 15.0 (and possibly later) -- Apple Clang 9.1 - 13.1 (and possibly later) +- GCC 4.8 - 14.2 (and possibly later) +- Clang 3.4 - 21.0 (and possibly later) +- Apple Clang 9.1 - 16.0 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Nvidia CUDA Compiler 11.0.221 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) @@ -1127,10 +1157,10 @@ I would be happy to learn about other compilers/versions. Please note: -- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. +- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - ``` + ```makefile APP_STL := c++_shared NDK_TOOLCHAIN_VERSION := clang3.6 APP_CPPFLAGS += -frtti -fexceptions @@ -1142,68 +1172,7 @@ Please note: - Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. -The following compilers are currently used in continuous integration at [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Cirrus CI](https://cirrus-ci.com/github/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions): - -| Compiler | Operating System | CI Provider | -|--------------------------------------------------------------------------------------------------------|--------------------|----------------| -| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.7 | macOS 11.7.1 | GitHub Actions | -| Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4 | macOS 11.7.1 | GitHub Actions | -| Apple Clang 12.0.5 (clang-1205.0.22.11); Xcode 12.5.1 | macOS 11.7.1 | GitHub Actions | -| Apple Clang 13.0.0 (clang-1300.0.29.3); Xcode 13.0 | macOS 11.7.1 | GitHub Actions | -| Apple Clang 13.0.0 (clang-1300.0.29.3); Xcode 13.1 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 13.0.0 (clang-1300.0.29.30); Xcode 13.2.1 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 13.1.6 (clang-1316.0.21.2.3); Xcode 13.3.1 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 13.1.6 (clang-1316.0.21.2.5); Xcode 13.4.1 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0.1 | macOS 12.6.1 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1 | macOS 12.6.1 | GitHub Actions | -| Clang 3.5.2 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 3.6.2 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 3.7.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 3.8.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 3.9.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 4.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 5.0.2 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 6.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 7.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 8.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 9.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 10.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 10.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 11.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 11.0.0 with MSVC-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 11.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 12.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 12.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 13.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 13.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 14.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 14.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 15.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | -| Clang 15.0.4 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Clang 16.0.0 (16.0.0-++20221031071727+500876226c60-1~exp1~20221031071831.439) | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 4.9.4 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 5.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 6.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 7.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | -| GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | -| GCC 8.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 9.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 10.4.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 11.1.0 | Ubuntu (aarch64) | Cirrus CI | -| GCC 11.3.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 12.2.0 | Ubuntu 20.04.3 LTS | GitHub Actions | -| GCC 13.0.0 20220605 (experimental) | Ubuntu 20.04.3 LTS | GitHub Actions | -| Intel C++ Compiler 2021.5.0.20211109 | Ubuntu 20.04.3 LTS | GitHub Actions | -| NVCC 11.0.221 | Ubuntu 20.04.3 LTS | GitHub Actions | -| Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor | -| Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor | -| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | -| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor | -| Visual Studio 17 2022 MSVC 19.30.30709.0 (Build Engine version 17.0.31804.368 for .NET Framework) | Windows-10.0.20348 | GitHub Actions | - +See the page [quality assurance](https://json.nlohmann.me/community/quality_assurance) on the compilers used to check the library in the CI. ## Integration @@ -1230,7 +1199,7 @@ To use this library from a CMake project, you can locate it directly with `find_ ```cmake # CMakeLists.txt -find_package(nlohmann_json 3.2.0 REQUIRED) +find_package(nlohmann_json 3.12.0 REQUIRED) ... add_library(foo ...) ... @@ -1270,10 +1239,11 @@ Since CMake v3.11, be used to automatically download a release as a dependency at configure time. Example: + ```cmake include(FetchContent) -FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz) FetchContent_MakeAvailable(json) target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) @@ -1300,11 +1270,12 @@ add_library(foo ...) # import method target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` + ```cmake # thirdparty/CMakeLists.txt ... if(FOO_USE_EXTERNAL_JSON) - find_package(nlohmann_json 3.2.0 REQUIRED) + find_package(nlohmann_json 3.12.0 REQUIRED) else() set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(nlohmann_json) @@ -1316,51 +1287,24 @@ endif() ### Package Managers -:beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information. +Use your favorite [**package manager**](https://json.nlohmann.me/integration/package_managers/) to use the library. -If you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging. +-  [**Homebrew**](https://json.nlohmann.me/integration/package_managers/#homebrew) `nlohmann-json` +-  [**Meson**](https://json.nlohmann.me/integration/package_managers/#meson) `nlohmann_json` +-  [**Bazel**](https://json.nlohmann.me/integration/package_managers/#bazel) `nlohmann_json` +-  [**Conan**](https://json.nlohmann.me/integration/package_managers/#conan) `nlohmann_json` +-  [**Spack**](https://json.nlohmann.me/integration/package_managers/#spack) `nlohmann-json` +- [**Hunter**](https://json.nlohmann.me/integration/package_managers/#hunter) `nlohmann_json` +-  [**vcpkg**](https://json.nlohmann.me/integration/package_managers/#vcpkg) `nlohmann-json` +- [**cget**](https://json.nlohmann.me/integration/package_managers/#cget) `nlohmann/json` +-  [**Swift Package Manager**](https://json.nlohmann.me/integration/package_managers/#swift-package-manager) `nlohmann/json` +-  [**Nuget**](https://json.nlohmann.me/integration/package_managers/#nuget) `nlohmann.json` +-  [**Conda**](https://json.nlohmann.me/integration/package_managers/#conda) `nlohmann_json` +-  [**MacPorts**](https://json.nlohmann.me/integration/package_managers/#macports) `nlohmann-json` +-  [**cpm.cmake**](https://json.nlohmann.me/integration/package_managers/#cpmcmake) `gh:nlohmann/json` +-  [**xmake**](https://json.nlohmann.me/integration/package_managers/#xmake) `nlohmann_json` -The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly. - -If you are using [Bazel](https://bazel.build/) you can simply reference this repository using `http_archive` or `git_repository` and depend on `@nlohmann_json//:json`. - -If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages. - -If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. - -If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. - -If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example). - -If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. - -If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). - -If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). - -If you are using [Swift Package Manager](https://swift.org/package-manager/), you can use the library by adding a package dependency to this repository. And target dependency as `.product(name: "nlohmann-json", package: "json")`. - -If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please file issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). - -If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). - -If you are using [MSYS2](https://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. - -If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. - -If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). -Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages. - -If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. - -If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake: - -```cmake -CPMAddPackage( - NAME nlohmann_json - GITHUB_REPOSITORY nlohmann/json - VERSION 3.9.1) -``` +The library is part of many package managers. See the [**documentation**](https://json.nlohmann.me/integration/package_managers/) for detailed descriptions and examples. ### Pkg-config @@ -1370,20 +1314,13 @@ If you are using bare Makefiles, you can use `pkg-config` to generate the includ pkg-config nlohmann_json --cflags ``` -Users of the Meson build system will also be able to use a system-wide library, which will be found by `pkg-config`: - -```meson -json = dependency('nlohmann_json', required: true) -``` - - ## License - +OSI approved license The class is licensed under the [MIT License](https://opensource.org/licenses/MIT): -Copyright © 2013-2022 [Niels Lohmann](https://nlohmann.me) +Copyright © 2013-2025 [Niels Lohmann](https://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -1393,13 +1330,19 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I * * * -The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) +- The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) +- The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/) +- The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). +- The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). -The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/) +REUSE Software -The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). +The library is compliant to version 3.3 of the [**REUSE specification**](https://reuse.software): -The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). +- Every source file contains an SPDX copyright header. +- The full text of all licenses used in the repository can be found in the `LICENSES` folder. +- File `.reuse/dep5` contains an overview of all files' copyrights and licenses. +- Run `pipx run reuse lint` to verify the project's REUSE compliance and `pipx run reuse spdx` to generate a SPDX SBOM. ## Contact @@ -1415,7 +1358,7 @@ Only if your request would contain confidential information, please [send me an I deeply appreciate the help of the following people. - +GitHub avatars of the contributors 1. [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. 2. [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. @@ -1534,7 +1477,7 @@ I deeply appreciate the help of the following people. 115. [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. 116. [agrianius](https://github.com/agrianius) added code to use alternative string implementations. 117. [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. -118. [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com). +118. [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](https://cppreference.com). 119. [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. 120. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. 121. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. @@ -1763,10 +1706,47 @@ I deeply appreciate the help of the following people. 344. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager. 345. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake. 346. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened. +347. [Juan Carlos Arevalo Baeza](https://github.com/TheJCAB) fixed the enum conversion. +348. [alferov](https://github.com/ALF-ONE) fixed a version in the documentation. +349. [ss](https://github.com/serge-s) fixed the amalgamation call. +350. [AniketDhemare](https://github.com/AniketDhemare) fixed a version in the documentation. +351. [Philip Müller](https://github.com/philip-paul-mueller) fixed an example. +352. [Leila Shcheglova](https://github.com/LeilaShcheglova) fixed a warning in a test. +353. [Alex Prabhat Bara](https://github.com/alexprabhat99) fixed a function name in the documentation. +354. [laterlaugh](https://github.com/laterlaugh) fixed some typos. +355. [Yuanhao Jia](https://github.com/MrJia1997) fixed the GDB pretty printer. +356. [Fallen_Breath](https://github.com/Fallen-Breath) fixed an example for JSON Pointer. +357. [Nikhil Idiculla](https://github.com/tsnl) fixed some typos. +358. [Griffin Myers](https://github.com/gmyers18) updated the Natvis file. +359. [thetimr](https://github.com/thetimr) fixed a typo in the documentation. +360. [Balazs Erseki](https://github.com/zerocukor287) fixed a URL in the contribution guidelines. +361. [Niccolò Iardella](https://github.com/rotolof) added `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros. +362. [Borislav Stanimirov](https://github.com/iboB) allowed overriding the CMake target name. +363. [Captain Crutches](https://github.com/captaincrutches) made `iterator_proxy_value` a `std::forward_iterator`. +364. [Fredrik Sandhei](https://github.com/fsandhei) added type conversion support for `std::optional`. +365. [jh96](https://github.com/jordan-hoang) added exceptions when `nullptr` is passed to `parse`. +366. [Stuart Gorman](https://github.com/StuartGorman) fixed number parsing when `EINTR` set in `errno`. +367. [Dylan Baker](https://github.com/dcbaker) generated a pkg-config file that follows the pkg-config conventions. +368. [Tianyi Chen](https://github.com/TianyiChen) optimized the binary `get_number` implementation. +369. [peng-wang-cn](https://github.com/peng-wang-cn) added type conversion support for multidimensional arrays. +370. [Einars Netlis-Galejs](https://github.com/EinarsNG) added `ONLY_SERIALIZE` for `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros. +371. [Marcel](https://github.com/mering) removed `alwayslink=True` Bazel flag. +372. [Harinath Nampally](https://github.com/hnampally) added diagnostic positions to exceptions. +373. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) fixed `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` with an empty JSON instance. +374. [Michael Valladolid](https://github.com/codenut) added support for BSON uint64 serialization/deserialization. +375. [Nikhil](https://github.com/nikhilreddydev) updated the documentation. +376. [Nebojša Cvetković](https://github.com/nebkat) added support for BJDATA optimized binary array type. +377. [Sushrut Shringarputale](https://github.com/sushshring) added support for diagnostic positions. +378. [kimci86](https://github.com/kimci86) templated to `NLOHMANN_DEFINE_TYPE` macros to also support `ordered_json`. +379. [Richard Topchii](https://github.com/richardtop) added support for VisionOS in the Swift Package Manager. +380. [Robert Chisholm](https://github.com/Robadob) fixed a typo. +381. [zjyhjqs](https://github.com/zjyhjqs) added CPack support. +382. [bitFiedler](https://github.com/bitFiedler) made GDB pretty printer work with Python 3.8. +383. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) fixed a compiler warning. +384. [risa2000](https://github.com/risa2000) made `std::filesystem::path` conversion to/from UTF-8 encoded string explicit. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. - ## Used third-party tools The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! @@ -1777,16 +1757,15 @@ The library itself consists of a single header file licensed under the MIT licen - [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation - [**Clang**](https://clang.llvm.org) for compilation with code sanitizers - [**CMake**](https://cmake.org) for build automation -- [**Codacy**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) +- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis - [**doctest**](https://github.com/onqtam/doctest) for the unit tests -- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages - [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) - [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks - [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros -- [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create an HTML view +- [**lcov**](https://github.com/linux-test-project/lcov) to process coverage information and create an HTML view - [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz - [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site - [**MkDocs**](https://www.mkdocs.org) for the documentation site @@ -1794,12 +1773,6 @@ The library itself consists of a single header file licensed under the MIT licen - [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. - [**Valgrind**](https://valgrind.org) to check for correct memory management - -## Projects using JSON for Modern C++ - -The library is currently used in Apple macOS Sierra-Monterey and iOS 10-15. I am not sure what they are using the library for, but I am happy that it runs on so many devices. - - ## Notes ### Character encoding @@ -1821,11 +1794,11 @@ This library does not support comments by default. It does so for three reasons: 1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: - - > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. - - > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. - + + > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. + > + > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. + 3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. @@ -1836,6 +1809,8 @@ By default, the library does not preserve the **insertion order of object elemen If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). +See the [**documentation on object order**](https://json.nlohmann.me/features/object_order/) for more information. + ### Memory Release We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks. @@ -1847,21 +1822,21 @@ Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924). ### Further notes -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://json.nlohmann.me/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://json.nlohmann.me/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://json.nlohmann.me/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://json.nlohmann.me/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. See the [**documentation on runtime assertions**](https://json.nlohmann.me/features/assertions/) for more information. - As the exact number type is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. -- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824). +- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824). See the [**documentation of exceptions**](https://json.nlohmann.me/home/exceptions/) for more information. ## Execute unit tests To compile and run the tests, you need to execute -```sh -$ mkdir build -$ cd build -$ cmake .. -DJSON_BuildTests=On -$ cmake --build . -$ ctest --output-on-failure +```shell +mkdir build +cd build +cmake .. -DJSON_BuildTests=On +cmake --build . +ctest --output-on-failure ``` Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. @@ -1884,8 +1859,8 @@ json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::che In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. -Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. +Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. Furthermore, assertions must be switched off to ensure reproducible builds (see [discussion 4494](https://github.com/nlohmann/json/discussions/4494)). Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information. -As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then. +As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html) then. diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel deleted file mode 100644 index 2b2ae9dba..000000000 --- a/WORKSPACE.bazel +++ /dev/null @@ -1 +0,0 @@ -workspace(name = "nlohmann_json") diff --git a/cmake/ci.cmake b/cmake/ci.cmake index bbb2d4cb9..ef4c257b1 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -8,34 +8,24 @@ set(N 10) include(FindPython3) find_package(Python3 COMPONENTS Interpreter) -find_program(ASTYLE_TOOL NAMES astyle) -execute_process(COMMAND ${ASTYLE_TOOL} --version OUTPUT_VARIABLE ASTYLE_TOOL_VERSION ERROR_VARIABLE ASTYLE_TOOL_VERSION) -string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" ASTYLE_TOOL_VERSION "${ASTYLE_TOOL_VERSION}") -message(STATUS "🔖 Artistic Style ${ASTYLE_TOOL_VERSION} (${ASTYLE_TOOL})") - -find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++) +find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++) execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}") message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})") -find_program(CLANG_TIDY_TOOL NAMES clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy) +find_program(CLANG_TIDY_TOOL NAMES clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy) execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}") message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})") message(STATUS "🔖 CMake ${CMAKE_VERSION} (${CMAKE_COMMAND})") -find_program(CPPCHECK_TOOL NAMES cppcheck) -execute_process(COMMAND ${CPPCHECK_TOOL} --version OUTPUT_VARIABLE CPPCHECK_TOOL_VERSION ERROR_VARIABLE CPPCHECK_TOOL_VERSION) -string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CPPCHECK_TOOL_VERSION "${CPPCHECK_TOOL_VERSION}") -message(STATUS "🔖 Cppcheck ${CPPCHECK_TOOL_VERSION} (${CPPCHECK_TOOL})") - -find_program(GCC_TOOL NAMES g++-latest g++-HEAD g++-13 g++-12 g++-11 g++-10) +find_program(GCC_TOOL NAMES g++-latest g++-HEAD g++ g++-15 g++-14 g++-13 g++-12 g++-11 g++-10) execute_process(COMMAND ${GCC_TOOL} --version OUTPUT_VARIABLE GCC_TOOL_VERSION ERROR_VARIABLE GCC_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCC_TOOL_VERSION "${GCC_TOOL_VERSION}") message(STATUS "🔖 GCC ${GCC_TOOL_VERSION} (${GCC_TOOL})") -find_program(GCOV_TOOL NAMES gcov-HEAD gcov-11 gcov-10 gcov) +find_program(GCOV_TOOL NAMES gcov-HEAD gcov gcov-15 gcov-14 gcov-13 gcov-12 gcov-11 gcov-10) execute_process(COMMAND ${GCOV_TOOL} --version OUTPUT_VARIABLE GCOV_TOOL_VERSION ERROR_VARIABLE GCOV_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCOV_TOOL_VERSION "${GCOV_TOOL_VERSION}") message(STATUS "🔖 GCOV ${GCOV_TOOL_VERSION} (${GCOV_TOOL})") @@ -88,332 +78,8 @@ file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp) # Thorough check with recent compilers ############################################################################### -# Ignored Clang warnings: -# -Wno-c++98-compat The library targets C++11. -# -Wno-c++98-compat-pedantic The library targets C++11. -# -Wno-deprecated-declarations The library contains annotations for deprecated functions. -# -Wno-extra-semi-stmt The library uses std::assert which triggers this warning. -# -Wno-padded We do not care about padding warnings. -# -Wno-covered-switch-default All switches list all cases and a default case. -# -Wno-unsafe-buffer-usage Otherwise Doctest would not compile. -# -Wno-weak-vtables The library is header-only. -# -Wreserved-identifier See https://github.com/onqtam/doctest/issues/536. - -set(CLANG_CXXFLAGS - -Werror - -Weverything - -Wno-c++98-compat - -Wno-c++98-compat-pedantic - -Wno-deprecated-declarations - -Wno-extra-semi-stmt - -Wno-padded - -Wno-covered-switch-default - -Wno-unsafe-buffer-usage - -Wno-weak-vtables - -Wno-reserved-identifier -) - -# Warning flags determined for GCC 13.0 (experimental) with https://github.com/nlohmann/gcc_flags: -# Ignored GCC warnings: -# -Wno-abi-tag We do not care about ABI tags. -# -Wno-aggregate-return The library uses aggregate returns. -# -Wno-long-long The library uses the long long type to interface with system functions. -# -Wno-namespaces The library uses namespaces. -# -Wno-padded We do not care about padding warnings. -# -Wno-system-headers We do not care about warnings in system headers. -# -Wno-templates The library uses templates. - -set(GCC_CXXFLAGS - -pedantic - -Werror - --all-warnings - --extra-warnings - -W - -WNSObject-attribute - -Wno-abi-tag - -Waddress - -Waddress-of-packed-member - -Wno-aggregate-return - -Waggressive-loop-optimizations - -Waligned-new=all - -Wall - -Walloc-zero - -Walloca - -Wanalyzer-double-fclose - -Wanalyzer-double-free - -Wanalyzer-exposure-through-output-file - -Wanalyzer-file-leak - -Wanalyzer-free-of-non-heap - -Wanalyzer-malloc-leak - -Wanalyzer-mismatching-deallocation - -Wanalyzer-null-argument - -Wanalyzer-null-dereference - -Wanalyzer-possible-null-argument - -Wanalyzer-possible-null-dereference - -Wanalyzer-shift-count-negative - -Wanalyzer-shift-count-overflow - -Wanalyzer-stale-setjmp-buffer - -Wanalyzer-tainted-allocation-size - -Wanalyzer-tainted-array-index - -Wanalyzer-tainted-divisor - -Wanalyzer-tainted-offset - -Wanalyzer-tainted-size - -Wanalyzer-too-complex - -Wanalyzer-unsafe-call-within-signal-handler - -Wanalyzer-use-after-free - -Wanalyzer-use-of-pointer-in-stale-stack-frame - -Wanalyzer-use-of-uninitialized-value - -Wanalyzer-va-arg-type-mismatch - -Wanalyzer-va-list-exhausted - -Wanalyzer-va-list-leak - -Wanalyzer-va-list-use-after-va-end - -Wanalyzer-write-to-const - -Wanalyzer-write-to-string-literal - -Warith-conversion - -Warray-bounds=2 - -Warray-compare - -Warray-parameter=2 - -Wattribute-alias=2 - -Wattribute-warning - -Wattributes - -Wbool-compare - -Wbool-operation - -Wbuiltin-declaration-mismatch - -Wbuiltin-macro-redefined - -Wc++0x-compat - -Wc++11-compat - -Wc++11-extensions - -Wc++14-compat - -Wc++14-extensions - -Wc++17-compat - -Wc++17-extensions - -Wc++1z-compat - -Wc++20-compat - -Wc++20-extensions - -Wc++23-extensions - -Wc++2a-compat - -Wcannot-profile - -Wcast-align - -Wcast-align=strict - -Wcast-function-type - -Wcast-qual - -Wcatch-value=3 - -Wchar-subscripts - -Wclass-conversion - -Wclass-memaccess - -Wclobbered - -Wcomma-subscript - -Wcomment - -Wcomments - -Wconditionally-supported - -Wconversion - -Wconversion-null - -Wcoverage-invalid-line-number - -Wcoverage-mismatch - -Wcpp - -Wctad-maybe-unsupported - -Wctor-dtor-privacy - -Wdangling-else - -Wdangling-pointer=2 - -Wdate-time - -Wdelete-incomplete - -Wdelete-non-virtual-dtor - -Wdeprecated - -Wdeprecated-copy - -Wdeprecated-copy-dtor - -Wdeprecated-declarations - -Wdeprecated-enum-enum-conversion - -Wdeprecated-enum-float-conversion - -Wdisabled-optimization - -Wdiv-by-zero - -Wdouble-promotion - -Wduplicated-branches - -Wduplicated-cond - -Weffc++ - -Wempty-body - -Wendif-labels - -Wenum-compare - -Wenum-conversion - -Wexceptions - -Wexpansion-to-defined - -Wextra - -Wextra-semi - -Wfloat-conversion - -Wfloat-equal - -Wformat-diag - -Wformat-overflow=2 - -Wformat-signedness - -Wformat-truncation=2 - -Wformat=2 - -Wframe-address - -Wfree-nonheap-object - -Whsa - -Wif-not-aligned - -Wignored-attributes - -Wignored-qualifiers - -Wimplicit-fallthrough=5 - -Winaccessible-base - -Winfinite-recursion - -Winherited-variadic-ctor - -Winit-list-lifetime - -Winit-self - -Winline - -Wint-in-bool-context - -Wint-to-pointer-cast - -Winterference-size - -Winvalid-imported-macros - -Winvalid-memory-model - -Winvalid-offsetof - -Winvalid-pch - -Wliteral-suffix - -Wlogical-not-parentheses - -Wlogical-op - -Wno-long-long - -Wlto-type-mismatch - -Wmain - -Wmaybe-uninitialized - -Wmemset-elt-size - -Wmemset-transposed-args - -Wmisleading-indentation - -Wmismatched-dealloc - -Wmismatched-new-delete - -Wmismatched-tags - -Wmissing-attributes - -Wmissing-braces - -Wmissing-declarations - -Wmissing-field-initializers - -Wmissing-include-dirs - -Wmissing-profile - -Wmissing-requires - -Wmissing-template-keyword - -Wmultichar - -Wmultiple-inheritance - -Wmultistatement-macros - -Wno-namespaces - -Wnarrowing - -Wnoexcept - -Wnoexcept-type - -Wnon-template-friend - -Wnon-virtual-dtor - -Wnonnull - -Wnonnull-compare - -Wnormalized=nfkc - -Wnull-dereference - -Wodr - -Wold-style-cast - -Wopenacc-parallelism - -Wopenmp-simd - -Woverflow - -Woverlength-strings - -Woverloaded-virtual - -Wpacked - -Wpacked-bitfield-compat - -Wpacked-not-aligned - -Wno-padded - -Wparentheses - -Wpedantic - -Wpessimizing-move - -Wplacement-new=2 - -Wpmf-conversions - -Wpointer-arith - -Wpointer-compare - -Wpragmas - -Wprio-ctor-dtor - -Wpsabi - -Wrange-loop-construct - -Wredundant-decls - -Wredundant-move - -Wredundant-tags - -Wregister - -Wreorder - -Wrestrict - -Wreturn-local-addr - -Wreturn-type - -Wscalar-storage-order - -Wsequence-point - -Wshadow=compatible-local - -Wshadow=global - -Wshadow=local - -Wshift-count-negative - -Wshift-count-overflow - -Wshift-negative-value - -Wshift-overflow=2 - -Wsign-compare - -Wsign-conversion - -Wsign-promo - -Wsized-deallocation - -Wsizeof-array-argument - -Wsizeof-array-div - -Wsizeof-pointer-div - -Wsizeof-pointer-memaccess - -Wstack-protector - -Wstrict-aliasing=3 - -Wstrict-null-sentinel - -Wno-strict-overflow - -Wstring-compare - -Wstringop-overflow=4 - -Wstringop-overread - -Wstringop-truncation - -Wsubobject-linkage - -Wsuggest-attribute=cold - -Wsuggest-attribute=const - -Wsuggest-attribute=format - -Wsuggest-attribute=malloc - -Wsuggest-attribute=noreturn - -Wsuggest-attribute=pure - -Wsuggest-final-methods - -Wsuggest-final-types - -Wsuggest-override - -Wswitch - -Wswitch-bool - -Wswitch-default - -Wswitch-enum - -Wswitch-outside-range - -Wswitch-unreachable - -Wsync-nand - -Wsynth - -Wno-system-headers - -Wtautological-compare - -Wno-templates - -Wterminate - -Wtrampolines - -Wtrigraphs - -Wtrivial-auto-var-init - -Wtsan - -Wtype-limits - -Wundef - -Wuninitialized - -Wunknown-pragmas - -Wunreachable-code - -Wunsafe-loop-optimizations - -Wunused - -Wunused-but-set-parameter - -Wunused-but-set-variable - -Wunused-const-variable=2 - -Wunused-function - -Wunused-label - -Wunused-local-typedefs - -Wunused-macros - -Wunused-parameter - -Wunused-result - -Wunused-value - -Wunused-variable - -Wuse-after-free=3 - -Wuseless-cast - -Wvarargs - -Wvariadic-macros - -Wvector-operation-performance - -Wvexing-parse - -Wvirtual-inheritance - -Wvirtual-move-assign - -Wvla - -Wvla-parameter - -Wvolatile - -Wvolatile-register-var - -Wwrite-strings - -Wzero-as-null-pointer-constant - -Wzero-length-bounds -) +include(clang_flags) +include(gcc_flags) add_custom_target(ci_test_gcc COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} @@ -439,7 +105,7 @@ add_custom_target(ci_test_clang # Different C++ Standards. ############################################################################### -foreach(CXX_STANDARD 11 14 17 20 23) +foreach(CXX_STANDARD 11 14 17 20 23 26) add_custom_target(ci_test_gcc_cxx${CXX_STANDARD} COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja @@ -461,6 +127,19 @@ foreach(CXX_STANDARD 11 14 17 20 23) COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMENT "Compile and test with Clang for C++${CXX_STANDARD}" ) + + add_custom_target(ci_test_clang_libcxx_cxx${CXX_STANDARD} + COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS}" ${CMAKE_COMMAND} + -DCMAKE_BUILD_TYPE=Debug -GNinja + -DJSON_BuildTests=ON -DJSON_FastTests=ON + -DJSON_TestStandards=${CXX_STANDARD} + -DCMAKE_CXX_FLAGS="-stdlib=libc++" + -DCMAKE_EXE_LINKER_FLAGS="-lc++abi" + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} + COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure + COMMENT "Compile and test with Clang for C++${CXX_STANDARD} (libc++)" + ) endforeach() ############################################################################### @@ -505,6 +184,20 @@ add_custom_target(ci_test_diagnostics COMMENT "Compile and test with improved diagnostics enabled" ) +############################################################################### +# Enable diagnostic positions support. +############################################################################### + +add_custom_target(ci_test_diagnostic_positions + COMMAND ${CMAKE_COMMAND} + -DCMAKE_BUILD_TYPE=Debug -GNinja + -DJSON_BuildTests=ON -DJSON_Diagnostic_Positions=ON + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_diagnostic_positions + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_diagnostic_positions + COMMAND cd ${PROJECT_BINARY_DIR}/build_diagnostic_positions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure + COMMENT "Compile and test with diagnostic positions enabled" +) + ############################################################################### # Enable legacy discarded value comparison. ############################################################################### @@ -553,8 +246,8 @@ add_custom_target(ci_test_coverage COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_coverage32 COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage32 && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure - COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc lcov_branch_coverage=1 - COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc lcov_branch_coverage=1 + COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused + COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused COMMAND ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept @@ -581,8 +274,6 @@ add_custom_target(ci_test_clang_sanitizer # Check if header is amalgamated and sources are properly indented. ############################################################################### -set(ASTYLE_FLAGS --style=allman --indent=spaces=4 --indent-modifiers --indent-switches --indent-preproc-block --indent-preproc-define --indent-col1-comments --pad-oper --pad-header --align-pointer=type --align-reference=type --add-brackets --convert-tabs --close-templates --lineend=linux --preserve-date --formatted) - file(GLOB_RECURSE INDENT_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp ${PROJECT_SOURCE_DIR}/tests/src/*.cpp @@ -598,14 +289,18 @@ add_custom_target(ci_test_amalgamation COMMAND cp ${include_dir}/json.hpp ${include_dir}/json.hpp~ COMMAND cp ${include_dir}/json_fwd.hpp ${include_dir}/json_fwd.hpp~ + COMMAND ${Python3_EXECUTABLE} -mvenv venv_astyle + COMMAND venv_astyle/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/tools/astyle/requirements.txt + COMMAND venv_astyle/bin/astyle --version + COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s . COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s . - COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} --suffix=none --quiet ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp + COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp COMMAND diff ${include_dir}/json_fwd.hpp~ ${include_dir}/json_fwd.hpp - COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} ${INDENT_FILES} + COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES} COMMAND for FILE in `find . -name '*.orig'`\; do false \; done WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} @@ -617,7 +312,7 @@ add_custom_target(ci_test_amalgamation ############################################################################### add_custom_target(ci_test_single_header - COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_MultipleHeaders=OFF -DJSON_FastTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_single_header @@ -660,7 +355,16 @@ add_custom_target(ci_clang_analyze ############################################################################### add_custom_target(ci_cppcheck - COMMAND ${CPPCHECK_TOOL} --enable=warning --suppress=missingReturn --inline-suppr --inconclusive --force --std=c++11 ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp --error-exitcode=1 + COMMAND mkdir -p cppcheck + COMMAND clang -dM -E -x c++ -std=c++11 ${CMAKE_SOURCE_DIR}/include/nlohmann/thirdparty/hedley/hedley.hpp > default_defines.hpp 2> /dev/null + COMMAND ${Python3_EXECUTABLE} -mvenv venv_cppcheck + COMMAND venv_cppcheck/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/cmake/requirements/requirements-cppcheck.txt + COMMAND venv_cppcheck/bin/cppcheck --enable=warning --check-level=exhaustive --inline-suppr --inconclusive --force + --std=c++11 ${PROJECT_SOURCE_DIR}/include/nlohmann/json.hpp -I ${CMAKE_SOURCE_DIR}/include + --error-exitcode=1 --relative-paths=${PROJECT_SOURCE_DIR} -j ${N} --include=default_defines.hpp + --cppcheck-build-dir=cppcheck --check-level=exhaustive + -UJSON_CATCH_USER -UJSON_TRY_USER -UJSON_ASSERT -UJSON_INTERNAL_CATCH -UJSON_THROW + -DJSON_HAS_CPP_11 -UJSON_HAS_CPP_14 -UJSON_HAS_CPP_17 -UJSON_HAS_CPP_20 -UJSON_HAS_THREE_WAY_COMPARISON COMMENT "Check code with Cppcheck" ) @@ -670,7 +374,7 @@ add_custom_target(ci_cppcheck add_custom_target(ci_cpplint COMMAND ${Python3_EXECUTABLE} -mvenv venv_cpplint - COMMAND venv_cpplint/bin/pip3 --quiet install cpplint + COMMAND venv_cpplint/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/cmake/requirements/requirements-cpplint.txt COMMAND venv_cpplint/bin/cpplint --filter=-whitespace,-legal,-runtime/references,-runtime/explicit,-runtime/indentation_namespace,-readability/casting,-readability/nolint --quiet --recursive ${SRC_FILES} COMMENT "Check code with cpplint" WORKING_DIRECTORY ${PROJECT_BINARY_DIR} @@ -837,6 +541,11 @@ add_custom_target(ci_benchmarks # CMake flags ############################################################################### +# we test the project with different CMake versions: +# - CMake 3.5 (the earliest supported) +# - CMake 3.31.6 (the latest 3.x release) +# - CMake 4.0.0 (the latest release) + function(ci_get_cmake version var) set(${var} ${PROJECT_BINARY_DIR}/cmake-${version}/bin/cmake) add_custom_command( @@ -844,26 +553,30 @@ function(ci_get_cmake version var) COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz COMMAND tar xfz cmake-${version}.tar.gz COMMAND rm cmake-${version}.tar.gz - COMMAND ${CMAKE_COMMAND} -S cmake-${version} -B cmake-${version} - COMMAND ${CMAKE_COMMAND} --build cmake-${version} --parallel 10 + # -DCMAKE_POLICY_VERSION_MINIMUM=3.5 required to compile older CMake versions with CMake 4.0.0 + COMMAND cmake -S cmake-${version} -B cmake-${version} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + COMMAND cmake --build cmake-${version} --parallel 10 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} COMMENT "Download CMake ${version}" ) set(${var} ${${var}} PARENT_SCOPE) endfunction() -ci_get_cmake(3.1.0 CMAKE_3_1_0_BINARY) -ci_get_cmake(3.13.0 CMAKE_3_13_0_BINARY) +ci_get_cmake(3.5.0 CMAKE_3_5_0_BINARY) +ci_get_cmake(3.31.6 CMAKE_3_31_6_BINARY) +ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY) -set(JSON_CMAKE_FLAGS_3_1_0 JSON_Diagnostics JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization +# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0 +set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind) -set(JSON_CMAKE_FLAGS_3_13_0 JSON_BuildTests) +set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_31_6}) +set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) function(ci_add_cmake_flags_targets flag min_version) string(TOLOWER "ci_cmake_flag_${flag}" flag_target) string(REPLACE . _ min_version_var ${min_version}) set(cmake_binary ${CMAKE_${min_version_var}_BINARY}) - add_custom_target(${flag_target} + add_custom_target(${flag_target}_${min_version}_2 COMMENT "Check CMake flag ${flag} (CMake ${CMAKE_VERSION})" COMMAND ${CMAKE_COMMAND} -Werror=dev @@ -883,12 +596,16 @@ function(ci_add_cmake_flags_targets flag min_version) set(JSON_CMAKE_FLAG_BUILD_DIRS ${JSON_CMAKE_FLAG_BUILD_DIRS} PARENT_SCOPE) endfunction() -foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_1_0}) - ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.1.0) +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_5_0}) + ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.5.0) endforeach() -foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_13_0}) - ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.13.0) +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_31_6}) + ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.31.6) +endforeach() + +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_4_0_0}) + ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 4.0.0) endforeach() add_custom_target(ci_cmake_flags @@ -900,7 +617,7 @@ add_custom_target(ci_cmake_flags # Use more installed compilers. ############################################################################### -foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 g++-11 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12 clang++-13 clang++-14 clang++-15 clang++-16 clang++-17) +foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 g++-11 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12 clang++-13 clang++-14 clang++-15 clang++-16 clang++-17 clang++-18 clang++-19 clang++-20) find_program(COMPILER_TOOL NAMES ${COMPILER}) if (COMPILER_TOOL) unset(ADDITIONAL_FLAGS) @@ -957,6 +674,17 @@ add_custom_target(ci_icpc COMMENT "Compile and test with ICPC" ) +############################################################################### +# REUSE +############################################################################### + +add_custom_target(ci_reuse_compliance + COMMAND ${Python3_EXECUTABLE} -mvenv venv_reuse + COMMAND venv_reuse/bin/pip3 --quiet install -r ${PROJECT_SOURCE_DIR}/cmake/requirements/requirements-reuse.txt + COMMAND venv_reuse/bin/reuse --root ${PROJECT_SOURCE_DIR} lint + COMMENT "Check REUSE specification compliance" +) + ############################################################################### # test documentation ############################################################################### @@ -967,10 +695,12 @@ add_custom_target(ci_test_examples COMMENT "Check that all examples compile and create the desired output" ) -add_custom_target(ci_test_api_documentation - COMMAND ${Python3_EXECUTABLE} scripts/check_structure.py +add_custom_target(ci_test_build_documentation + COMMAND ${Python3_EXECUTABLE} -mvenv venv + COMMAND venv/bin/pip3 --quiet install -r requirements.txt + COMMAND make build WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs/mkdocs - COMMENT "Lint the API documentation" + COMMENT "Build the documentation" ) ############################################################################### @@ -978,6 +708,6 @@ add_custom_target(ci_test_api_documentation ############################################################################### add_custom_target(ci_clean - COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* cmake-3.1.0-Darwin64 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries} + COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* cmake-3.5.0-Darwin64 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries} COMMENT "Clean generated directories" ) diff --git a/cmake/clang_flags.cmake b/cmake/clang_flags.cmake new file mode 100644 index 000000000..7c1e9cc64 --- /dev/null +++ b/cmake/clang_flags.cmake @@ -0,0 +1,20 @@ +# Ignored Clang warnings: +# -Wno-c++98-compat The library targets C++11. +# -Wno-c++98-compat-pedantic The library targets C++11. +# -Wno-deprecated-declarations The library contains annotations for deprecated functions. +# -Wno-extra-semi-stmt The library uses assert which triggers this warning. +# -Wno-padded We do not care about padding warnings. +# -Wno-covered-switch-default All switches list all cases and a default case. +# -Wno-unsafe-buffer-usage Otherwise Doctest would not compile. + +set(CLANG_CXXFLAGS + -Werror + -Weverything + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-deprecated-declarations + -Wno-extra-semi-stmt + -Wno-padded + -Wno-covered-switch-default + -Wno-unsafe-buffer-usage +) diff --git a/cmake/gcc_flags.cmake b/cmake/gcc_flags.cmake new file mode 100644 index 000000000..848630f33 --- /dev/null +++ b/cmake/gcc_flags.cmake @@ -0,0 +1,348 @@ +# Warning flags determined for GCC 14.2.0 with https://github.com/nlohmann/gcc_flags: +# Ignored GCC warnings: +# -Wno-abi-tag We do not care about ABI tags. +# -Wno-aggregate-return The library uses aggregate returns. +# -Wno-long-long The library uses the long long type to interface with system functions. +# -Wno-namespaces The library uses namespaces. +# -Wno-nrvo Doctest triggers this warning. +# -Wno-padded We do not care about padding warnings. +# -Wno-system-headers We do not care about warnings in system headers. +# -Wno-templates The library uses templates. + +set(GCC_CXXFLAGS + -pedantic + -Werror + --all-warnings + --extra-warnings + -W + -WNSObject-attribute + -Wno-abi-tag + -Waddress + -Waddress-of-packed-member + -Wno-aggregate-return + -Waggressive-loop-optimizations + -Waligned-new=all + -Wall + -Walloc-size + -Walloc-zero + -Walloca + -Wanalyzer-allocation-size + -Wanalyzer-deref-before-check + -Wanalyzer-double-fclose + -Wanalyzer-double-free + -Wanalyzer-exposure-through-output-file + -Wanalyzer-exposure-through-uninit-copy + -Wanalyzer-fd-access-mode-mismatch + -Wanalyzer-fd-double-close + -Wanalyzer-fd-leak + -Wanalyzer-fd-phase-mismatch + -Wanalyzer-fd-type-mismatch + -Wanalyzer-fd-use-after-close + -Wanalyzer-fd-use-without-check + -Wanalyzer-file-leak + -Wanalyzer-free-of-non-heap + -Wanalyzer-imprecise-fp-arithmetic + -Wanalyzer-infinite-loop + -Wanalyzer-infinite-recursion + -Wanalyzer-jump-through-null + -Wanalyzer-malloc-leak + -Wanalyzer-mismatching-deallocation + -Wanalyzer-null-argument + -Wanalyzer-null-dereference + -Wanalyzer-out-of-bounds + -Wanalyzer-overlapping-buffers + -Wanalyzer-possible-null-argument + -Wanalyzer-possible-null-dereference + -Wanalyzer-putenv-of-auto-var + -Wanalyzer-shift-count-negative + -Wanalyzer-shift-count-overflow + -Wanalyzer-stale-setjmp-buffer + -Wanalyzer-symbol-too-complex + -Wanalyzer-tainted-allocation-size + -Wanalyzer-tainted-array-index + -Wanalyzer-tainted-assertion + -Wanalyzer-tainted-divisor + -Wanalyzer-tainted-offset + -Wanalyzer-tainted-size + -Wanalyzer-too-complex + -Wanalyzer-undefined-behavior-strtok + -Wanalyzer-unsafe-call-within-signal-handler + -Wanalyzer-use-after-free + -Wanalyzer-use-of-pointer-in-stale-stack-frame + -Wanalyzer-use-of-uninitialized-value + -Wanalyzer-va-arg-type-mismatch + -Wanalyzer-va-list-exhausted + -Wanalyzer-va-list-leak + -Wanalyzer-va-list-use-after-va-end + -Wanalyzer-write-to-const + -Wanalyzer-write-to-string-literal + -Warith-conversion + -Warray-bounds=2 + -Warray-compare + -Warray-parameter=2 + -Wattribute-alias=2 + -Wattribute-warning + -Wattributes + -Wbool-compare + -Wbool-operation + -Wbuiltin-declaration-mismatch + -Wbuiltin-macro-redefined + -Wc++0x-compat + -Wc++11-compat + -Wc++11-extensions + -Wc++14-compat + -Wc++14-extensions + -Wc++17-compat + -Wc++17-extensions + -Wc++1z-compat + -Wc++20-compat + -Wc++20-extensions + -Wc++23-extensions + -Wc++26-extensions + -Wc++2a-compat + -Wcalloc-transposed-args + -Wcannot-profile + -Wcast-align + -Wcast-align=strict + -Wcast-function-type + -Wcast-qual + -Wcast-user-defined + -Wcatch-value=3 + -Wchanges-meaning + -Wchar-subscripts + -Wclass-conversion + -Wclass-memaccess + -Wclobbered + -Wcomma-subscript + -Wcomment + -Wcomments + -Wcomplain-wrong-lang + -Wconditionally-supported + -Wconversion + -Wconversion-null + -Wcoverage-invalid-line-number + -Wcoverage-mismatch + -Wcoverage-too-many-conditions + -Wcpp + -Wctad-maybe-unsupported + -Wctor-dtor-privacy + -Wdangling-else + -Wdangling-pointer=2 + -Wdangling-reference + -Wdate-time + -Wdelete-incomplete + -Wdelete-non-virtual-dtor + -Wdeprecated + -Wdeprecated-copy + -Wdeprecated-copy-dtor + -Wdeprecated-declarations + -Wdeprecated-enum-enum-conversion + -Wdeprecated-enum-float-conversion + -Wdisabled-optimization + -Wdiv-by-zero + -Wdouble-promotion + -Wduplicated-branches + -Wduplicated-cond + -Weffc++ + -Welaborated-enum-base + -Wempty-body + -Wendif-labels + -Wenum-compare + -Wenum-conversion + -Wexceptions + -Wexpansion-to-defined + -Wextra + -Wextra-semi + -Wflex-array-member-not-at-end + -Wfloat-conversion + -Wfloat-equal + -Wformat -Wformat-contains-nul + -Wformat -Wformat-extra-args + -Wformat -Wformat-nonliteral + -Wformat -Wformat-security + -Wformat -Wformat-y2k + -Wformat -Wformat-zero-length + -Wformat-diag + -Wformat-overflow=2 + -Wformat-signedness + -Wformat-truncation=2 + -Wformat=2 + -Wframe-address + -Wfree-nonheap-object + -Wglobal-module + -Whardened + -Whsa + -Wif-not-aligned + -Wignored-attributes + -Wignored-qualifiers + -Wimplicit-fallthrough=5 + -Winaccessible-base + -Winfinite-recursion + -Winherited-variadic-ctor + -Winit-list-lifetime + -Winit-self + -Winline + -Wint-in-bool-context + -Wint-to-pointer-cast + -Winterference-size + -Winvalid-constexpr + -Winvalid-imported-macros + -Winvalid-memory-model + -Winvalid-offsetof + -Winvalid-pch + -Winvalid-utf8 + -Wliteral-suffix + -Wlogical-not-parentheses + -Wlogical-op + -Wno-long-long + -Wlto-type-mismatch + -Wmain + -Wmaybe-uninitialized + -Wmemset-elt-size + -Wmemset-transposed-args + -Wmisleading-indentation + -Wmismatched-dealloc + -Wmismatched-new-delete + -Wmismatched-tags + -Wmissing-attributes + -Wmissing-braces + -Wmissing-declarations + -Wmissing-field-initializers + -Wmissing-include-dirs + -Wmissing-profile + -Wmissing-requires + -Wmissing-template-keyword + -Wmultichar + -Wmultiple-inheritance + -Wmultistatement-macros + -Wno-namespaces + -Wnarrowing + -Wnoexcept + -Wnoexcept-type + -Wnon-template-friend + -Wnon-virtual-dtor + -Wnonnull + -Wnonnull-compare + -Wnormalized=nfkc + -Wno-nrvo + -Wnull-dereference + -Wodr + -Wold-style-cast + -Wopenacc-parallelism + -Wopenmp + -Wopenmp-simd + -Woverflow + -Woverlength-strings + -Woverloaded-virtual=2 + -Wpacked + -Wpacked-bitfield-compat + -Wpacked-not-aligned + -Wno-padded + -Wparentheses + -Wpedantic + -Wpessimizing-move + -Wplacement-new=2 + -Wpmf-conversions + -Wpointer-arith + -Wpointer-compare + -Wpragmas + -Wprio-ctor-dtor + -Wpsabi + -Wrange-loop-construct + -Wredundant-decls + -Wredundant-move + -Wredundant-tags + -Wregister + -Wreorder + -Wrestrict + -Wreturn-local-addr + -Wreturn-type + -Wscalar-storage-order + -Wself-move + -Wsequence-point + -Wshadow=compatible-local + -Wshadow=global + -Wshadow=local + -Wshift-count-negative + -Wshift-count-overflow + -Wshift-negative-value + -Wshift-overflow=2 + -Wsign-compare + -Wsign-conversion + -Wsign-promo + -Wsized-deallocation + -Wsizeof-array-argument + -Wsizeof-array-div + -Wsizeof-pointer-div + -Wsizeof-pointer-memaccess + -Wstack-protector + -Wstrict-aliasing=3 + -Wstrict-null-sentinel + -Wstrict-overflow + -Wstring-compare + -Wstringop-overflow=4 + -Wstringop-overread + -Wstringop-truncation + -Wsubobject-linkage + -Wsuggest-attribute=cold + -Wsuggest-attribute=const + -Wsuggest-attribute=format + -Wsuggest-attribute=malloc + -Wsuggest-attribute=noreturn + -Wsuggest-attribute=pure + -Wsuggest-attribute=returns_nonnull + -Wsuggest-final-methods + -Wsuggest-final-types + -Wsuggest-override + -Wswitch + -Wswitch-bool + -Wswitch-default + -Wswitch-enum + -Wswitch-outside-range + -Wswitch-unreachable + -Wsync-nand + -Wsynth + -Wno-system-headers + -Wtautological-compare + -Wno-templates + -Wterminate + -Wtrampolines + -Wtrigraphs + -Wtrivial-auto-var-init + -Wtsan + -Wtype-limits + -Wundef + -Wunicode + -Wuninitialized + -Wunknown-pragmas + -Wunreachable-code + -Wunsafe-loop-optimizations + -Wunused + -Wunused-but-set-parameter + -Wunused-but-set-variable + -Wunused-const-variable=2 + -Wunused-function + -Wunused-label + -Wunused-local-typedefs + -Wunused-macros + -Wunused-parameter + -Wunused-result + -Wunused-value + -Wunused-variable + -Wuse-after-free=3 + -Wuseless-cast + -Wvarargs + -Wvariadic-macros + -Wvector-operation-performance + -Wvexing-parse + -Wvirtual-inheritance + -Wvirtual-move-assign + -Wvla + -Wvla-parameter + -Wvolatile + -Wvolatile-register-var + -Wwrite-strings + -Wxor-used-as-pow + -Wzero-as-null-pointer-constant + -Wzero-length-bounds +) diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in index d36317f09..21a91a3cf 100644 --- a/cmake/pkg-config.pc.in +++ b/cmake/pkg-config.pc.in @@ -1,4 +1,7 @@ -Name: ${PROJECT_NAME} +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@ Description: JSON for Modern C++ -Version: ${PROJECT_VERSION} -Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR} +Version: @PROJECT_VERSION@ +Cflags: -I${includedir} diff --git a/cmake/requirements/requirements-cppcheck.txt b/cmake/requirements/requirements-cppcheck.txt new file mode 100644 index 000000000..9119ad7b6 --- /dev/null +++ b/cmake/requirements/requirements-cppcheck.txt @@ -0,0 +1 @@ +cppcheck==1.5.0 diff --git a/cmake/requirements/requirements-cpplint.txt b/cmake/requirements/requirements-cpplint.txt new file mode 100644 index 000000000..abb438cc5 --- /dev/null +++ b/cmake/requirements/requirements-cpplint.txt @@ -0,0 +1 @@ +cpplint==2.0.1 diff --git a/cmake/requirements/requirements-reuse.txt b/cmake/requirements/requirements-reuse.txt new file mode 100644 index 000000000..e7677662c --- /dev/null +++ b/cmake/requirements/requirements-reuse.txt @@ -0,0 +1 @@ +reuse==5.0.2 diff --git a/docs/Makefile b/docs/Makefile index 35c30daef..0412fb90a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -7,7 +7,7 @@ all: create_output ########################################################################## # where are the example cpp files -EXAMPLES = $(wildcard examples/*.cpp) +EXAMPLES = $(wildcard mkdocs/docs/examples/*.cpp) cxx_standard = $(lastword c++11 $(filter c++%, $(subst ., ,$1))) @@ -37,9 +37,8 @@ check_output: $(EXAMPLES:.cpp=.test) # check output of all stand-alone example files (exclude files with platform-dependent output.) # This target is used in the CI (ci_test_documentation). -check_output_portable: $(filter-out examples/meta.test examples/max_size.test examples/std_hash.test examples/basic_json__CompatibleType.test,$(EXAMPLES:.cpp=.test)) +check_output_portable: $(filter-out mkdocs/docs/examples/meta.test mkdocs/docs/examples/max_size.test mkdocs/docs/examples/std_hash.test mkdocs/docs/examples/basic_json__CompatibleType.test,$(EXAMPLES:.cpp=.test)) clean: rm -fr $(EXAMPLES:.cpp=) $(MAKE) clean -C docset - $(MAKE) clean -C mkdocs diff --git a/docs/avatars.png b/docs/avatars.png index 25429f34a..c6efa0c1f 100644 Binary files a/docs/avatars.png and b/docs/avatars.png differ diff --git a/docs/docset/Makefile b/docs/docset/Makefile index eb1cfd38c..9f4363462 100644 --- a/docs/docset/Makefile +++ b/docs/docset/Makefile @@ -16,6 +16,7 @@ JSON_for_Modern_C++.docset: Info.plist docSet.dsidx cp icon*.png JSON_for_Modern_C++.docset cp Info.plist JSON_for_Modern_C++.docset/Contents # build and copy documentation + $(MAKE) install_venv -C ../mkdocs $(MAKE) build -C ../mkdocs cp -r ../mkdocs/site/* JSON_for_Modern_C++.docset/Contents/Resources/Documents # patch CSS to hide navigation items diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index ea6b4f285..38b203d38 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -38,6 +38,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace', 'Method INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace_back', 'Method', 'api/basic_json/emplace_back/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::empty', 'Method', 'api/basic_json/empty/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end', 'Method', 'api/basic_json/end/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end_pos', 'Method', 'api/basic_json/end_pos/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::erase', 'Method', 'api/basic_json/erase/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::error_handler_t', 'Enum', 'api/basic_json/error_handler_t/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::exception', 'Class', 'api/basic_json/exception/index.html'); @@ -72,6 +73,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_primitive', 'M INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_string', 'Method', 'api/basic_json/is_string/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_structured', 'Method', 'api/basic_json/is_structured/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::items', 'Method', 'api/basic_json/items/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_base_class_t', 'Type', 'api/basic_json/json_base_class_t/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_serializer', 'Class', 'api/basic_json/json_serializer/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::max_size', 'Method', 'api/basic_json/max_size/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::merge_patch', 'Method', 'api/basic_json/merge_patch/index.html'); @@ -107,6 +109,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rbegin', 'Method' INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rend', 'Method', 'api/basic_json/rend/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::sax_parse', 'Function', 'api/basic_json/sax_parse/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::size', 'Method', 'api/basic_json/size/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::start_pos', 'Method', 'api/basic_json/start_pos/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::string_t', 'Type', 'api/basic_json/string_t/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::swap', 'Method', 'api/basic_json/swap/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type', 'Method', 'api/basic_json/type/index.html'); @@ -175,6 +178,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Element Access', 'Guide', 'fe INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Access with default value: value', 'Guide', 'features/element_access/default_value/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Checked access: at', 'Guide', 'features/element_access/checked_access/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Unchecked access: operator[]', 'Guide', 'features/element_access/unchecked_access/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('Exceptions', 'Guide', 'home/exceptions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Migration Guide', 'Guide', 'integration/migration_guide/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Integration: CMake', 'Guide', 'integration/cmake/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Header only', 'Guide', 'integration/index.html'); @@ -201,6 +205,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', ' INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html'); @@ -209,6 +214,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_20', 'Macro', 'a INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_EXPERIMENTAL_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_RANGES', 'Macro', 'api/macros/json_has_ranges/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STATIC_RTTI', 'Macro', 'api/macros/json_has_static_rtti/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_THREE_WAY_COMPARISON', 'Macro', 'api/macros/json_has_three_way_comparison/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NOEXCEPTION', 'Macro', 'api/macros/json_noexception/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_IO', 'Macro', 'api/macros/json_no_io/index.html'); @@ -220,6 +226,10 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html'); diff --git a/docs/docset/docset.json b/docs/docset/docset.json index bc08d283d..15cf4a7b1 100644 --- a/docs/docset/docset.json +++ b/docs/docset/docset.json @@ -1,6 +1,6 @@ { "name": "JSON for Modern C++", - "version": "3.11.3", + "version": "3.12.0", "archive": "JSON_for_Modern_C++.tgz", "author": { "name": "Niels Lohmann", diff --git a/docs/examples/nlohmann_json_namespace.output b/docs/examples/nlohmann_json_namespace.output deleted file mode 100644 index 5565deafd..000000000 --- a/docs/examples/nlohmann_json_namespace.output +++ /dev/null @@ -1 +0,0 @@ -nlohmann::json_abi_v3_11_3 diff --git a/docs/examples/nlohmann_json_version.output b/docs/examples/nlohmann_json_version.output deleted file mode 100644 index 75dbe8478..000000000 --- a/docs/examples/nlohmann_json_version.output +++ /dev/null @@ -1 +0,0 @@ -JSON for Modern C++ version 3.11.3 diff --git a/docs/json.gif b/docs/json.gif index 8b86b0375..c70837972 100644 Binary files a/docs/json.gif and b/docs/json.gif differ diff --git a/docs/mkdocs/Makefile b/docs/mkdocs/Makefile index d3356b820..8c72b0e80 100644 --- a/docs/mkdocs/Makefile +++ b/docs/mkdocs/Makefile @@ -1,37 +1,45 @@ # serve the site locally -serve: prepare_files style_check +serve: style_check venv/bin/mkdocs serve -serve_dirty: prepare_files style_check +serve_dirty: style_check venv/bin/mkdocs serve --dirtyreload -build: prepare_files style_check +# This target is used in the CI (ci_test_build_documentation). +# This target is used by the docset Makefile. +build: style_check venv/bin/mkdocs build -# create files that are not versioned inside the mkdocs folder (images, examples) -prepare_files: clean - mkdir docs/examples - cp -r ../json.gif docs/images - cp -r ../examples/*.cpp ../examples/*.output docs/examples - style_check: - @cd docs ; python3 ../scripts/check_structure.py + @cd docs ; ../venv/bin/python3 ../scripts/check_structure.py -# clean subfolders -clean: - rm -fr docs/images/json.gif docs/examples +# check the links in the documentation files in docs/mkdocs +link_check: + ENABLED_HTMLPROOFER=true venv/bin/mkdocs build + +# check the links in all other Markdown files +link_check_markdowns: + npx markdown-link-check --progress --alive 200,429 ../../README.md ../../FILES.md ../../.github/*.md # publish site to GitHub pages (not working in GitHub Actions; need special action) -publish: prepare_files +publish: venv/bin/mkdocs gh-deploy --clean --force # install a Python virtual environment +# This target is used by the docset Makefile. install_venv: requirements.txt python3 -mvenv venv venv/bin/pip install --upgrade pip - venv/bin/pip install wheel venv/bin/pip install -r requirements.txt # uninstall the virtual environment -uninstall_venv: clean +uninstall_venv: rm -fr venv + +update_requirements: + rm -fr venv_small + python3 -mvenv venv_small + venv_small/bin/pip3 install pur + venv_small/bin/pur -r requirements.txt + rm -fr venv_small venv + make install_venv diff --git a/docs/mkdocs/docs/api/basic_json/accept.md b/docs/mkdocs/docs/api/basic_json/accept.md index 1c806e82f..152069846 100644 --- a/docs/mkdocs/docs/api/basic_json/accept.md +++ b/docs/mkdocs/docs/api/basic_json/accept.md @@ -17,10 +17,10 @@ Checks whether the input is valid JSON. 1. Reads from a compatible input. 2. Reads from a pair of character iterators - The value_type of the iterator must be an integral type with size of 1, 2 or 4 bytes, which will be interpreted - respectively as UTF-8, UTF-16 and UTF-32. + The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted + respectively as UTF-8, UTF-16, and UTF-32. -Unlike the [`parse`](parse.md) function, this function neither throws an exception in case of invalid JSON input +Unlike the [`parse()`](parse.md) function, this function neither throws an exception in case of invalid JSON input (i.e., a parse error) nor creates diagnostic information. ## Template parameters @@ -29,9 +29,9 @@ Unlike the [`parse`](parse.md) function, this function neither throws an excepti : A compatible input, for instance: - an `std::istream` object - - a `FILE` pointer (must not be null) + - a `#!c FILE` pointer (throws if null) - a C-style array of characters - - a pointer to a null-terminated string of single byte characters + - a pointer to a null-terminated string of single byte characters (throws if null) - a `std::string` - an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators. @@ -51,10 +51,10 @@ Unlike the [`parse`](parse.md) function, this function neither throws an excepti (`#!cpp false`); (optional, `#!cpp false` by default) `first` (in) -: iterator to start of character range +: iterator to the start of the character range `last` (in) -: iterator to end of character range +: iterator to the end of the character range ## Return value @@ -64,18 +64,17 @@ Whether the input is valid JSON. Strong guarantee: if an exception is thrown, there are no changes in the JSON value. +## Exceptions + +Throws [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) in case of an empty input like a null `#!c FILE*` or `#!c char*` pointer. + ## Complexity Linear in the length of the input. The parser is a predictive LL(1) parser. ## Notes -(1) A UTF-8 byte order mark is silently ignored. - -!!! danger "Runtime assertion" - - The precondition that a passed `#!cpp FILE` pointer must not be null is enforced with a - [runtime assertion](../../features/assertions.md). +A UTF-8 byte order mark is silently ignored. ## Examples @@ -102,6 +101,7 @@ Linear in the length of the input. The parser is a predictive LL(1) parser. - Added in version 3.0.0. - Ignoring comments via `ignore_comments` added in version 3.9.0. +- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. !!! warning "Deprecation" diff --git a/docs/mkdocs/docs/api/basic_json/at.md b/docs/mkdocs/docs/api/basic_json/at.md index 5e9504508..800b46eb3 100644 --- a/docs/mkdocs/docs/api/basic_json/at.md +++ b/docs/mkdocs/docs/api/basic_json/at.md @@ -59,29 +59,29 @@ Strong exception safety: if an exception occurs, the original value stays intact 1. The function can throw the following exceptions: - Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the JSON value is not an array; - in this case, calling `at` with an index makes no sense. See example below. + in this case, calling `at` with an index makes no sense. See the example below. - Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if the index `idx` is out of - range of the array; that is, `idx >= size()`. See example below. + range of the array; that is, `idx >= size()`. See the example below. 2. The function can throw the following exceptions: - Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the JSON value is not an object; - in this case, calling `at` with a key makes no sense. See example below. + in this case, calling `at` with a key makes no sense. See the example below. - Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the key `key` is not - stored in the object; that is, `find(key) == end()`. See example below. + stored in the object; that is, `find(key) == end()`. See the example below. 3. See 2. 4. The function can throw the following exceptions: - Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed - JSON pointer `ptr` begins with '0'. See example below. + JSON pointer `ptr` begins with '0'. See the example below. - Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed - JSON pointer `ptr` is not a number. See example below. + JSON pointer `ptr` is not a number. See the example below. - Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if an array index in the passed - JSON pointer `ptr` is out of range. See example below. + JSON pointer `ptr` is out of range. See the example below. - Throws [`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402) if the array index '-' is used in the passed JSON pointer `ptr`. As `at` provides checked access (and no elements are implicitly inserted), the - index '-' is always invalid. See example below. + index '-' is always invalid. See the example below. - Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the JSON pointer describes a - key of an object which cannot be found. See example below. + key of an object which cannot be found. See the example below. - Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if the JSON pointer `ptr` can - not be resolved. See example below. + not be resolved. See the example below. ## Complexity @@ -215,8 +215,8 @@ Strong exception safety: if an exception occurs, the original value stays intact ## See also - documentation on [checked access](../../features/element_access/checked_access.md) -- see [`operator[]`](operator%5B%5D.md) for unchecked access by reference -- see [`value`](value.md) for access with default value +- [`operator[]`](operator%5B%5D.md) for unchecked access by reference +- [`value`](value.md) for access with default value ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/back.md b/docs/mkdocs/docs/api/basic_json/back.md index 1a715284d..b717e16e0 100644 --- a/docs/mkdocs/docs/api/basic_json/back.md +++ b/docs/mkdocs/docs/api/basic_json/back.md @@ -17,8 +17,8 @@ return *tmp; ## Return value -In case of a structured type (array or object), a reference to the last element is returned. In case of number, string, -boolean, or binary values, a reference to the value is returned. +In the case of a structured type (array or object), a reference to the last element is returned. In the case of number, +string, boolean, or binary values, a reference to the value is returned. ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index e2e73612c..71def92a5 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -99,8 +99,8 @@ basic_json(basic_json&& other) noexcept; 2. C++ has no way of describing mapped types other than to list a list of pairs. As JSON requires that keys must be of type string, rule 2 is the weakest constraint one can pose on initializer lists to interpret them as an object. - 3. In all other cases, the initializer list could not be interpreted as JSON object type, so interpreting it as JSON - array type is safe. + 3. In all other cases, the initializer list could not be interpreted as a JSON object type, so interpreting it as a + JSON array type is safe. With the rules described above, the following JSON values cannot be expressed by an initializer list: @@ -113,7 +113,7 @@ basic_json(basic_json&& other) noexcept; 6. Constructs a JSON array value by creating `cnt` copies of a passed value. In case `cnt` is `0`, an empty array is created. -7. Constructs the JSON value with the contents of the range `[first, last)`. The semantics depends on the different +7. Constructs the JSON value with the contents of the range `[first, last)`. The semantics depend on the different types a JSON value can have: - In case of a `#!json null` type, [invalid_iterator.206](../../home/exceptions.md#jsonexceptioninvalid_iterator206) @@ -175,10 +175,10 @@ basic_json(basic_json&& other) noexcept; : the number of JSON copies of `val` to create `first` (in) -: begin of the range to copy from (included) +: the beginning of the range to copy from (included) `last` (in) -: end of the range to copy from (excluded) +: the end of the range to copy from (excluded) `other` (in) : the JSON value to copy/move @@ -188,10 +188,10 @@ basic_json(basic_json&& other) noexcept; 1. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. 2. No-throw guarantee: this constructor never throws exceptions. 3. Depends on the called constructor. For types directly supported by the library (i.e., all types for which no - `to_json()` function was provided), strong guarantee holds: if an exception is thrown, there are no changes to any + `to_json()` function was provided), a strong guarantee holds: if an exception is thrown, there are no changes to any JSON value. 4. Depends on the called constructor. For types directly supported by the library (i.e., all types for which no - `to_json()` function was provided), strong guarantee holds: if an exception is thrown, there are no changes to any + `to_json()` function was provided), a strong guarantee holds: if an exception is thrown, there are no changes to any JSON value. 5. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. 6. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @@ -217,7 +217,7 @@ basic_json(basic_json&& other) noexcept; `[first, last)` is undefined. - Throws [`invalid_iterator.204`](../../home/exceptions.md#jsonexceptioninvalid_iterator204) if iterators `first` and `last` belong to a primitive type (number, boolean, or string), but `first` does not point to the first - element anymore. In this case, the range `[first, last)` is undefined. See example code below. + element anymore. In this case, the range `[first, last)` is undefined. See the example code below. - Throws [`invalid_iterator.206`](../../home/exceptions.md#jsonexceptioninvalid_iterator206) if iterators `first` and `last` belong to a `#!json null` value. In this case, the range `[first, last)` is undefined. 8. (none) @@ -333,7 +333,7 @@ basic_json(basic_json&& other) noexcept; --8<-- "examples/basic_json__list_init_t.output" ``` -??? example "Example: (6) construct an array with count copies of given value" +??? example "Example: (6) construct an array with count copies of a given value" The following code shows examples for creating arrays with several copies of a given value. diff --git a/docs/mkdocs/docs/api/basic_json/binary.md b/docs/mkdocs/docs/api/basic_json/binary.md index ce45d8a0f..efd4347ca 100644 --- a/docs/mkdocs/docs/api/basic_json/binary.md +++ b/docs/mkdocs/docs/api/basic_json/binary.md @@ -21,7 +21,7 @@ create a value for serialization to those formats. ## Parameters `init` (in) -: container containing bytes to use as binary type +: container containing bytes to use as a binary type `subtype` (in) : subtype to use in CBOR, MessagePack, and BSON @@ -42,8 +42,8 @@ Linear in the size of `init`; constant for `typename binary_t::container_type&& Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a `std::vector`. Because -JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization -of a binary array type, for backwards compatibility and so it does not happen on accident. +JSON binary arrays are a non-standard extension, it was decided that it would be best to prevent automatic +initialization of a binary array type, for backwards compatibility and so it does not happen on accident. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/binary_t.md b/docs/mkdocs/docs/api/basic_json/binary_t.md index 705c92cb5..902ffe732 100644 --- a/docs/mkdocs/docs/api/basic_json/binary_t.md +++ b/docs/mkdocs/docs/api/basic_json/binary_t.md @@ -56,11 +56,11 @@ type `#!cpp binary_t*` must be dereferenced. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is - then added as signed 8-bit integer. + then added as a signed 8-bit integer. - If no subtype is given, the bin family (bin8, bin16, bin32) is used. - BSON - - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If a subtype is given, it is used and added as an unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. ## Examples @@ -86,4 +86,4 @@ type `#!cpp binary_t*` must be dereferenced. ## Version history -- Added in version 3.8.0. Changed type of subtype to `std::uint64_t` in version 3.10.0. +- Added in version 3.8.0. Changed the type of subtype to `std::uint64_t` in version 3.10.0. diff --git a/docs/mkdocs/docs/api/basic_json/clear.md b/docs/mkdocs/docs/api/basic_json/clear.md index ff04b08e6..427a7fc39 100644 --- a/docs/mkdocs/docs/api/basic_json/clear.md +++ b/docs/mkdocs/docs/api/basic_json/clear.md @@ -33,7 +33,7 @@ Linear in the size of the JSON value. ## Notes -All iterators, pointers and references related to this container are invalidated. +All iterators, pointers, and references related to this container are invalidated. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/contains.md b/docs/mkdocs/docs/api/basic_json/contains.md index ba2c3df2d..41c376e57 100644 --- a/docs/mkdocs/docs/api/basic_json/contains.md +++ b/docs/mkdocs/docs/api/basic_json/contains.md @@ -35,7 +35,7 @@ bool contains(const json_pointer& ptr) const; ## Return value -1. `#!cpp true` if an element with specified `key` exists. If no such element with such key is found or the JSON value +1. `#!cpp true` if an element with specified `key` exists. If no such element with such a key is found or the JSON value is not an object, `#!cpp false` is returned. 2. See 1. 3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise. diff --git a/docs/mkdocs/docs/api/basic_json/dump.md b/docs/mkdocs/docs/api/basic_json/dump.md index 41adb154d..21e22a48c 100644 --- a/docs/mkdocs/docs/api/basic_json/dump.md +++ b/docs/mkdocs/docs/api/basic_json/dump.md @@ -8,7 +8,7 @@ string_t dump(const int indent = -1, ``` Serialization function for JSON values. The function tries to mimic Python's -[`json.dumps()` function](https://docs.python.org/2/library/json.html#json.dump), and currently supports its `indent` +[`json.dumps()` function](https://docs.python.org/2/library/json.html#json.dump), and currently supports its `indent` and `ensure_ascii` parameters. ## Parameters @@ -49,7 +49,7 @@ Linear. ## Notes -Binary values are serialized as object containing two keys: +Binary values are serialized as an object containing two keys: - "bytes": an array of bytes as integers - "subtype": the subtype as integer or `#!json null` if the binary has no subtype diff --git a/docs/mkdocs/docs/api/basic_json/emplace.md b/docs/mkdocs/docs/api/basic_json/emplace.md index 6cc2c98d7..cf637d628 100644 --- a/docs/mkdocs/docs/api/basic_json/emplace.md +++ b/docs/mkdocs/docs/api/basic_json/emplace.md @@ -14,6 +14,11 @@ created from `args`. `Args` : compatible types to create a `basic_json` object +## Iterator invalidation + +For [`ordered_json`](../ordered_json.md), adding a value to an object can yield a reallocation, in which case all +iterators (including the `end()` iterator) and all references to the elements are invalidated. + ## Parameters `args` (in) diff --git a/docs/mkdocs/docs/api/basic_json/emplace_back.md b/docs/mkdocs/docs/api/basic_json/emplace_back.md index 597ad41e4..21829c216 100644 --- a/docs/mkdocs/docs/api/basic_json/emplace_back.md +++ b/docs/mkdocs/docs/api/basic_json/emplace_back.md @@ -13,6 +13,12 @@ Creates a JSON value from the passed parameters `args` to the end of the JSON va `Args` : compatible types to create a `basic_json` object +## Iterator invalidation + +By adding an element to the end of the array, a reallocation can happen, in which case all iterators (including the +[`end()`](end.md) iterator) and all references to the elements are invalidated. Otherwise, only the [`end()`](end.md) +iterator is invalidated. + ## Parameters `args` (in) @@ -48,6 +54,11 @@ Amortized constant. --8<-- "examples/emplace_back.output" ``` +## See also + +- [operator+=](operator+=.md) add a value to an array/object +- [push_back](push_back.md) add a value to an array/object + ## Version history - Since version 2.0.8. diff --git a/docs/mkdocs/docs/api/basic_json/end_pos.md b/docs/mkdocs/docs/api/basic_json/end_pos.md new file mode 100644 index 000000000..95b07297f --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json/end_pos.md @@ -0,0 +1,68 @@ +# nlohmann::basic_json::end_pos + +```cpp +#if JSON_DIAGNOSTIC_POSITIONS +constexpr std::size_t end_pos() const noexcept; +#endif +``` + +Returns the position immediately following the last character of the JSON string from which the value was parsed from. + +| JSON type | return value | +|-----------|-----------------------------------| +| object | position after the closing `}` | +| array | position after the closing `]` | +| string | position after the closing `"` | +| number | position after the last character | +| boolean | position after `e` | +| null | position after `l` | + +## Return value + +the position of the character _following_ the last character of the given value in the parsed JSON string, if the +value was created by the [`parse`](parse.md) function, or `std::string::npos` if the value was constructed otherwise + +## Exception safety + +No-throw guarantee: this member function never throws exceptions. + +## Complexity + +Constant. + +## Notes + +!!! note "Note" + + The function is only available if macro [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) has + been defined to `#!cpp 1` before including the library header. + +!!! warning "Invalidation" + + The returned positions are only valid as long as the JSON value is not changed. The positions are *not* updated + when the JSON value is changed. + +## Examples + +??? example "Example" + + ```cpp + --8<-- "examples/diagnostic_positions.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostic_positions.output" + ``` + + The output shows the start/end positions of all the objects and fields in the JSON string. + +## See also + +- [start_pos](start_pos.md) to access the start position +- [JSON_DIAGNOSTIC_POSITIONS](../macros/json_diagnostic_positions.md) for an overview of the diagnostic positions + +## Version history + +- Added in version 3.12.0. diff --git a/docs/mkdocs/docs/api/basic_json/exception.md b/docs/mkdocs/docs/api/basic_json/exception.md index 794b7d1e2..b592d62ee 100644 --- a/docs/mkdocs/docs/api/basic_json/exception.md +++ b/docs/mkdocs/docs/api/basic_json/exception.md @@ -8,24 +8,36 @@ This class is an extension of [`std::exception`](https://en.cppreference.com/w/c member `id` for exception ids. It is used as the base class for all exceptions thrown by the `basic_json` class. This class can hence be used as "wildcard" to catch exceptions, see example below. -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception #FFFF00 { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error + + style json_exception fill:#CCCCFF ``` Subclasses: diff --git a/docs/mkdocs/docs/api/basic_json/flatten.md b/docs/mkdocs/docs/api/basic_json/flatten.md index 8703e86d1..7b26a8900 100644 --- a/docs/mkdocs/docs/api/basic_json/flatten.md +++ b/docs/mkdocs/docs/api/basic_json/flatten.md @@ -18,7 +18,7 @@ Strong exception safety: if an exception occurs, the original value stays intact ## Complexity -Linear in the size the JSON value. +Linear in the size of the JSON value. ## Notes diff --git a/docs/mkdocs/docs/api/basic_json/from_bjdata.md b/docs/mkdocs/docs/api/basic_json/from_bjdata.md index 3c5eeb351..cef13aea5 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/from_bjdata.md @@ -18,7 +18,7 @@ Deserializes a given input to a JSON value using the BJData (Binary JData) seria 1. Reads from a compatible input. 2. Reads from an iterator range. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bjdata.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md). ## Template parameters @@ -40,10 +40,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : an input in BJData format convertible to an input adapter `first` (in) -: iterator to start of the input +: iterator to the start of the input `last` (in) -: iterator to end of the input +: iterator to the end of the input `strict` (in) : whether to expect the input to be consumed until EOF (`#!cpp true` by default) @@ -63,7 +63,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or - the end of file was not reached when `strict` was set to true + the end of the file was not reached when `strict` was set to true - Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs - Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed successfully diff --git a/docs/mkdocs/docs/api/basic_json/from_bson.md b/docs/mkdocs/docs/api/basic_json/from_bson.md index 77549370c..fd7d0b097 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bson.md +++ b/docs/mkdocs/docs/api/basic_json/from_bson.md @@ -18,7 +18,7 @@ Deserializes a given input to a JSON value using the BSON (Binary JSON) serializ 1. Reads from a compatible input. 2. Reads from an iterator range. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bson.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md). ## Template parameters @@ -40,10 +40,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : an input in BSON format convertible to an input adapter `first` (in) -: iterator to start of the input +: iterator to the start of the input `last` (in) -: iterator to end of the input +: iterator to the end of the input `strict` (in) : whether to expect the input to be consumed until EOF (`#!cpp true` by default) diff --git a/docs/mkdocs/docs/api/basic_json/from_cbor.md b/docs/mkdocs/docs/api/basic_json/from_cbor.md index 3aa57b9ec..c1d1410b4 100644 --- a/docs/mkdocs/docs/api/basic_json/from_cbor.md +++ b/docs/mkdocs/docs/api/basic_json/from_cbor.md @@ -21,7 +21,7 @@ Deserializes a given input to a JSON value using the CBOR (Concise Binary Object 1. Reads from a compatible input. 2. Reads from an iterator range. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/cbor.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md). ## Template parameters @@ -43,10 +43,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : an input in CBOR format convertible to an input adapter `first` (in) -: iterator to start of the input +: iterator to the start of the input `last` (in) -: iterator to end of the input +: iterator to the end of the input `strict` (in) : whether to expect the input to be consumed until EOF (`#!cpp true` by default) @@ -70,10 +70,10 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or - the end of file was not reached when `strict` was set to true + the end of the file was not reached when `strict` was set to true - Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if unsupported features from CBOR were used in the given input or if the input is not valid CBOR -- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string was expected as map key, +- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string was expected as a map key, but not found ## Complexity diff --git a/docs/mkdocs/docs/api/basic_json/from_msgpack.md b/docs/mkdocs/docs/api/basic_json/from_msgpack.md index 117c3865f..93c3acc5d 100644 --- a/docs/mkdocs/docs/api/basic_json/from_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/from_msgpack.md @@ -18,7 +18,7 @@ Deserializes a given input to a JSON value using the MessagePack serialization f 1. Reads from a compatible input. 2. Reads from an iterator range. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/messagepack.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md). ## Template parameters @@ -40,10 +40,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : an input in MessagePack format convertible to an input adapter `first` (in) -: iterator to start of the input +: iterator to the start of the input `last` (in) -: iterator to end of the input +: iterator to the end of the input `strict` (in) : whether to expect the input to be consumed until EOF (`#!cpp true` by default) @@ -54,7 +54,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f ## Return value deserialized JSON value; in case of a parse error and `allow_exceptions` set to `#!cpp false`, the return value will be -`value_t::discarded`. The latter can be checked with [`is_discarded`](is_discarded.md). +`value_t::discarded`. The latter can be checked with [`is_discarded`](is_discarded.md). ## Exception safety @@ -63,10 +63,10 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or - the end of file was not reached when `strict` was set to true + the end of the file was not reached when `strict` was set to true - Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if unsupported features from MessagePack were used in the given input or if the input is not valid MessagePack -- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string was expected as map key, +- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string was expected as a map key, but not found ## Complexity diff --git a/docs/mkdocs/docs/api/basic_json/from_ubjson.md b/docs/mkdocs/docs/api/basic_json/from_ubjson.md index 08117e89b..084a2d8bb 100644 --- a/docs/mkdocs/docs/api/basic_json/from_ubjson.md +++ b/docs/mkdocs/docs/api/basic_json/from_ubjson.md @@ -18,7 +18,7 @@ Deserializes a given input to a JSON value using the UBJSON (Universal Binary JS 1. Reads from a compatible input. 2. Reads from an iterator range. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/ubjson.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md). ## Template parameters @@ -40,10 +40,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : an input in UBJSON format convertible to an input adapter `first` (in) -: iterator to start of the input +: iterator to the start of the input `last` (in) -: iterator to end of the input +: iterator to the end of the input `strict` (in) : whether to expect the input to be consumed until EOF (`#!cpp true` by default) @@ -63,7 +63,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or - the end of file was not reached when `strict` was set to true + the end of the file was not reached when `strict` was set to true - Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs - Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed successfully diff --git a/docs/mkdocs/docs/api/basic_json/front.md b/docs/mkdocs/docs/api/basic_json/front.md index e258c36a0..b5fea1135 100644 --- a/docs/mkdocs/docs/api/basic_json/front.md +++ b/docs/mkdocs/docs/api/basic_json/front.md @@ -10,8 +10,8 @@ Returns a reference to the first element in the container. For a JSON container ## Return value -In case of a structured type (array or object), a reference to the first element is returned. In case of number, string, -boolean, or binary values, a reference to the value is returned. +In the case of a structured type (array or object), a reference to the first element is returned. In the case of number, +string, boolean, or binary values, a reference to the value is returned. ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/get_ptr.md b/docs/mkdocs/docs/api/basic_json/get_ptr.md index 2441e1156..7c000f1ac 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ptr.md +++ b/docs/mkdocs/docs/api/basic_json/get_ptr.md @@ -35,7 +35,37 @@ Constant. !!! danger "Undefined behavior" - Writing data to the pointee of the result yields an undefined state. + The pointer becomes invalid if the underlying JSON object changes. + + Consider the following example code where the pointer `ptr` changes after the array is resized. As a result, + reading or writing to `ptr` after the array change would be undefined behavior. The address of the first array + element changes, because the underlying `std::vector` is resized after adding a fifth element. + + ```cpp + #include + #include + + using json = nlohmann::json; + + int main() + { + json j = {1, 2, 3, 4}; + auto* ptr = j[0].get_ptr(); + std::cout << "value at " << ptr << " is " << *ptr << std::endl; + + j.push_back(5); + + ptr = j[0].get_ptr(); + std::cout << "value at " << ptr << " is " << *ptr << std::endl; + } + ``` + + Output: + + ``` + value at 0x6000012fc1c8 is 1 + value at 0x6000029fc088 is 1 + ``` ## Examples @@ -54,6 +84,10 @@ Constant. --8<-- "examples/get_ptr.output" ``` +## See also + +- [get_ref()](get_ref.md) get a reference value + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/get_ref.md b/docs/mkdocs/docs/api/basic_json/get_ref.md index b1219742c..73b20b0e0 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ref.md +++ b/docs/mkdocs/docs/api/basic_json/get_ref.md @@ -40,7 +40,7 @@ Constant. !!! danger "Undefined behavior" - Writing data to the referee of the result yields an undefined state. + The reference becomes invalid if the underlying JSON object changes. ## Examples @@ -58,6 +58,10 @@ Constant. --8<-- "examples/get_ref.output" ``` +## See also + +- [get_ptr()](get_ptr.md) get a pointer value + ## Version history - Added in version 1.1.0. diff --git a/docs/mkdocs/docs/api/basic_json/index.md b/docs/mkdocs/docs/api/basic_json/index.md index 648670144..2c942d4db 100644 --- a/docs/mkdocs/docs/api/basic_json/index.md +++ b/docs/mkdocs/docs/api/basic_json/index.md @@ -38,11 +38,19 @@ class basic_json; ## Specializations - [**json**](../json.md) - default specialization -- [**ordered_json**](../ordered_json.md) - specialization that maintains the insertion order of object keys +- [**ordered_json**](../ordered_json.md) - a specialization that maintains the insertion order of object keys ## Iterator invalidation -Todo +All operations that add values to an **array** ([`push_back`](push_back.md) , [`operator+=`](operator+=.md), +[`emplace_back`](emplace_back.md), [`insert`](insert.md), and [`operator[]`](operator%5B%5D.md) for a non-existing +index) can yield a reallocation, in which case all iterators (including the [`end()`](end.md) iterator) and all +references to the elements are invalidated. + +For [`ordered_json`](../ordered_json.md), also all operations that add a value to an **object** +([`push_back`](push_back.md), [`operator+=`](operator+=.md), [`emplace`](emplace.md), [`insert`](insert.md), +[`update`](update.md), and [`operator[]`](operator%5B%5D.md) for a non-existing key) can yield a reallocation, in +which case all iterators (including the [`end()`](end.md) iterator) and all references to the elements are invalidated. ## Requirements @@ -50,8 +58,8 @@ The class satisfies the following concept requirements: ### Basic -- [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): JSON values can be default - constructed. The result will be a JSON null value. +- [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): JSON values can be + default-constructed. The result will be a JSON null value. - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible): A JSON value can be @@ -148,9 +156,9 @@ The class satisfies the following concept requirements: - [(constructor)](basic_json.md) - [(destructor)](~basic_json.md) - [**operator=**](operator=.md) - copy assignment -- [**array**](array_t.md) (_static_) - explicitly create an array +- [**array**](array.md) (_static_) - explicitly create an array - [**binary**](binary.md) (_static_) - explicitly create a binary array -- [**object**](object_t.md) (_static_) - explicitly create an object +- [**object**](object.md) (_static_) - explicitly create an object ### Object inspection @@ -159,19 +167,24 @@ Functions to inspect the type of a JSON value. - [**type**](type.md) - return the type of the JSON value - [**operator value_t**](operator_value_t.md) - return the type of the JSON value - [**type_name**](type_name.md) - return the type as string -- [**is_primitive**](is_primitive.md) - return whether type is primitive -- [**is_structured**](is_structured.md) - return whether type is structured -- [**is_null**](is_null.md) - return whether value is null -- [**is_boolean**](is_boolean.md) - return whether value is a boolean -- [**is_number**](is_number.md) - return whether value is a number -- [**is_number_integer**](is_number_integer.md) - return whether value is an integer number -- [**is_number_unsigned**](is_number_unsigned.md) - return whether value is an unsigned integer number -- [**is_number_float**](is_number_float.md) - return whether value is a floating-point number -- [**is_object**](is_object.md) - return whether value is an object -- [**is_array**](is_array.md) - return whether value is an array -- [**is_string**](is_string.md) - return whether value is a string -- [**is_binary**](is_binary.md) - return whether value is a binary array -- [**is_discarded**](is_discarded.md) - return whether value is discarded +- [**is_primitive**](is_primitive.md) - return whether the type is primitive +- [**is_structured**](is_structured.md) - return whether the type is structured +- [**is_null**](is_null.md) - return whether the value is null +- [**is_boolean**](is_boolean.md) - return whether the value is a boolean +- [**is_number**](is_number.md) - return whether the value is a number +- [**is_number_integer**](is_number_integer.md) - return whether the value is an integer number +- [**is_number_unsigned**](is_number_unsigned.md) - return whether the value is an unsigned integer number +- [**is_number_float**](is_number_float.md) - return whether the value is a floating-point number +- [**is_object**](is_object.md) - return whether the value is an object +- [**is_array**](is_array.md) - return whether the value is an array +- [**is_string**](is_string.md) - return whether the value is a string +- [**is_binary**](is_binary.md) - return whether the value is a binary array +- [**is_discarded**](is_discarded.md) - return whether the value is discarded + +Optional functions to access the [diagnostic positions](../macros/json_diagnostic_positions.md). + +- [**start_pos**](start_pos.md) - return the start position of the value +- [**end_pos**](end_pos.md) - return the one past the end position of the value ### Value access @@ -224,7 +237,7 @@ Access to the JSON value - [**push_back**](push_back.md) - add a value to an array/object - [**operator+=**](operator+=.md) - add a value to an array/object - [**emplace_back**](emplace_back.md) - add a value to an array -- [**emplace**](emplace.md) - add a value to an object if key does not exist +- [**emplace**](emplace.md) - add a value to an object if a key does not exist - [**erase**](erase.md) - remove elements - [**insert**](insert.md) - inserts elements - [**update**](update.md) - updates a JSON object from another object, overwriting existing keys diff --git a/docs/mkdocs/docs/api/basic_json/insert.md b/docs/mkdocs/docs/api/basic_json/insert.md index 2e6b29301..2f809f015 100644 --- a/docs/mkdocs/docs/api/basic_json/insert.md +++ b/docs/mkdocs/docs/api/basic_json/insert.md @@ -18,11 +18,22 @@ iterator insert(const_iterator pos, initializer_list_t ilist); void insert(const_iterator first, const_iterator last); ``` -1. Inserts element `val` into array before iterator `pos`. -2. Inserts `cnt` copies of `val` into array before iterator `pos`. -3. Inserts elements from range `[first, last)` into array before iterator `pos`. -4. Inserts elements from initializer list `ilist` into array before iterator `pos`. -5. Inserts elements from range `[first, last)` into object. +1. Inserts element `val` into an array before iterator `pos`. +2. Inserts `cnt` copies of `val` into an array before iterator `pos`. +3. Inserts elements from range `[first, last)` into an array before iterator `pos`. +4. Inserts elements from initializer list `ilist` into an array before iterator `pos`. +5. Inserts elements from range `[first, last)` into an object. + +## Iterator invalidation + +For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators +(including the [`end()`](end.md) iterator) and all references to the elements are invalidated. Otherwise, only the +[`end()`](end.md) iterator is invalidated. Also, any iterator or reference after the insertion point will point to the +same index which is now a different value. + +For [`ordered_json`](../ordered_json.md), also adding an element to an **object** can yield a reallocation which again +invalidates all iterators and all references. Also, any iterator or reference after the insertion point will point to +the same index which is now a different value. ## Parameters @@ -36,10 +47,10 @@ void insert(const_iterator first, const_iterator last); : number of copies of `val` to insert `first` (in) -: begin of the range of elements to insert +: the start of the range of elements to insert `last` (in) -: end of the range of elements to insert +: the end of the range of elements to insert `ilist` (in) : initializer list to insert the values from @@ -128,7 +139,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__count.output" ``` -??? example "Example (3): insert range of elements into array" +??? example "Example (3): insert a range of elements into an array" The example shows how `insert()` is used. @@ -142,7 +153,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__range.output" ``` -??? example "Example (4): insert elements from initializer list into array" +??? example "Example (4): insert elements from an initializer list into an array" The example shows how `insert()` is used. @@ -156,7 +167,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__ilist.output" ``` -??? example "Example (5): insert range of elements into object" +??? example "Example (5): insert a range of elements into an object" The example shows how `insert()` is used. diff --git a/docs/mkdocs/docs/api/basic_json/invalid_iterator.md b/docs/mkdocs/docs/api/basic_json/invalid_iterator.md index f9fdce5b4..3f0f75356 100644 --- a/docs/mkdocs/docs/api/basic_json/invalid_iterator.md +++ b/docs/mkdocs/docs/api/basic_json/invalid_iterator.md @@ -8,26 +8,36 @@ This exception is thrown if iterators passed to a library function do not match Exceptions have ids 2xx (see [list of iterator errors](../../home/exceptions.md#iterator-errors)). -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error -class basic_json::invalid_iterator #FFFF00 {} + style json_invalid_iterator fill:#CCCCFF ``` ## Member functions diff --git a/docs/mkdocs/docs/api/basic_json/is_binary.md b/docs/mkdocs/docs/api/basic_json/is_binary.md index ea48d745c..2a42e5edf 100644 --- a/docs/mkdocs/docs/api/basic_json/is_binary.md +++ b/docs/mkdocs/docs/api/basic_json/is_binary.md @@ -4,7 +4,7 @@ constexpr bool is_binary() const noexcept; ``` -This function returns `#!cpp true` if and only if the JSON value is binary array. +This function returns `#!cpp true` if and only if the JSON value is a binary array. ## Return value diff --git a/docs/mkdocs/docs/api/basic_json/is_number.md b/docs/mkdocs/docs/api/basic_json/is_number.md index 9807911bc..2f6d63565 100644 --- a/docs/mkdocs/docs/api/basic_json/is_number.md +++ b/docs/mkdocs/docs/api/basic_json/is_number.md @@ -9,7 +9,7 @@ unsigned) and floating-point values. ## Return value -`#!cpp true` if type is number (regardless whether integer, unsigned integer or floating-type), `#!cpp false` otherwise. +`#!cpp true` if type is number (regardless whether integer, unsigned integer, or floating-type), `#!cpp false` otherwise. ## Exception safety @@ -46,9 +46,9 @@ constexpr bool is_number() const noexcept ## See also -- [is_number_integer()](is_number_integer.md) check if value is an integer or unsigned integer number -- [is_number_unsigned()](is_number_unsigned.md) check if value is an unsigned integer number -- [is_number_float()](is_number_float.md) check if value is a floating-point number +- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number +- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number +- [is_number_float()](is_number_float.md) check if the value is a floating-point number ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/is_number_float.md b/docs/mkdocs/docs/api/basic_json/is_number_float.md index 68d0cfb01..ad18858e3 100644 --- a/docs/mkdocs/docs/api/basic_json/is_number_float.md +++ b/docs/mkdocs/docs/api/basic_json/is_number_float.md @@ -37,9 +37,9 @@ Constant. ## See also -- [is_number()](is_number.md) check if value is a number -- [is_number_integer()](is_number_integer.md) check if value is an integer or unsigned integer number -- [is_number_unsigned()](is_number_unsigned.md) check if value is an unsigned integer number +- [is_number()](is_number.md) check if the value is a number +- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number +- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/is_number_integer.md b/docs/mkdocs/docs/api/basic_json/is_number_integer.md index 8ca214aed..b8f971bd6 100644 --- a/docs/mkdocs/docs/api/basic_json/is_number_integer.md +++ b/docs/mkdocs/docs/api/basic_json/is_number_integer.md @@ -37,9 +37,9 @@ Constant. ## See also -- [is_number()](is_number.md) check if value is a number -- [is_number_unsigned()](is_number_unsigned.md) check if value is an unsigned integer number -- [is_number_float()](is_number_float.md) check if value is a floating-point number +- [is_number()](is_number.md) check if the value is a number +- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number +- [is_number_float()](is_number_float.md) check if the value is a floating-point number ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/is_number_unsigned.md b/docs/mkdocs/docs/api/basic_json/is_number_unsigned.md index 2ac98a5f0..50083164e 100644 --- a/docs/mkdocs/docs/api/basic_json/is_number_unsigned.md +++ b/docs/mkdocs/docs/api/basic_json/is_number_unsigned.md @@ -37,9 +37,9 @@ Constant. ## See also -- [is_number()](is_number.md) check if value is a number -- [is_number_integer()](is_number_integer.md) check if value is an integer or unsigned integer number -- [is_number_float()](is_number_float.md) check if value is a floating-point number +- [is_number()](is_number.md) check if the value is a number +- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number +- [is_number_float()](is_number_float.md) check if the value is a floating-point number ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/is_primitive.md b/docs/mkdocs/docs/api/basic_json/is_primitive.md index cf6cbbd4c..076c2bfef 100644 --- a/docs/mkdocs/docs/api/basic_json/is_primitive.md +++ b/docs/mkdocs/docs/api/basic_json/is_primitive.md @@ -35,7 +35,7 @@ The term *primitive* stems from [RFC 8259](https://tools.ietf.org/html/rfc8259): > JSON can represent four primitive types (strings, numbers, booleans, and null) and two structured types (objects and > arrays). -This library extends primitive types to binary types, because binary types are roughly comparable to strings. Hence, +This library extends primitive types to binary types, because binary types are roughly comparable to strings. Hence, `is_primitive()` returns `#!cpp true` for binary values. ## Examples @@ -56,12 +56,12 @@ This library extends primitive types to binary types, because binary types are ## See also -- [is_structured()](is_structured.md) returns whether JSON value is structured -- [is_null()](is_null.md) returns whether JSON value is `null` -- [is_string()](is_string.md) returns whether JSON value is a string -- [is_boolean()](is_boolean.md) returns whether JSON value is a boolean -- [is_number()](is_number.md) returns whether JSON value is a number -- [is_binary()](is_binary.md) returns whether JSON value is a binary array +- [is_structured()](is_structured.md) returns whether the JSON value is structured +- [is_null()](is_null.md) returns whether the JSON value is `null` +- [is_string()](is_string.md) returns whether the JSON value is a string +- [is_boolean()](is_boolean.md) returns whether the JSON value is a boolean +- [is_number()](is_number.md) returns whether the JSON value is a number +- [is_binary()](is_binary.md) returns whether the JSON value is a binary array ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/is_structured.md b/docs/mkdocs/docs/api/basic_json/is_structured.md index f8fe4dcba..f2d9e79ff 100644 --- a/docs/mkdocs/docs/api/basic_json/is_structured.md +++ b/docs/mkdocs/docs/api/basic_json/is_structured.md @@ -21,7 +21,7 @@ Constant. ## Possible implementation ```cpp -constexpr bool is_primitive() const noexcept +constexpr bool is_structured() const noexcept { return is_array() || is_object(); } @@ -55,8 +55,8 @@ Note that though strings are containers in C++, they are treated as primitive va ## See also - [is_primitive()](is_primitive.md) returns whether JSON value is primitive -- [is_array()](is_array.md) returns whether value is an array -- [is_object()](is_object.md) returns whether value is an object +- [is_array()](is_array.md) returns whether the value is an array +- [is_object()](is_object.md) returns whether the value is an object ## Version history diff --git a/docs/mkdocs/docs/api/basic_json/items.md b/docs/mkdocs/docs/api/basic_json/items.md index 0b34ddcba..be32bbfd9 100644 --- a/docs/mkdocs/docs/api/basic_json/items.md +++ b/docs/mkdocs/docs/api/basic_json/items.md @@ -66,7 +66,7 @@ When iterating over an array, `key()` will return the index of the element as st !!! danger "Lifetime issues" Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See - for more information. + [#2040](https://github.com/nlohmann/json/issues/2040) for more information. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/number_float_t.md b/docs/mkdocs/docs/api/basic_json/number_float_t.md index 50aa43b48..3e8933da6 100644 --- a/docs/mkdocs/docs/api/basic_json/number_float_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_float_t.md @@ -13,7 +13,7 @@ The type used to store JSON numbers (floating-point). > cannot be represented in the grammar below (such as Infinity and NaN) are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is -known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different +known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different types, [`number_integer_t`](number_integer_t.md), [`number_unsigned_t`](number_unsigned_t.md) and `number_float_t` are used. @@ -28,9 +28,9 @@ With the default values for `NumberFloatType` (`double`), the default value for #### Default behavior -- The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in floating-point literals will be - ignored. Internally, the value will be stored as decimal number. For instance, the C++ floating-point literal `01.2` - will be serialized to `1.2`. During deserialization, leading zeros yield an error. +- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in floating-point literals will + be ignored. Internally, the value will be stored as a decimal number. For instance, the C++ floating-point literal + `01.2` will be serialized to `1.2`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits diff --git a/docs/mkdocs/docs/api/basic_json/number_integer_t.md b/docs/mkdocs/docs/api/basic_json/number_integer_t.md index 9bb3835a0..cef3f2001 100644 --- a/docs/mkdocs/docs/api/basic_json/number_integer_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_integer_t.md @@ -13,7 +13,7 @@ The type used to store JSON numbers (integers). > cannot be represented in the grammar below (such as Infinity and NaN) are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is -known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different +known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different types, `number_integer_t`, [`number_unsigned_t`](number_unsigned_t.md) and [`number_float_t`](number_float_t.md) are used. @@ -29,9 +29,9 @@ With the default values for `NumberIntegerType` (`std::int64_t`), the default va #### Default behavior -- The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an - interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer - literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. +- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an + interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ + integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits @@ -42,7 +42,7 @@ With the default values for `NumberIntegerType` (`std::int64_t`), the default va When the default type is used, the maximal integer number that can be stored is `9223372036854775807` (INT64_MAX) and the minimal integer number that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers -will be automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md). +will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md). [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are diff --git a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md index 8a1540a57..79b1c486c 100644 --- a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md @@ -13,7 +13,7 @@ The type used to store JSON numbers (unsigned). > cannot be represented in the grammar below (such as Infinity and NaN) are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is -known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different +known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different types, [`number_integer_t`](number_integer_t.md), `number_unsigned_t` and [`number_float_t`](number_float_t.md) are used. @@ -29,9 +29,9 @@ With the default values for `NumberUnsignedType` (`std::uint64_t`), the default #### Default behavior -- The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an - interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer - literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. +- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an + interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ + integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits @@ -41,7 +41,7 @@ With the default values for `NumberUnsignedType` (`std::uint64_t`), the default When the default type is used, the maximal integer number that can be stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number that can be stored is `0`. Integer numbers that are out of range will yield over/underflow -when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored +when used in a constructor. During deserialization, too large or small integer numbers will automatically be stored as [`number_integer_t`](number_integer_t.md) or [`number_float_t`](number_float_t.md). [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: diff --git a/docs/mkdocs/docs/api/basic_json/object.md b/docs/mkdocs/docs/api/basic_json/object.md index 9bdbddb6a..73fbcaf79 100644 --- a/docs/mkdocs/docs/api/basic_json/object.md +++ b/docs/mkdocs/docs/api/basic_json/object.md @@ -25,7 +25,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va Throws [`type_error.301`](../../home/exceptions.md#jsonexceptiontype_error301) if `init` is not a list of pairs whose first elements are strings. In this case, no object can be created. When such a value is passed to `basic_json(initializer_list_t, bool, value_t)`, an array would have been created from the passed initializer list -`init`. See example below. +`init`. See the example below. ## Complexity @@ -34,7 +34,7 @@ Linear in the size of `init`. ## Notes This function is only added for symmetry reasons. In contrast to the related function `array(initializer_list_t)`, there -are no cases which can only be expressed by this function. That is, any initializer list `init` can also be passed to +are no cases that can only be expressed by this function. That is, any initializer list `init` can also be passed to the initializer list constructor `basic_json(initializer_list_t, bool, value_t)`. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/object_t.md b/docs/mkdocs/docs/api/basic_json/object_t.md index 39f68b089..7dda42d2b 100644 --- a/docs/mkdocs/docs/api/basic_json/object_t.md +++ b/docs/mkdocs/docs/api/basic_json/object_t.md @@ -87,8 +87,8 @@ Objects are stored as pointers in a `basic_json` type. That is, for any access t #### Object key order -The order name/value pairs are added to the object is *not* preserved by the library. Therefore, iterating an object may -return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in +The order name/value pairs are added to the object are *not* preserved by the library. Therefore, iterating an object +may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. diff --git a/docs/mkdocs/docs/api/basic_json/operator+=.md b/docs/mkdocs/docs/api/basic_json/operator+=.md index dc5f2ecc4..473b82a4e 100644 --- a/docs/mkdocs/docs/api/basic_json/operator+=.md +++ b/docs/mkdocs/docs/api/basic_json/operator+=.md @@ -27,6 +27,15 @@ reference operator+=(initializer_list_t init); `init` is converted into an object element and added using `operator+=(const typename object_t::value_type&)`. Otherwise, `init` is converted to a JSON value and added using `operator+=(basic_json&&)`. +## Iterator invalidation + +For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including +the [`end()`](end.md) iterator) and all references to the elements are invalidated. Otherwise, only the +[`end()`](end.md) iterator is invalidated. + +For [`ordered_json`](../ordered_json.md), also adding an element to an **object** can yield a reallocation which again +invalidates all iterators and all references. + ## Parameters `val` (in) @@ -103,8 +112,13 @@ interpreted as `object_t::value_type` or `std::initializer_list`, se --8<-- "examples/push_back__initializer_list.output" ``` +## See also + +- [emplace_back](emplace_back.md) add a value to an array +- [push_back](push_back.md) add a value to an array/object + ## Version history 1. Since version 1.0.0. 2. Since version 1.0.0. -2. Since version 2.0.0. +3. Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/operator[].md b/docs/mkdocs/docs/api/basic_json/operator[].md index 51dd8588c..3eebd562a 100644 --- a/docs/mkdocs/docs/api/basic_json/operator[].md +++ b/docs/mkdocs/docs/api/basic_json/operator[].md @@ -34,6 +34,15 @@ const_reference operator[](const json_pointer& ptr) const; [`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md). This can also be a string view (C++17). +## Iterator invalidation + +For the non-const versions 1. and 4., when passing an **array** index that does not exist, it is created and filled with +a `#!json null` value before a reference to it is returned. For this, a reallocation can happen, in which case all +iterators (including the [`end()`](end.md) iterator) and all references to the elements are invalidated. + +For [`ordered_json`](../ordered_json.md), also passing an **object key** to the non-const versions 2., 3., and 4., a +reallocation can happen which again invalidates all iterators and all references. + ## Parameters `idx` (in) diff --git a/docs/mkdocs/docs/api/basic_json/operator_gt.md b/docs/mkdocs/docs/api/basic_json/operator_gt.md index 9516656e0..486da5fd0 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_gt.md +++ b/docs/mkdocs/docs/api/basic_json/operator_gt.md @@ -17,7 +17,7 @@ bool operator>(ScalarType lhs, const const_reference rhs) noexcept; // (2) operand is `NaN` and the other operand is either `NaN` or any other number. - Otherwise, returns the result of `#!cpp !(lhs <= rhs)` (see [**operator<=**](operator_le.md)). -2. Compares wether a JSON value is greater than a scalar or a scalar is greater than a JSON value by +2. Compares whether a JSON value is greater than a scalar or a scalar is greater than a JSON value by converting the scalar to a JSON value and comparing both JSON values according to 1. ## Template parameters diff --git a/docs/mkdocs/docs/api/basic_json/operator_le.md b/docs/mkdocs/docs/api/basic_json/operator_le.md index 7b648e035..9dfa4e1e0 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_le.md +++ b/docs/mkdocs/docs/api/basic_json/operator_le.md @@ -17,7 +17,7 @@ bool operator<=(ScalarType lhs, const const_reference rhs) noexcept; // (2) operand is `NaN` and the other operand is either `NaN` or any other number. - Otherwise, returns the result of `#!cpp !(rhs < lhs)` (see [**operator<**](operator_lt.md)). -1. Compares wether a JSON value is less than or equal to a scalar or a scalar is less than or equal +2. Compares whether a JSON value is less than or equal to a scalar or a scalar is less than or equal to a JSON value by converting the scalar to a JSON value and comparing both JSON values according to 1. diff --git a/docs/mkdocs/docs/api/basic_json/operator_lt.md b/docs/mkdocs/docs/api/basic_json/operator_lt.md index b5d191ec4..118d817c8 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_lt.md +++ b/docs/mkdocs/docs/api/basic_json/operator_lt.md @@ -27,7 +27,7 @@ bool operator<(ScalarType lhs, const const_reference rhs) noexcept; // (2) 7. binary For instance, any boolean value is considered less than any string. -2. Compares wether a JSON value is less than a scalar or a scalar is less than a JSON value by converting +2. Compares whether a JSON value is less than a scalar or a scalar is less than a JSON value by converting the scalar to a JSON value and comparing both JSON values according to 1. ## Template parameters diff --git a/docs/mkdocs/docs/api/basic_json/other_error.md b/docs/mkdocs/docs/api/basic_json/other_error.md index 9a83340a0..251c0f3d4 100644 --- a/docs/mkdocs/docs/api/basic_json/other_error.md +++ b/docs/mkdocs/docs/api/basic_json/other_error.md @@ -8,26 +8,36 @@ This exception is thrown in case of errors that cannot be classified with the ot Exceptions have ids 5xx (see [list of other errors](../../home/exceptions.md#further-exceptions)). -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error -class basic_json::other_error #FFFF00 {} + style json_other_error fill:#CCCCFF ``` ## Member functions diff --git a/docs/mkdocs/docs/api/basic_json/out_of_range.md b/docs/mkdocs/docs/api/basic_json/out_of_range.md index 6c1f0dfba..3b6178999 100644 --- a/docs/mkdocs/docs/api/basic_json/out_of_range.md +++ b/docs/mkdocs/docs/api/basic_json/out_of_range.md @@ -5,30 +5,40 @@ class out_of_range : public exception; ``` This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for -instance in case of array indices or nonexisting object keys. +instance, in the case of array indices or nonexisting object keys. Exceptions have ids 4xx (see [list of out-of-range errors](../../home/exceptions.md#out-of-range)). -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error -class basic_json::out_of_range #FFFF00 {} + style json_out_of_range fill:#CCCCFF ``` ## Member functions diff --git a/docs/mkdocs/docs/api/basic_json/parse.md b/docs/mkdocs/docs/api/basic_json/parse.md index 49838ad1d..140a08f3d 100644 --- a/docs/mkdocs/docs/api/basic_json/parse.md +++ b/docs/mkdocs/docs/api/basic_json/parse.md @@ -19,8 +19,8 @@ static basic_json parse(IteratorType first, IteratorType last, 1. Deserialize from a compatible input. 2. Deserialize from a pair of character iterators - The `value_type` of the iterator must be an integral type with size of 1, 2 or 4 bytes, which will be interpreted - respectively as UTF-8, UTF-16 and UTF-32. + The `value_type` of the iterator must be an integral type with size of 1, 2, or 4 bytes, which will be interpreted + respectively as UTF-8, UTF-16, and UTF-32. ## Template parameters @@ -28,9 +28,9 @@ static basic_json parse(IteratorType first, IteratorType last, : A compatible input, for instance: - an `std::istream` object - - a `FILE` pointer (must not be null) + - a `FILE` pointer (throws if null) - a C-style array of characters - - a pointer to a null-terminated string of single byte characters + - a pointer to a null-terminated string of single byte characters (throws if null) - a `std::string` - an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators. @@ -57,10 +57,10 @@ static basic_json parse(IteratorType first, IteratorType last, (`#!cpp false`); (optional, `#!cpp false` by default) `first` (in) -: iterator to start of character range +: iterator to the start of a character range `last` (in) -: iterator to end of character range +: iterator to the end of a character range ## Return value @@ -73,10 +73,11 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions -- Throws [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token. -- Throws [`parse_error.102`](../../home/exceptions.md#jsonexceptionparse_error102) if to_unicode fails or surrogate +- Throws [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token, or + empty input like a null `FILE*` or `char*` pointer. +- Throws [`parse_error.102`](../../home/exceptions.md#jsonexceptionparse_error102) if `to_unicode` fails or surrogate error. -- Throws [`parse_error.103`](../../home/exceptions.md#jsonexceptionparse_error103) if to_unicode fails. +- Throws [`parse_error.103`](../../home/exceptions.md#jsonexceptionparse_error103) if `to_unicode` fails. ## Complexity @@ -86,12 +87,7 @@ super-linear complexity. ## Notes -(1) A UTF-8 byte order mark is silently ignored. - -!!! danger "Runtime assertion" - - The precondition that a passed `#!cpp FILE` pointer must not be null is enforced with a - [runtime assertion](../../features/assertions.md). +A UTF-8 byte order mark is silently ignored. ## Examples @@ -151,7 +147,7 @@ super-linear complexity. --8<-- "examples/parse__contiguouscontainer__parser_callback_t.output" ``` -??? example "Parsing from a non null-terminated string" +??? example "Parsing from a non-null-terminated string" The example below demonstrates the `parse()` function reading from a string that is not null-terminated. @@ -203,6 +199,7 @@ super-linear complexity. - Added in version 1.0.0. - Overload for contiguous containers (1) added in version 2.0.3. - Ignoring comments via `ignore_comments` added in version 3.9.0. +- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. !!! warning "Deprecation" diff --git a/docs/mkdocs/docs/api/basic_json/parse_error.md b/docs/mkdocs/docs/api/basic_json/parse_error.md index af3e1f0b3..93986e543 100644 --- a/docs/mkdocs/docs/api/basic_json/parse_error.md +++ b/docs/mkdocs/docs/api/basic_json/parse_error.md @@ -4,31 +4,43 @@ class parse_error : public exception; ``` -This exception is thrown by the library when a parse error occurs. Parse errors can occur during the deserialization of +The library throws this exception when a parse error occurs. Parse errors can occur during the deserialization of JSON text, BSON, CBOR, MessagePack, UBJSON, as well as when using JSON Patch. Member `byte` holds the byte index of the last read character in the input file (see note below). Exceptions have ids 1xx (see [list of parse errors](../../home/exceptions.md#parse-errors)). -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error #FFFF00 { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error + + style json_parse_error fill:#CCCCFF ``` ## Member functions diff --git a/docs/mkdocs/docs/api/basic_json/patch.md b/docs/mkdocs/docs/api/basic_json/patch.md index deec47434..0f6387a69 100644 --- a/docs/mkdocs/docs/api/basic_json/patch.md +++ b/docs/mkdocs/docs/api/basic_json/patch.md @@ -37,8 +37,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Complexity -Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is -affected by the patch, the complexity can usually be neglected. +Linear in the size of the JSON value and the length of the JSON patch. As usually the patch affects only a fraction of +the JSON value, the complexity can usually be neglected. ## Notes diff --git a/docs/mkdocs/docs/api/basic_json/patch_inplace.md b/docs/mkdocs/docs/api/basic_json/patch_inplace.md index e8fd176c3..6cc13e102 100644 --- a/docs/mkdocs/docs/api/basic_json/patch_inplace.md +++ b/docs/mkdocs/docs/api/basic_json/patch_inplace.md @@ -33,8 +33,8 @@ No guarantees, value may be corrupted by an unsuccessful patch operation. ## Complexity -Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is -affected by the patch, the complexity can usually be neglected. +Linear in the size of the JSON value and the length of the JSON patch. As usually the patch affects only a fraction of +the JSON value, the complexity can usually be neglected. ## Notes diff --git a/docs/mkdocs/docs/api/basic_json/push_back.md b/docs/mkdocs/docs/api/basic_json/push_back.md index 5c7d20dd6..49f185c56 100644 --- a/docs/mkdocs/docs/api/basic_json/push_back.md +++ b/docs/mkdocs/docs/api/basic_json/push_back.md @@ -27,6 +27,15 @@ void push_back(initializer_list_t init); `init` is converted into an object element and added using `push_back(const typename object_t::value_type&)`. Otherwise, `init` is converted to a JSON value and added using `push_back(basic_json&&)`. +## Iterator invalidation + +For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including +the [`end()`](end.md) iterator) and all references to the elements are invalidated. Otherwise, only the +[`end()`](end.md) iterator is invalidated. + +For [`ordered_json`](../ordered_json.md), also adding an element to an **object** can yield a reallocation which again +invalidates all iterators and all references. + ## Parameters `val` (in) @@ -99,8 +108,13 @@ All functions can throw the following exception: --8<-- "examples/push_back__initializer_list.output" ``` +## See also + +- [emplace_back](emplace_back.md) add a value to an array +- [operator+=](operator+=.md) add a value to an array/object + ## Version history 1. Since version 1.0.0. 2. Since version 1.0.0. -2. Since version 2.0.0. +3. Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/sax_parse.md b/docs/mkdocs/docs/api/basic_json/sax_parse.md index e2ac1b41d..43793d09a 100644 --- a/docs/mkdocs/docs/api/basic_json/sax_parse.md +++ b/docs/mkdocs/docs/api/basic_json/sax_parse.md @@ -23,8 +23,8 @@ Read from input and generate SAX events 1. Read from a compatible input. 2. Read from a pair of character iterators - The value_type of the iterator must be an integral type with size of 1, 2 or 4 bytes, which will be interpreted - respectively as UTF-8, UTF-16 and UTF-32. + The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted + respectively as UTF-8, UTF-16, and UTF-32. The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md). @@ -66,10 +66,10 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index (`#!cpp false`); (optional, `#!cpp false` by default) `first` (in) -: iterator to start of character range +: iterator to the start of a character range `last` (in) -: iterator to end of character range +: iterator to the end of a character range ## Return value diff --git a/docs/mkdocs/docs/api/basic_json/start_pos.md b/docs/mkdocs/docs/api/basic_json/start_pos.md new file mode 100644 index 000000000..19a31df15 --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json/start_pos.md @@ -0,0 +1,68 @@ +# nlohmann::basic_json::start_pos + +```cpp +#if JSON_DIAGNOSTIC_POSITIONS +constexpr std::size_t start_pos() const noexcept; +#endif +``` + +Returns the position of the first character in the JSON string from which the value was parsed from. + +| JSON type | return value | +|-----------|------------------------------------------------| +| object | position of the opening `{` | +| array | position of the opening `[` | +| string | position of the opening `"` | +| number | position of the first character | +| boolean | position of `t` for `true` and `f` for `false` | +| null | position of `n` | + +## Return value + +the position of the first character of the value in the parsed JSON string, if the value was created by the +[`parse`](parse.md) function, or `std::string::npos` if the value was constructed otherwise + +## Exception safety + +No-throw guarantee: this member function never throws exceptions. + +## Complexity + +Constant. + +## Notes + +!!! note "Note" + + The function is only available if macro [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) has + been defined to `#!cpp 1` before including the library header. + +!!! warning "Invalidation" + + The returned positions are only valid as long as the JSON value is not changed. The positions are *not* updated + when the JSON value is changed. + +## Examples + +??? example "Example" + + ```cpp + --8<-- "examples/diagnostic_positions.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostic_positions.output" + ``` + + The output shows the start/end positions of all the objects and fields in the JSON string. + +## See also + +- [end_pos](end_pos.md) to access the end position +- [JSON_DIAGNOSTIC_POSITIONS](../macros/json_diagnostic_positions.md) for an overview of the diagnostic positions + +## Version history + +- Added in version 3.12.0. diff --git a/docs/mkdocs/docs/api/basic_json/to_bjdata.md b/docs/mkdocs/docs/api/basic_json/to_bjdata.md index 48598a5e6..7aa331d02 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/to_bjdata.md @@ -4,13 +4,16 @@ // (1) static std::vector to_bjdata(const basic_json& j, const bool use_size = false, - const bool use_type = false); + const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2); // (2) static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false); + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2); static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false); + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2); ``` Serializes a given JSON value `j` to a byte vector using the BJData (Binary JData) serialization format. BJData aims to @@ -19,7 +22,7 @@ be more compact than JSON itself, yet more efficient to parse. 1. Returns a byte vector containing the BJData serialization. 2. Writes the BJData serialization to an output adapter. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bjdata.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md). ## Parameters @@ -36,6 +39,10 @@ The exact mapping and its limitations is described on a [dedicated page](../../f : whether to add type annotations to container types (must be combined with `#!cpp use_size = true`); optional, `#!cpp false` by default. +`version` (in) +: which version of BJData to use (see note on "Binary values" on [BJData](../../features/binary_formats/bjdata.md)); +optional, `#!cpp bjdata_version_t::draft2` by default. + ## Return value 1. BJData serialization as byte vector @@ -68,3 +75,4 @@ Linear in the size of the JSON value `j`. ## Version history - Added in version 3.11.0. +- BJData version parameter (for draft3 binary encoding) added in version 3.12.0. \ No newline at end of file diff --git a/docs/mkdocs/docs/api/basic_json/to_bson.md b/docs/mkdocs/docs/api/basic_json/to_bson.md index 5c4324a3f..d0cae0ea3 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bson.md +++ b/docs/mkdocs/docs/api/basic_json/to_bson.md @@ -15,7 +15,7 @@ so-called document). 1. Returns a byte vector containing the BSON serialization. 2. Writes the BSON serialization to an output adapter. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bson.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md). ## Parameters @@ -27,7 +27,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f ## Return value -1. BSON serialization as byte vector +1. BSON serialization as a byte vector 2. (none) ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/to_cbor.md b/docs/mkdocs/docs/api/basic_json/to_cbor.md index 0f944c481..81d66467b 100644 --- a/docs/mkdocs/docs/api/basic_json/to_cbor.md +++ b/docs/mkdocs/docs/api/basic_json/to_cbor.md @@ -10,13 +10,13 @@ static void to_cbor(const basic_json& j, detail::output_adapter o); ``` Serializes a given JSON value `j` to a byte vector using the CBOR (Concise Binary Object Representation) serialization -format. CBOR is a binary serialization format which aims to be more compact than JSON itself, yet more efficient to +format. CBOR is a binary serialization format that aims to be more compact than JSON itself, yet more efficient to parse. 1. Returns a byte vector containing the CBOR serialization. 2. Writes the CBOR serialization to an output adapter. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/cbor.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md). ## Parameters @@ -28,7 +28,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f ## Return value -1. CBOR serialization as byte vector +1. CBOR serialization as a byte vector 2. (none) ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/to_msgpack.md b/docs/mkdocs/docs/api/basic_json/to_msgpack.md index 7d40981d5..3ae43a049 100644 --- a/docs/mkdocs/docs/api/basic_json/to_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/to_msgpack.md @@ -10,12 +10,12 @@ static void to_msgpack(const basic_json& j, detail::output_adapter o); ``` Serializes a given JSON value `j` to a byte vector using the MessagePack serialization format. MessagePack is a binary -serialization format which aims to be more compact than JSON itself, yet more efficient to parse. +serialization format that aims to be more compact than JSON itself, yet more efficient to parse. 1. Returns a byte vector containing the MessagePack serialization. 2. Writes the MessagePack serialization to an output adapter. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/messagepack.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md). ## Parameters @@ -27,7 +27,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f ## Return value -1. MessagePack serialization as byte vector +1. MessagePack serialization as a byte vector 2. (none) ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/to_ubjson.md b/docs/mkdocs/docs/api/basic_json/to_ubjson.md index e3cd5d62b..a27280314 100644 --- a/docs/mkdocs/docs/api/basic_json/to_ubjson.md +++ b/docs/mkdocs/docs/api/basic_json/to_ubjson.md @@ -19,7 +19,7 @@ aims to be more compact than JSON itself, yet more efficient to parse. 1. Returns a byte vector containing the UBJSON serialization. 2. Writes the UBJSON serialization to an output adapter. -The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/ubjson.md). +The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md). ## Parameters @@ -38,7 +38,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f ## Return value -1. UBJSON serialization as byte vector +1. UBJSON serialization as a byte vector 2. (none) ## Exception safety diff --git a/docs/mkdocs/docs/api/basic_json/type_error.md b/docs/mkdocs/docs/api/basic_json/type_error.md index cda54c089..4d590556f 100644 --- a/docs/mkdocs/docs/api/basic_json/type_error.md +++ b/docs/mkdocs/docs/api/basic_json/type_error.md @@ -9,26 +9,36 @@ does not match the expected semantics. Exceptions have ids 3xx (see [list of type errors](../../home/exceptions.md#type-errors)). -```plantuml -std::exception <|-- basic_json::exception -basic_json::exception <|-- basic_json::parse_error -basic_json::exception <|-- basic_json::invalid_iterator -basic_json::exception <|-- basic_json::type_error -basic_json::exception <|-- basic_json::out_of_range -basic_json::exception <|-- basic_json::other_error +```mermaid +classDiagram + direction LR + + class std_exception ["std::exception"] { + <> + } -interface std::exception {} + class json_exception ["basic_json::exception"] { + +const int id + +const char* what() const + } + + class json_parse_error ["basic_json::parse_error"] { + +const std::size_t byte + } -class basic_json::exception { - + const int id - + const char* what() const -} + class json_invalid_iterator ["basic_json::invalid_iterator"] + class json_type_error ["basic_json::type_error"] + class json_out_of_range ["basic_json::out_of_range"] + class json_other_error ["basic_json::other_error"] -class basic_json::parse_error { - + const std::size_t byte -} + std_exception <|-- json_exception + json_exception <|-- json_parse_error + json_exception <|-- json_invalid_iterator + json_exception <|-- json_type_error + json_exception <|-- json_out_of_range + json_exception <|-- json_other_error -class basic_json::type_error #FFFF00 {} + style json_type_error fill:#CCCCFF ``` ## Member functions diff --git a/docs/mkdocs/docs/api/basic_json/unflatten.md b/docs/mkdocs/docs/api/basic_json/unflatten.md index d9778036c..5585cbc31 100644 --- a/docs/mkdocs/docs/api/basic_json/unflatten.md +++ b/docs/mkdocs/docs/api/basic_json/unflatten.md @@ -28,11 +28,11 @@ The function can throw the following exceptions: ## Complexity -Linear in the size the JSON value. +Linear in the size of the JSON value. ## Notes -Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and can not unflattened to +Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot unflattened to their original type. Apart from this example, for a JSON value `j`, the following is always true: `#!cpp j == j.flatten().unflatten()`. diff --git a/docs/mkdocs/docs/api/basic_json/update.md b/docs/mkdocs/docs/api/basic_json/update.md index a594cf9d0..267a70517 100644 --- a/docs/mkdocs/docs/api/basic_json/update.md +++ b/docs/mkdocs/docs/api/basic_json/update.md @@ -17,6 +17,11 @@ recursively merges objects with common keys. The function is motivated by Python's [dict.update](https://docs.python.org/3.6/library/stdtypes.html#dict.update) function. +## Iterator invalidation + +For [`ordered_json`](../ordered_json.md), adding a value to an object can yield a reallocation, in which case all +iterators (including the `end()` iterator) and all references to the elements are invalidated. + ## Parameters `j` (in) @@ -27,10 +32,10 @@ function. `#!c false`) `first` (in) -: begin of the range of elements to insert +: the beginning of the range of elements to insert `last` (in) -: end of the range of elements to insert +: the end of the range of elements to insert ## Exceptions @@ -139,4 +144,4 @@ function. ## Version history - Added in version 3.0.0. -- Added `merge_objects` parameter in 3.10.4. +- Added `merge_objects` parameter in 3.10.5. diff --git a/docs/mkdocs/docs/api/basic_json/value.md b/docs/mkdocs/docs/api/basic_json/value.md index edb5406ba..c9bca6be7 100644 --- a/docs/mkdocs/docs/api/basic_json/value.md +++ b/docs/mkdocs/docs/api/basic_json/value.md @@ -103,6 +103,30 @@ changes to any JSON value. 2. Logarithmic in the size of the container. 3. Logarithmic in the size of the container. +## Notes + +!!! warning "Return type" + + The value function is a template, and the return type of the function is determined by the type of the provided + default value unless otherwise specified. This can have unexpected effects. In the example below, we store a 64-bit + unsigned integer. We get exactly that value when using [`operator[]`](operator[].md). However, when we call `value` + and provide `#!c 0` as default value, then `#!c -1` is returned. The occurs, because `#!c 0` has type `#!c int` + which overflows when handling the value `#!c 18446744073709551615`. + + To address this issue, either provide a correctly typed default value or use the template parameter to specify the + desired return type. Note that this issue occurs even when a value is stored at the provided key, and the default + value is not used as the return value. + + ```cpp + --8<-- "examples/value__return_type.cpp" + ``` + + Output: + + ```json + --8<-- "examples/value__return_type.output" + ``` + ## Examples ??? example "Example: (1) access specified object element with default value" diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md index 9913a9b5c..c8e47cfa3 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md @@ -13,9 +13,9 @@ byte_container_with_subtype(const container_type& container, subtype_type subtyp byte_container_with_subtype(container_type&& container, subtype_type subtype); ``` -1. Create empty binary container without subtype. -2. Create binary container without subtype. -3. Create binary container with subtype. +1. Create an empty binary container without a subtype. +2. Create a binary container without a subtype. +3. Create a binary container with a subtype. ## Parameters diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md index c62dead36..f4bb891ee 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md @@ -5,7 +5,7 @@ void clear_subtype() noexcept; ``` Clears the binary subtype and flags the value as not having a subtype, which has implications for serialization; for -instance MessagePack will prefer the bin family over the ext family. +instance, MessagePack will prefer the bin family over the ext family. ## Exception safety diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/index.md b/docs/mkdocs/docs/api/byte_container_with_subtype/index.md index 277fffa34..85c09079b 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/index.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/index.md @@ -7,7 +7,7 @@ class byte_container_with_subtype : public BinaryType; This type extends the template parameter `BinaryType` provided to [`basic_json`](../basic_json/index.md) with a subtype used by BSON and MessagePack. This type exists so that the user does not have to specify a type themselves with a -specific naming scheme in order to override the binary type. +specific naming scheme in order to override the binary type. ## Template parameters @@ -32,4 +32,4 @@ specific naming scheme in order to override the binary type. ## Version history - Added in version 3.8.0. -- Changed type of subtypes to `#!cpp std::uint64_t` in 3.10.0. +- Changed the type of subtypes to `#!cpp std::uint64_t` in 3.10.0. diff --git a/docs/mkdocs/docs/api/json_pointer/back.md b/docs/mkdocs/docs/api/json_pointer/back.md index 240bc6e1e..7b798e368 100644 --- a/docs/mkdocs/docs/api/json_pointer/back.md +++ b/docs/mkdocs/docs/api/json_pointer/back.md @@ -4,7 +4,7 @@ const string_t& back() const; ``` -Return last reference token. +Return the last reference token. ## Return value @@ -12,7 +12,7 @@ Last reference token. ## Exceptions -Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if JSON pointer has no parent. +Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. ## Complexity diff --git a/docs/mkdocs/docs/api/json_pointer/empty.md b/docs/mkdocs/docs/api/json_pointer/empty.md index 346364ad5..96328bd23 100644 --- a/docs/mkdocs/docs/api/json_pointer/empty.md +++ b/docs/mkdocs/docs/api/json_pointer/empty.md @@ -4,7 +4,7 @@ bool empty() const noexcept; ``` -Return whether pointer points to the root document. +Return whether the pointer points to the root document. ## Return value diff --git a/docs/mkdocs/docs/api/json_pointer/index.md b/docs/mkdocs/docs/api/json_pointer/index.md index 22e246405..8b70e2de7 100644 --- a/docs/mkdocs/docs/api/json_pointer/index.md +++ b/docs/mkdocs/docs/api/json_pointer/index.md @@ -34,10 +34,10 @@ are the base for JSON patches. - [**operator/=**](operator_slasheq.md) - append to the end of the JSON pointer - [**operator/**](operator_slash.md) - create JSON Pointer by appending - [**parent_pointer**](parent_pointer.md) - returns the parent of this JSON pointer -- [**pop_back**](pop_back.md) - remove last reference token +- [**pop_back**](pop_back.md) - remove the last reference token - [**back**](back.md) - return last reference token - [**push_back**](push_back.md) - append an unescaped token at the end of the pointer -- [**empty**](empty.md) - return whether pointer points to the root document +- [**empty**](empty.md) - return whether the pointer points to the root document ## Literals diff --git a/docs/mkdocs/docs/api/json_pointer/operator_string_t.md b/docs/mkdocs/docs/api/json_pointer/operator_string_t.md index 74105a4f1..89898fa4f 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_string_t.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_string_t.md @@ -42,6 +42,10 @@ operator string_t() const --8<-- "examples/json_pointer__operator_string_t.output" ``` +## See also + +- [string_t](../basic_json/string_t.md)- type for strings + ## Version history - Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/json_pointer/pop_back.md b/docs/mkdocs/docs/api/json_pointer/pop_back.md index 3c79f3638..16b1cd4da 100644 --- a/docs/mkdocs/docs/api/json_pointer/pop_back.md +++ b/docs/mkdocs/docs/api/json_pointer/pop_back.md @@ -4,11 +4,11 @@ void pop_back(); ``` -Remove last reference token. +Remove the last reference token. ## Exceptions -Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if JSON pointer has no parent. +Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. ## Complexity diff --git a/docs/mkdocs/docs/api/json_sax/index.md b/docs/mkdocs/docs/api/json_sax/index.md index f63e85c9a..d66b7a254 100644 --- a/docs/mkdocs/docs/api/json_sax/index.md +++ b/docs/mkdocs/docs/api/json_sax/index.md @@ -17,7 +17,7 @@ processing the input. ## Member types - [**number_integer_t**](../basic_json/number_integer_t.md) - `BasicJsonType`'s type for numbers (integer) -- [**number_unsigned_t**](../basic_json/number_unsigned_t.md) - `BasicJsonType`'s type for numbers (unsigned) +- [**number_unsigned_t**](../basic_json/number_unsigned_t.md) - `BasicJsonType`'s type for numbers (unsigned) - [**number_float_t**](../basic_json/number_float_t.md) - `BasicJsonType`'s type for numbers (floating-point) - [**string_t**](../basic_json/string_t.md) - `BasicJsonType`'s type for strings - [**binary_t**](../basic_json/binary_t.md) - `BasicJsonType`'s type for binary arrays diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index ae9eb2044..59e4b3d28 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -11,6 +11,7 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_CATCH_USER(exception)**
**JSON_THROW_USER(exception)**
**JSON_TRY_USER**](json_throw_user.md) - control exceptions - [**JSON_DIAGNOSTICS**](json_diagnostics.md) - control extended diagnostics +- [**JSON_DIAGNOSTIC_POSITIONS**](json_diagnostic_positions.md) - access positions of elements - [**JSON_NOEXCEPTION**](json_noexception.md) - switch off exceptions ## Language support @@ -42,7 +43,6 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums - [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions - ## Comparison behavior - [**JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON**](json_use_legacy_discarded_value_comparison.md) - @@ -50,13 +50,34 @@ header. See also the [macro overview page](../../features/macros.md). ## Serialization/deserialization macros -- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)**
**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)** -
**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, member...)**][DefInt] - \- serialization/deserialization of types _with_ access to private variables -- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)**
**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)** -
**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, member...)**][DefNonInt] - \- serialization/deserialization of types _without_ access to private variables -- [**NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)**](nlohmann_json_serialize_enum.md) - serialization/deserialization of enum types +### Enums -[DefInt]: nlohmann_define_type_intrusive.md -[DefNonInt]: nlohmann_define_type_non_intrusive.md +- [**NLOHMANN_JSON_SERIALIZE_ENUM**](nlohmann_json_serialize_enum.md) - serialize/deserialize an enum + +### Classes and structs + +- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](nlohmann_define_type_intrusive.md) - serialize/deserialize a non-derived class + with private members +- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT**](nlohmann_define_type_intrusive.md) - serialize/deserialize a + non-derived class with private members; uses default values +- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE**](nlohmann_define_type_intrusive.md) - serialize a non-derived class + with private members +- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE**](nlohmann_define_type_non_intrusive.md) - serialize/deserialize a non-derived + class +- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](nlohmann_define_type_non_intrusive.md) - serialize/deserialize a + non-derived class; uses default values +- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](nlohmann_define_type_non_intrusive.md) - serialize a + non-derived class + +- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE**](nlohmann_define_derived_type.md) - serialize/deserialize a derived class + with private members +- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT**](nlohmann_define_derived_type.md) - serialize/deserialize a + derived class with private members; uses default values +- [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE**](nlohmann_define_derived_type.md) - serialize a derived + class with private members +- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE**](nlohmann_define_derived_type.md) - serialize/deserialize a derived + class +- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](nlohmann_define_derived_type.md) - serialize/deserialize + a derived class; uses default values +- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](nlohmann_define_derived_type.md) - serialize a derived + class diff --git a/docs/mkdocs/docs/api/macros/json_assert.md b/docs/mkdocs/docs/api/macros/json_assert.md index a093341a1..2d7b0c78a 100644 --- a/docs/mkdocs/docs/api/macros/json_assert.md +++ b/docs/mkdocs/docs/api/macros/json_assert.md @@ -9,7 +9,7 @@ This macro controls which code is executed for [runtime assertions](../../featur ## Parameters `x` (in) -: expression of scalar type +: expression of a scalar type ## Default definition @@ -79,6 +79,10 @@ Therefore, assertions can be switched off by defining `NDEBUG`. assertion error in operator[] ``` +## See also + +- [Runtime Assertions](../../features/assertions.md) - overview documentation + ## Version history - Added in version 3.9.0. diff --git a/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md b/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md new file mode 100644 index 000000000..f928f227e --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md @@ -0,0 +1,119 @@ +# JSON_DIAGNOSTIC_POSITIONS + +```cpp +#define JSON_DIAGNOSTIC_POSITIONS /* value */ +``` + +This macro enables position diagnostics for generated JSON objects. + +When enabled, two new member functions [`start_pos()`](../basic_json/start_pos.md) and +[`end_pos()`](../basic_json/end_pos.md) are added to [`basic_json`](../basic_json/index.md) values. If the value was +created by calling the[`parse`](../basic_json/parse.md) function, then these functions allow querying the byte positions +of the value in the input it was parsed from. In case the value was constructed by other means, `std::string::npos` is +returned. + +[`start_pos()`](../basic_json/start_pos.md) returns the position of the first character of a given value in the original +JSON string, while [`end_pos()`](../basic_json/end_pos.md) returns the position of the character _following_ the last +character. For objects and arrays, the first and last characters correspond to the opening or closing braces/brackets, +respectively. For primitive values, the first and last character represents the opening and closing quotes (strings) or +the first and last character of the field's numerical or predefined value (`true`, `false`, `null`), respectively. + +| JSON type | return value [`start_pos()`](../basic_json/start_pos.md) | return value [`end_pos()`](../basic_json/end_pos.md) | +|-----------|----------------------------------------------------------|------------------------------------------------------| +| object | position of the opening `{` | position after the closing `}` | +| array | position of the opening `[` | position after the closing `]` | +| string | position of the opening `"` | position after the closing `"` | +| number | position of the first character | position after the last character | +| boolean | position of `t` for `true` and `f` for `false` | position after `e` | +| null | position of `n` | position after `l` | + +Given the above, [`end_pos()`](../basic_json/end_pos.md)` - `[`start_pos()`](../basic_json/start_pos.md) for a JSON +value provides the length of the parsed JSON string for that value, including the opening or closing braces, brackets, +or quotes. + +Note that enabling this macro increases the size of every JSON value by two `std::size_t` fields and adds slight runtime +overhead to parsing, copying JSON value objects, and the generation of error messages for exceptions. It also causes +these values to be reported in those error messages. + +## Default definition + +The default value is `0` (position diagnostics are switched off). + +```cpp +#define JSON_DIAGNOSTIC_POSITIONS 0 +``` + +When the macro is not defined, the library will define it to its default value. + +## Notes + +!!! note "CMake option" + + Diagnostic positions can also be controlled with the CMake option + [`JSON_Diagnostic_Positions`](../../integration/cmake.md#json_diagnostic_positions) (`OFF` by default) + which defines `JSON_DIAGNOSTIC_POSITIONS` accordingly. + +!!! note "Availability" + + Diagnostic positions are only available if the value was created by the [`parse`](../basic_json/parse.md) function. + The [`sax_parse`](../basic_json/sax_parse.md) function or all other means to create a JSON value **do not** set the + diagnostic positions and [`start_pos()`](../basic_json/start_pos.md) and [`end_pos()`](../basic_json/end_pos.md) + will only return `std::string::npos` for these values. + +!!! warning "Invalidation" + + The returned positions are only valid as long as the JSON value is not changed. The positions are *not* updated + when the JSON value is changed. + +## Examples + +??? example "Example: retrieving positions" + + ```cpp + --8<-- "examples/diagnostic_positions.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostic_positions.output" + ``` + + The output shows the start/end positions of all the objects and fields in the JSON string. + +??? example "Example 2: using only diagnostic positions in exceptions" + + ```cpp + --8<-- "examples/diagnostic_positions_exception.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostic_positions_exception.output" + ``` + + The output shows the exception with start/end positions only. + +??? example "Example 3: using extended diagnostics with positions enabled in exceptions" + + ```cpp + --8<-- "examples/diagnostics_extended_positions.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostics_extended_positions.output" + ``` + + The output shows the exception with diagnostic path info and start/end positions. + +## See also + +- [:simple-cmake: JSON_Diagnostic_Positions](../../integration/cmake.md#json_diagnostic_positions) - CMake option to control the macro +- [JSON_DIAGNOSTICS](json_diagnostics.md) - macro to control extended diagnostics + +## Version history + +- Added in version 3.12.0. diff --git a/docs/mkdocs/docs/api/macros/json_diagnostics.md b/docs/mkdocs/docs/api/macros/json_diagnostics.md index 4fc0fc38e..91bdc1b39 100644 --- a/docs/mkdocs/docs/api/macros/json_diagnostics.md +++ b/docs/mkdocs/docs/api/macros/json_diagnostics.md @@ -9,7 +9,7 @@ Possible values are `1` to enable or `0` to disable (default). When enabled, exception messages contain a [JSON Pointer](../json_pointer/json_pointer.md) to the JSON value that triggered the exception. Note that enabling this macro increases the size of every JSON value by one pointer and adds -some runtime overhead. +some runtime overhead. ## Default definition @@ -70,7 +70,25 @@ When the macro is not defined, the library will define it to its default value. Now the exception message contains a JSON Pointer `/address/housenumber` that indicates which value has the wrong type. +??? example "Example 3: using only diagnostic positions in exceptions" + + ```cpp + --8<-- "examples/diagnostic_positions_exception.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostic_positions_exception.output" + ``` + The output shows the exception with start/end positions only. + +## See also + +- [:simple-cmake: JSON_Diagnostics](../../integration/cmake.md#json_diagnostics) - CMake option to control the macro +- [JSON_DIAGNOSTIC_POSITIONS](json_diagnostic_positions.md) - macro to access positions of elements + ## Version history - Added in version 3.10.0. -- As of version 3.11.0 the definition is allowed to vary between translation units. +- As of version 3.11.0, the definition is allowed to vary between translation units. diff --git a/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md index 6440e34e3..6acfdc2a1 100644 --- a/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md +++ b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md @@ -145,7 +145,9 @@ The default value is `0`. ## See also -- [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) +- [:simple-cmake: JSON_DisableEnumSerialization](../../integration/cmake.md#json_disableenumserialization) - CMake option to control + the macro +- [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) - serialize/deserialize an enum ## Version history diff --git a/docs/mkdocs/docs/api/macros/json_has_static_rtti.md b/docs/mkdocs/docs/api/macros/json_has_static_rtti.md index 780878319..33d0703ab 100644 --- a/docs/mkdocs/docs/api/macros/json_has_static_rtti.md +++ b/docs/mkdocs/docs/api/macros/json_has_static_rtti.md @@ -28,4 +28,4 @@ When the macro is not defined, the library will define it to its default value. ## Version history -- Added in version ?. +- Added in version 3.11.3. diff --git a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md index 374fa4c27..52cdbd172 100644 --- a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md +++ b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md @@ -4,8 +4,8 @@ #define JSON_SKIP_UNSUPPORTED_COMPILER_CHECK ``` -When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to -use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. +When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows +using the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. ## Default definition diff --git a/docs/mkdocs/docs/api/macros/json_use_global_udls.md b/docs/mkdocs/docs/api/macros/json_use_global_udls.md index 69db9e77c..3110d4662 100644 --- a/docs/mkdocs/docs/api/macros/json_use_global_udls.md +++ b/docs/mkdocs/docs/api/macros/json_use_global_udls.md @@ -92,6 +92,7 @@ When the macro is not defined, the library will define it to its default value. - [`operator""_json`](../operator_literal_json.md) - [`operator""_json_pointer`](../operator_literal_json_pointer.md) +- [:simple-cmake: JSON_GlobalUDLs](../../integration/cmake.md#json_globaludls) - CMake option to control the macro ## Version history diff --git a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md index 557dfa299..0a5ad4df4 100644 --- a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md +++ b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md @@ -27,7 +27,7 @@ By default, implicit conversions are enabled. !!! hint "CMake option" Implicit conversions can also be controlled with the CMake option - [`JSON_ImplicitConversions`](../../integration/cmake.md#json_legacydiscardedvaluecomparison) + [`JSON_ImplicitConversions`](../../integration/cmake.md#json_implicitconversions) (`ON` by default) which defines `JSON_USE_IMPLICIT_CONVERSIONS` accordingly. ## Examples @@ -53,6 +53,7 @@ By default, implicit conversions are enabled. - [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit) - [**get**](../basic_json/get.md) - get a value (explicit) +- [:simple-cmake: JSON_ImplicitConversions](../../integration/cmake.md#json_implicitconversions) - CMake option to control the macro ## Version history diff --git a/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md b/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md index bc1d1434a..b14266304 100644 --- a/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md +++ b/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md @@ -56,7 +56,7 @@ When the macro is not defined, the library will define it to its default value. !!! hint "CMake option" Legacy comparison can also be controlled with the CMake option - [`JSON_LegacyDiscardedValueComparison`](../../integration/cmake.md#json_legacydiscardedvaluecomparison) + [`JSON_LegacyDiscardedValueComparison`](../../integration/cmake.md#json_implicitconversions) (`OFF` by default) which defines `JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON` accordingly. ## Examples @@ -72,6 +72,10 @@ When the macro is not defined, the library will define it to its default value. ... ``` +### See also + +- [:simple-cmake: JSON_LegacyDiscardedValueComparison](../../integration/cmake.md#json_legacydiscardedvaluecomparison) - CMake option to control the macro + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md b/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md new file mode 100644 index 000000000..d9c9e0422 --- /dev/null +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md @@ -0,0 +1,177 @@ +

NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE

+ +```cpp +// (1) +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(type, base_type, member...) +// (2) +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) +// (3) +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...) + +// (4) +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(type, base_type, member...) +// (5) +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) +// (6) +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, base_type, member...) +``` + +These macros can be used to simplify the serialization/deserialization of derived types if you want to use a JSON +object as serialization and want to use the member variable names as object keys in that object. + +- Macros 1, 2, and 3 are to be defined **inside** the class/struct to create code for. +Like [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](nlohmann_define_type_intrusive.md), they can access private members. +- Macros 4, 5, and 6 are to be defined **outside** the class/struct to create code for, but **inside** its namespace. +Like [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](nlohmann_define_type_non_intrusive.md), +they **cannot** access private members. + +The first parameter is the name of the derived class/struct, +the second parameter is the name of the base class/struct and all remaining parameters name the members. +The base type **must** be already serializable/deserializable. + +- Macros 1 and 4 will use [`at`](../basic_json/at.md) during deserialization and will throw + [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a key is missing in the JSON object. +- Macros 2 and 5 will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the + respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function + default constructs an object and uses its values as the defaults when calling the `value` function. + +Summary: + +| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | +|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|---------------------------------------------------------------| +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE** | +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT** | +|
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE** | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE** | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT** | +|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| **NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE** | + +## Parameters + +`type` (in) +: name of the type (class, struct) to serialize/deserialize + +`base_type` (in) +: name of the base type (class, struct) `type` is derived from + +`member` (in) +: name of the member variable to serialize/deserialize; up to 64 members can be given as a comma-separated list + +## Default definition + +Macros 1 and 2 add two friend functions to the class which take care of the serialization and deserialization: + +```cpp +template +friend void to_json(BasicJsonType&, const type&); +template +friend void from_json(const BasicJsonType&, type&); +``` + +Macros 4 and 5 add two functions to the namespace which take care of the serialization and deserialization: + +```cpp +template +void to_json(BasicJsonType&, const type&); +template +void from_json(const BasicJsonType&, type&); +``` + +Macros 3 and 6 add one function to the namespace which takes care of the serialization only: + +```cpp +template +void to_json(BasicJsonType&, const type&); +``` + +In first two cases, they call the `to_json`/`from_json` functions of the base type +before serializing/deserializing the members of the derived type: + +```cpp +class A { /* ... */ }; +class B : public A { /* ... */ }; + +template +void to_json(BasicJsonType& j, const B& b) { + nlohmann::to_json(j, static_cast(b)); + // ... +} + +template +void from_json(const BasicJsonType& j, B& b) { + nlohmann::from_json(j, static_cast(b)); + // ... +} +``` + +In the third case, only `to_json` will be called: + +```cpp +class A { /* ... */ }; +class B : public A { /* ... */ }; + +template +void to_json(BasicJsonType& j, const B& b) { + nlohmann::to_json(j, static_cast(b)); + // ... +} +``` + +## Notes + +!!! info "Prerequisites" + + - Macros 1, 2, and 3 have the same prerequisites of [NLOHMANN_DEFINE_TYPE_INTRUSIVE](nlohmann_define_type_intrusive.md). + - Macros 4, 5, and 6 have the same prerequisites of [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE](nlohmann_define_type_non_intrusive.md). + - Serialization/deserialization of base types must be defined. + +!!! warning "Implementation limits" + + See Implementation limits for [NLOHMANN_DEFINE_TYPE_INTRUSIVE](nlohmann_define_type_intrusive.md) and + [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE](nlohmann_define_type_non_intrusive.md), respectively. + +## Examples + +??? example "NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE" + + Consider the following complete example: + + ```cpp hl_lines="28" + --8<-- "examples/nlohmann_define_derived_type_intrusive_macro.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_define_derived_type_intrusive_macro.output" + ``` + + Notes: + + - `A` and `B` are default-constructible. This is a requirement for using the macro. + - `A` has private members and is not a derived class. Hence, macro `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is used. + - As `B` is a derived class, `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is not applicable, but + `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE` must be used. + - The macro `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE` is used _inside_ the class use as + `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. + +## See also + +- [NLOHMANN_DEFINE_TYPE_INTRUSIVE / NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT / + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_intrusive.md) + for similar macros that can be defined _inside_ a non-derived type. +- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE / NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT / + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_non_intrusive.md) + for similar macros that can be defined _outside_ a non-derived type. +- [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview. + +## Version history + +1. Added in version 3.12.0. +2. Added in version 3.12.0. +3. Added in version 3.12.0. +4. Added in version 3.12.0. +5. Added in version 3.12.0. +6. Added in version 3.12.0. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md b/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md index ad425810a..32fb68ee2 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md @@ -17,7 +17,15 @@ parameter is the name of the class/struct, and all remaining parameters name the 2. Will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function default constructs an object and uses its values as the defaults when calling the `value` function. -3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization in required. +3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization is required. + +Summary: + +| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | +|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|-------------------------------------------------------| +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| **NLOHMANN_DEFINE_TYPE_INTRUSIVE** | +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| **NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT** | +|
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| **NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE** | ## Parameters @@ -25,15 +33,17 @@ parameter is the name of the class/struct, and all remaining parameters name the : name of the type (class, struct) to serialize/deserialize `member` (in) -: name of the member variable to serialize/deserialize; up to 64 members can be given as comma-separated list +: name of the member variable to serialize/deserialize; up to 64 members can be given as a comma-separated list ## Default definition The macros add two friend functions to the class which take care of the serialization and deserialization: ```cpp -friend void to_json(nlohmann::json&, const type&); -friend void from_json(const nlohmann::json&, type&); // except (3) +template +friend void to_json(BasicJsonType&, const type&); +template +friend void from_json(const BasicJsonType&, type&); // except (3) ``` See examples below for the concrete generated code. @@ -52,8 +62,6 @@ See examples below for the concrete generated code. - The current implementation is limited to at most 64 member variables. If you want to serialize/deserialize types with more than 64 member variables, you need to define the `to_json`/`from_json` functions manually. - - The macros only work for the [`nlohmann::json`](../json.md) type; other specializations such as - [`nlohmann::ordered_json`](../ordered_json.md) are currently unsupported. ## Examples @@ -82,7 +90,7 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34" + ```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35 36" --8<-- "examples/nlohmann_define_type_intrusive_explicit.cpp" ``` @@ -110,7 +118,7 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35" + ```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37" --8<-- "examples/nlohmann_define_type_intrusive_with_default_explicit.cpp" ``` @@ -139,18 +147,24 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="22 22 23 24 25 26 27" + ```cpp hl_lines="22 22 23 24 25 26 27 28" --8<-- "examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp" ``` ## See also -- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE{_WITH_DEFAULT, _ONLY_SERIALIZE}](nlohmann_define_type_non_intrusive.md) +- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_non_intrusive.md) for a similar macro that can be defined _outside_ the type. +- [NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_derived_type.md) for similar macros for + derived types - [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview. ## Version history 1. Added in version 3.9.0. 2. Added in version 3.11.0. -3. Added in version TODO. +3. Added in version 3.11.3. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md b/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md index 5830f8ca9..2bbf0a690 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md @@ -17,7 +17,15 @@ parameter is the name of the class/struct, and all remaining parameters name the 2. Will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function default constructs an object and uses its values as the defaults when calling the `value` function. -3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization in required. +3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization is required. + +Summary: + +| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | +|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|-------------------------------------------------------| +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| **NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE** | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| **NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT** | +|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| **NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE** | ## Parameters @@ -25,15 +33,17 @@ parameter is the name of the class/struct, and all remaining parameters name the : name of the type (class, struct) to serialize/deserialize `member` (in) -: name of the (public) member variable to serialize/deserialize; up to 64 members can be given as comma-separated list +: name of the (public) member variable to serialize/deserialize; up to 64 members can be given as a comma-separated list ## Default definition The macros add two functions to the namespace which take care of the serialization and deserialization: ```cpp -void to_json(nlohmann::json&, const type&); -void from_json(const nlohmann::json&, type&); // except (3) +template +void to_json(BasicJsonType&, const type&); +template +void from_json(const BasicJsonType&, type&); // except (3) ``` See examples below for the concrete generated code. @@ -53,8 +63,6 @@ See examples below for the concrete generated code. - The current implementation is limited to at most 64 member variables. If you want to serialize/deserialize types with more than 64 member variables, you need to define the `to_json`/`from_json` functions manually. - - The macros only work for the [`nlohmann::json`](../json.md) type; other specializations such as - [`nlohmann::ordered_json`](../ordered_json.md) are currently unsupported. ## Examples @@ -82,7 +90,7 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="16 17 18 19 20 21 22 23 24 25 26 27 28" + ```cpp hl_lines="16 17 18 19 20 21 22 23 24 25 26 27 28 29 30" --8<-- "examples/nlohmann_define_type_non_intrusive_explicit.cpp" ``` @@ -90,7 +98,7 @@ See examples below for the concrete generated code. Consider the following complete example: - ```cpp hl_lines="22" + ```cpp hl_lines="21" --8<-- "examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp" ``` @@ -111,7 +119,7 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35" + ```cpp hl_lines="21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36" --8<-- "examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp" ``` @@ -140,18 +148,24 @@ See examples below for the concrete generated code. The macro is equivalent to: - ```cpp hl_lines="16 17 18 19 20 21" + ```cpp hl_lines="16 17 18 19 20 21 22" --8<-- "examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp" ``` ## See also -- [NLOHMANN_DEFINE_TYPE_INTRUSIVE{_WITH_DEFAULT, _ONLY_SERIALIZE}](nlohmann_define_type_intrusive.md) +- [NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_intrusive.md) for a similar macro that can be defined _inside_ the type. +- [NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_derived_type.md) for similar macros for + derived types - [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview. ## Version history 1. Added in version 3.9.0. 2. Added in version 3.11.0. -3. Added in version TODO. +3. Added in version 3.11.3. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md index dc2cc8ecb..c54f9195f 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md @@ -5,7 +5,7 @@ ``` By default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an -enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be +enum is modified or re-ordered after data has been serialized to JSON, the later deserialized JSON data may be undefined or a different enum value than was originally intended. The `NLOHMANN_JSON_SERIALIZE_ENUM` allows to define a user-defined serialization for every enumerator. @@ -20,7 +20,7 @@ The `NLOHMANN_JSON_SERIALIZE_ENUM` allows to define a user-defined serialization ## Default definition -The macros add two friend functions to the class which take care of the serialization and deserialization: +The macro adds two functions to the namespace which take care of the serialization and deserialization: ```cpp template diff --git a/docs/mkdocs/docs/api/operator_gtgt.md b/docs/mkdocs/docs/api/operator_gtgt.md index e76cc0db7..f332a7517 100644 --- a/docs/mkdocs/docs/api/operator_gtgt.md +++ b/docs/mkdocs/docs/api/operator_gtgt.md @@ -21,8 +21,8 @@ the stream `i` ## Exceptions - Throws [`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token. -- Throws [`parse_error.102`](../home/exceptions.md#jsonexceptionparse_error102) if to_unicode fails or surrogate error. -- Throws [`parse_error.103`](../home/exceptions.md#jsonexceptionparse_error103) if to_unicode fails. +- Throws [`parse_error.102`](../home/exceptions.md#jsonexceptionparse_error102) if `to_unicode` fails or surrogate error. +- Throws [`parse_error.103`](../home/exceptions.md#jsonexceptionparse_error103) if `to_unicode` fails. ## Complexity diff --git a/docs/mkdocs/docs/api/operator_literal_json.md b/docs/mkdocs/docs/api/operator_literal_json.md index bc2b2cfc5..a3a4bd28b 100644 --- a/docs/mkdocs/docs/api/operator_literal_json.md +++ b/docs/mkdocs/docs/api/operator_literal_json.md @@ -17,7 +17,7 @@ using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -['JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. ## Parameters diff --git a/docs/mkdocs/docs/api/operator_literal_json_pointer.md b/docs/mkdocs/docs/api/operator_literal_json_pointer.md index 0e12440e1..423678c77 100644 --- a/docs/mkdocs/docs/api/operator_literal_json_pointer.md +++ b/docs/mkdocs/docs/api/operator_literal_json_pointer.md @@ -16,7 +16,7 @@ using namespace nlohmann::literals::json_literals; using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -['JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. ## Parameters diff --git a/docs/mkdocs/docs/api/operator_ltlt.md b/docs/mkdocs/docs/api/operator_ltlt.md index 1718b3c9e..8dedb0509 100644 --- a/docs/mkdocs/docs/api/operator_ltlt.md +++ b/docs/mkdocs/docs/api/operator_ltlt.md @@ -84,4 +84,4 @@ Linear. 1. Added in version 1.0.0. Added support for indentation character and deprecated `#!cpp std::ostream& operator>>(const basic_json& j, std::ostream& o)` in version 3.0.0. -3. Added in version 3.11.0. +2. Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/ordered_json.md b/docs/mkdocs/docs/api/ordered_json.md index 7cfd9f4dd..f4062d13d 100644 --- a/docs/mkdocs/docs/api/ordered_json.md +++ b/docs/mkdocs/docs/api/ordered_json.md @@ -6,6 +6,13 @@ using ordered_json = basic_json; This type preserves the insertion order of object keys. +## Iterator invalidation + +The type is based on [`ordered_map`](ordered_map.md) which in turn uses a `std::vector` to store object elements. +Therefore, adding object elements can yield a reallocation in which case all iterators (including the +[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or +reference after the insertion point will point to the same index which is now a different value. + ## Examples ??? example diff --git a/docs/mkdocs/docs/api/ordered_map.md b/docs/mkdocs/docs/api/ordered_map.md index 160b85c28..ca4934161 100644 --- a/docs/mkdocs/docs/api/ordered_map.md +++ b/docs/mkdocs/docs/api/ordered_map.md @@ -23,6 +23,11 @@ A minimal map-like container that preserves insertion order for use within [`nlo `Allocator` : allocator type +## Iterator invalidation + +The type uses a `std::vector` to store object elements. Therefore, adding elements can yield a reallocation in which +case all iterators (including the `end()` iterator) and all references to the elements are invalidated. + ## Member types - **key_type** - key type (`Key`) diff --git a/docs/mkdocs/docs/community/code_of_conduct.md b/docs/mkdocs/docs/community/code_of_conduct.md new file mode 100644 index 000000000..0685e0e57 --- /dev/null +++ b/docs/mkdocs/docs/community/code_of_conduct.md @@ -0,0 +1 @@ +--8<-- "../../../.github/CODE_OF_CONDUCT.md" diff --git a/docs/mkdocs/docs/community/contribution_guidelines.md b/docs/mkdocs/docs/community/contribution_guidelines.md new file mode 100644 index 000000000..d439f1cfb --- /dev/null +++ b/docs/mkdocs/docs/community/contribution_guidelines.md @@ -0,0 +1 @@ +--8<-- "../../../.github/CONTRIBUTING.md" diff --git a/docs/mkdocs/docs/community/governance.md b/docs/mkdocs/docs/community/governance.md new file mode 100644 index 000000000..7da85f3fe --- /dev/null +++ b/docs/mkdocs/docs/community/governance.md @@ -0,0 +1,122 @@ +# Governance + +The governance model for the JSON for Modern C++ project is a **Benevolent Dictator for Life (BDFL)** structure. As the +sole maintainer, [Niels Lohmann](https://github.com/nlohmann) is responsible for all key aspects of the project. The +project governance may evolve as the project grows, but any changes will be documented here and communicated to +contributors. + +## Overview + +This project is led by a benevolent dictator, [Niels Lohmann](https://github.com/nlohmann), and managed by the +community. That is, the community actively contributes to the day-to-day maintenance of the project, but the general +strategic line is drawn by the benevolent dictator. In case of disagreement, they have the last word. It is the +benevolent dictator’s job to resolve disputes within the community and to ensure that the project is able to progress in +a coordinated way. In turn, it is the community’s job to guide the decisions of the benevolent dictator through active +engagement and contribution. + +## Roles and responsibilities + +### Benevolent dictator (project lead) + +Typically, the benevolent dictator, or project lead, is self-appointed. However, because the community always has the +ability to fork, this person is fully answerable to the community. The project lead’s role is a difficult one: they set +the strategic objectives of the project and communicate these clearly to the community. They also have to understand the +community as a whole and strive to satisfy as many conflicting needs as possible, while ensuring that the project +survives in the long term. + +In many ways, the role of the benevolent dictator is less about dictatorship and more about diplomacy. The key is to +ensure that, as the project expands, the right people are given influence over it and the community rallies behind the +vision of the project lead. The lead’s job is then to ensure that the committers (see below) make the right decisions on +behalf of the project. Generally speaking, as long as the committers are aligned with the project’s strategy, the +project lead will allow them to proceed as they desire. + +### Committers + +Committers are contributors who have made several valuable contributions to the project and are now relied upon to both +write code directly to the repository and screen the contributions of others. In many cases they are programmers but it +is also possible that they contribute in a different role. Typically, a committer will focus on a specific aspect of the +project, and will bring a level of expertise and understanding that earns them the respect of the community and the +project lead. The role of committer is not an official one, it is simply a position that influential members of the +community will find themselves in as the project lead looks to them for guidance and support. + +Committers have no authority over the overall direction of the project. However, they do have the ear of the project +lead. It is a committer’s job to ensure that the lead is aware of the community’s needs and collective objectives, and +to help develop or elicit appropriate contributions to the project. Often, committers are given informal control over +their specific areas of responsibility, and are assigned rights to directly modify certain areas of the source code. +That is, although committers do not have explicit decision-making authority, they will often find that their actions are +synonymous with the decisions made by the lead. + +### Contributors + +Contributors are community members who either have no desire to become committers, or have not yet been given the +opportunity by the benevolent dictator. They make valuable contributions, such as those outlined in the list below, but +generally do not have the authority to make direct changes to the project code. Contributors engage with the project +through communication tools, such as email lists, and via reports and patches attached to issues in the issue tracker, +as detailed in our community tools document. + +Anyone can become a contributor. There is no expectation of commitment to the project, no specific skill requirements +and no selection process. To become a contributor, a community member simply has to perform one or more actions that are +beneficial to the project. + +Some contributors will already be engaging with the project as users, but will also find themselves doing one or more of +the following: + +- supporting new users (current users often provide the most effective new user support) +- reporting bugs +- identifying requirements +- supplying graphics and web design +- programming +- assisting with project infrastructure +- writing documentation +- fixing bugs +- adding features + +As contributors gain experience and familiarity with the project, they may find that the project lead starts relying on +them more and more. When this begins to happen, they gradually adopt the role of committer, as described above. + +### Users + +Users are community members who have a need for the project. They are the most important members of the community: +without them, the project would have no purpose. Anyone can be a user; there are no specific requirements. + +Users should be encouraged to participate in the life of the project and the community as much as possible. User +contributions enable the project team to ensure that they are satisfying the needs of those users. Common user +activities include (but are not limited to): + +- evangelising about the project +- informing developers of project strengths and weaknesses from a new user’s perspective +- providing moral support (a ‘thank you’ goes a long way) +- providing financial support + +Users who continue to engage with the project and its community will often find themselves becoming more and more +involved. Such users may then go on to become contributors, as described above. + +## Support + +All participants in the community are encouraged to provide support for new users within the project management +infrastructure. This support is provided as a way of growing the community. Those seeking support should recognise that +all support activity within the project is voluntary and is therefore provided as and when time allows. A user requiring +guaranteed response times or results should therefore seek to purchase a support contract from a vendor. (Of course, +that vendor should be an active member of the community.) However, for those willing to engage with the project on its +own terms, and willing to help support other users, the community support channels are ideal. + +## Contribution Process + +Anyone can contribute to the project, regardless of their skills, as there are many ways to contribute. For instance, a +contributor might be active on the project mailing list and issue tracker, or might supply patches. The various ways of +contributing are described in more detail in our roles in open source document. + +The developer mailing list is the most appropriate place for a contributor to ask for help when making their first +contribution. + +## Decision-Making Process + +The benevolent dictatorship model does not need a formal conflict resolution process, since the project lead’s word is +final. If the community chooses to question the wisdom of the actions of a committer, the project lead can review their +decisions by checking the email archives, and either uphold or reverse them. + +--- + +!!! quote "Source" + + The text was taken from http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel. diff --git a/docs/mkdocs/docs/community/index.md b/docs/mkdocs/docs/community/index.md new file mode 100644 index 000000000..caef17be3 --- /dev/null +++ b/docs/mkdocs/docs/community/index.md @@ -0,0 +1,7 @@ +# Community + +- [Code of Conduct](code_of_conduct.md) - the rules and norms of this project +- [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project +- [Governance](governance.md) - the governance model of this project +- [Quality Assurance](quality_assurance.md) - how the quality of this project is assured +- [Security Policy](security_policy.md) - the security policy of the project diff --git a/docs/mkdocs/docs/community/quality_assurance.md b/docs/mkdocs/docs/community/quality_assurance.md new file mode 100644 index 000000000..134926ca1 --- /dev/null +++ b/docs/mkdocs/docs/community/quality_assurance.md @@ -0,0 +1,214 @@ +# Quality assurance + +Ensuring quality is paramount for this project, particularly because [numerous other projects](../home/customers.md) +depend on it. Each commit to the library undergoes rigorous checks against the following requirements, and any +violations will result in a failed build. + +## C++ language compliance and compiler compatibility + +!!! success "Requirement: Compiler support" + + Any compiler with complete C++11 support can compile the library without warnings. + +- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms, + including the oldest versions known to compile the library. + + ??? abstract "Compilers used in continuous integration" + + | Compiler | Architecture | Operating System | CI | + |----------------------------------------------|--------------|--------------------------|-----------| + | AppleClang 14.0.0.14000029; Xcode 14.1 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 14.0.0.14000029; Xcode 14.2 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 14.0.3.14030022; Xcode 14.3.1 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 15.0.0.15000040; Xcode 15.0.1 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 15.0.0.15000100; Xcode 15.1 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 15.0.0.15000100; Xcode 15.2 | x86_64 | macOS 13.7.2 (Ventura) | GitHub | + | AppleClang 15.0.0.15000309; Xcode 15.3 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | + | AppleClang 15.0.0.15000309; Xcode 15.4 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | + | AppleClang 16.0.0.16000026; Xcode 16 | arm64 | macOS 15.2 (Sequoia) | GitHub | + | AppleClang 16.0.0.16000026; Xcode 16.1 | arm64 | macOS 15.2 (Sequoia) | GitHub | + | AppleClang 16.0.0.16000026; Xcode 16.2 | arm64 | macOS 15.2 (Sequoia) | GitHub | + | Clang 3.5.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 3.6.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 3.7.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 3.8.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 3.9.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 4.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 5.0.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 6.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 7.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 8.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 9.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 10.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 11.0.0 with GNU-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 11.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 12.0.0 with GNU-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 12.0.0 with MSVC-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 12.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 13.0.0 with GNU-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 13.0.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 14.0.0 with GNU-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 14.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 15.0.0 with GNU-like command-line | x86_64 | Windows 10 (Build 17763) | GitHub | + | Clang 15.0.7 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 16.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 17.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 18.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 19.1.7 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 21.0.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 5.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 6.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 7.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 8.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 9.3.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 9.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 9.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 10.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 11.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 11.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 12.2.0 (MinGW-W64 i686-ucrt-posix-dwarf) | x86_64 | Windows 10 (Build 17763) | GitHub | + | GNU 12.2.0 (MinGW-W64 x86_64-ucrt-posix-seh) | x86_64 | Windows 10 (Build 17763) | GitHub | + | GNU 12.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 13.3.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 14.2.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 14.2.0 | arm64 | Linux 6.1.100 | Cirrus CI | + | MSVC 19.0.24241.7 | x86 | Windows 8.1 | AppVeyor | + | MSVC 19.16.27035.0 | x86 | Windows-10 (Build 14393) | AppVeyor | + | MSVC 19.29.30157.0 | x86 | Windows 10 (Build 17763) | GitHub | + | MSVC 19.29.30157.0 | x86_64 | Windows 10 (Build 17763) | GitHub | + | MSVC 19.29.30157.0 | x86 | Windows-10 (Build 17763) | AppVeyor | + | MSVC 19.42.34435.0 | x86 | Windows 10 (Build 20348) | GitHub | + | MSVC 19.42.34435.0 | x86_64 | Windows 10 (Build 20348) | GitHub | + +- [x] The library is compiled with all C++ language revisions (C++11, C++14, C++17, C++20, C++23, and C++26) to detect + and fix language deprecations early. +- [x] The library is checked for compiler warnings: + - On Clang, `-Weverything` is used with 7 exceptions. + + ??? abstract "Clang warnings" + + ```cmake + --8<-- "../../../cmake/clang_flags.cmake" + ``` + + - On GCC, 300+ warnings are enabled with 8 exceptions. + + ??? abstract "GCC warnings" + + ```cmake + --8<-- "../../../cmake/gcc_flags.cmake" + ``` + +## C++ standard library compliance + +!!! success "Requirement: No prerequisites" + + The library has no prerequisites other than the Standard Template Library (STL). + +- [x] The library is compiled and tested with both [libc++](https://libcxx.llvm.org) and + [libstdc++](https://gcc.gnu.org/onlinedocs/libstdc++/) to detect subtle differences or incompatibilities. +- [x] The code checked with [Include What You Use (IWYU)](https://include-what-you-use.org) that all required standard + headers are included. +- [x] On Windows, the library is compiled with `` being included to detect and avoid common bugs. +- [x] The library is compiled with exceptions disabled to support alternative means of error handling. + +## Stable public API + +!!! success "Requirement: Stable public API" + + Any change to the library does not break the public API. + +- [x] All public API functions are tested with a variety of arguments. +- [x] The library is compiled and tested with different template arguments for number, string, array, and object types. +- [x] Unit tests cover all lines of the code base. +- [x] Every exception of the library is thrown in the test suite, and the error messages and exception ids are checked. + +!!! success "Requirement: Complete documentation" + + The public API is extensively documented. + +- [x] Every public API function has a dedicated page in the + [API reference documentation](https://json.nlohmann.me/api/basic_json/) with a self-contained code example. +- [x] All examples in the documentation are tested, and changes in their output are treated as an error. + +## Robust input processing + +!!! success "Requirement: Standards compliance" + + The library is compliant to JSON as defined in [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259). + +- [x] The lexer is tested with all valid Unicode code points and all prefixes of all invalid Unicode code points. +- [x] The parser is tested against extensive correctness suites for JSON compliance. +- [x] In addition, the library is continuously fuzz-tested at [OSS-Fuzz](https://google.github.io/oss-fuzz/) where the + library is checked against billions of inputs. + +## Static analysis + +!!! success "Requirement: State-of-the-art code analysis" + + The code is checked with state-of-the-art static code analysis tools. + +- [x] The code is checked with the latest [Clang-Tidy](https://clang.llvm.org/extra/clang-tidy/). + + ??? abstract "Clang-Tidy configuration (.clang-tidy)" + + ```ini + --8<-- "../../../.clang-tidy" + ``` + +- [x] The code is checked with the latest [Cppcheck](https://cppcheck.sourceforge.io) with all warnings enabled. +- [x] The code is checked with the latest [Clang Static Analyzer](https://clang-analyzer.llvm.org) with 89 enabled + rules. +- [x] The code is checked with [Infer](https://fbinfer.com). +- [x] The code is checked with [Codacy](https://app.codacy.com/gh/nlohmann/json/dashboard). + +## Dynamic analysis + +!!! success "Requirement: Correctness" + + The library is checked for memory correctness and absence of undefined behavior. + +- [x] The test suite is executed with enabled [runtime assertions](https://json.nlohmann.me/features/assertions/) to + check invariants and preconditions of functions to detect undefined behavior. +- [x] The test suite is executed with [Valgrind](https://valgrind.org) (Memcheck) to detect memory leaks. +- [x] The test suite is executed with [Sanitizers](https://github.com/google/sanitizers) (address sanitizer, undefined + behavior sanitizer, integer overflow detection, nullability violations). + +## Style check + +!!! success "Requirement: Common code style" + + A common code style is used throughout all code files of the library. + +- [x] The code is formatted with [Artistic Style](https://astyle.sourceforge.net) (astyle) against a style configuration + that is also enforced in the CI. + + ??? abstract "Astyle configuration (tools/astyle/.astylerc)" + + ```ini + --8<-- "../../../tools/astyle/.astylerc" + ``` + +- [x] The code style is checked with [cpplint](https://github.com/cpplint/cpplint) with 61 enabled rules. + +## Simple integration + +!!! success "Requirement: Single header" + + The library can be used by adding a single header to a C++ project. + +- [x] An amalgamation script is used to check if the source code is exposed as a self-contained single-header file. +- [x] The test suite is checked against the amalgamated source file as well as the individual source file. + +!!! success "Requirement: CMake as primary development tool" + + All library functions are exposed and usable by CMake. + +- [x] All library options are exposed as [CMake options](https://json.nlohmann.me/integration/cmake/) and tested. +- [x] The library is tested against relevant CMake versions: + - CMake 3.5 (the earliest supported) + - CMake 3.31.6 (the latest 3.x release) + - CMake 4.0.0 (a very recent release) diff --git a/docs/mkdocs/docs/community/security_policy.md b/docs/mkdocs/docs/community/security_policy.md new file mode 100644 index 000000000..fdee281cb --- /dev/null +++ b/docs/mkdocs/docs/community/security_policy.md @@ -0,0 +1 @@ +--8<-- "../../../.github/SECURITY.md" diff --git a/docs/mkdocs/docs/css/custom.css b/docs/mkdocs/docs/css/custom.css index 7a1008b0b..8940a782e 100644 --- a/docs/mkdocs/docs/css/custom.css +++ b/docs/mkdocs/docs/css/custom.css @@ -1,4 +1,4 @@ -/* disable ligatures in code and preformatted blocks */ -code, pre { - font-variant-ligatures: none; +/* enable ligatures in code and preformatted blocks */ +.md-typeset code, .md-typeset pre { + font-variant-ligatures: common-ligatures; } diff --git a/docs/examples/README.cpp b/docs/mkdocs/docs/examples/README.cpp similarity index 100% rename from docs/examples/README.cpp rename to docs/mkdocs/docs/examples/README.cpp diff --git a/docs/examples/README.output b/docs/mkdocs/docs/examples/README.output similarity index 100% rename from docs/examples/README.output rename to docs/mkdocs/docs/examples/README.output diff --git a/docs/examples/accept__string.cpp b/docs/mkdocs/docs/examples/accept__string.cpp similarity index 100% rename from docs/examples/accept__string.cpp rename to docs/mkdocs/docs/examples/accept__string.cpp diff --git a/docs/examples/accept__string.output b/docs/mkdocs/docs/examples/accept__string.output similarity index 100% rename from docs/examples/accept__string.output rename to docs/mkdocs/docs/examples/accept__string.output diff --git a/docs/examples/array.cpp b/docs/mkdocs/docs/examples/array.cpp similarity index 100% rename from docs/examples/array.cpp rename to docs/mkdocs/docs/examples/array.cpp diff --git a/docs/examples/array.output b/docs/mkdocs/docs/examples/array.output similarity index 100% rename from docs/examples/array.output rename to docs/mkdocs/docs/examples/array.output diff --git a/docs/examples/array_t.cpp b/docs/mkdocs/docs/examples/array_t.cpp similarity index 100% rename from docs/examples/array_t.cpp rename to docs/mkdocs/docs/examples/array_t.cpp diff --git a/docs/examples/array_t.output b/docs/mkdocs/docs/examples/array_t.output similarity index 100% rename from docs/examples/array_t.output rename to docs/mkdocs/docs/examples/array_t.output diff --git a/docs/examples/at__json_pointer.cpp b/docs/mkdocs/docs/examples/at__json_pointer.cpp similarity index 100% rename from docs/examples/at__json_pointer.cpp rename to docs/mkdocs/docs/examples/at__json_pointer.cpp diff --git a/docs/examples/at__json_pointer.output b/docs/mkdocs/docs/examples/at__json_pointer.output similarity index 100% rename from docs/examples/at__json_pointer.output rename to docs/mkdocs/docs/examples/at__json_pointer.output diff --git a/docs/examples/at__json_pointer_const.cpp b/docs/mkdocs/docs/examples/at__json_pointer_const.cpp similarity index 100% rename from docs/examples/at__json_pointer_const.cpp rename to docs/mkdocs/docs/examples/at__json_pointer_const.cpp diff --git a/docs/examples/at__json_pointer_const.output b/docs/mkdocs/docs/examples/at__json_pointer_const.output similarity index 100% rename from docs/examples/at__json_pointer_const.output rename to docs/mkdocs/docs/examples/at__json_pointer_const.output diff --git a/docs/examples/at__keytype.c++17.cpp b/docs/mkdocs/docs/examples/at__keytype.c++17.cpp similarity index 100% rename from docs/examples/at__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/at__keytype.c++17.cpp diff --git a/docs/examples/at__keytype.c++17.output b/docs/mkdocs/docs/examples/at__keytype.c++17.output similarity index 100% rename from docs/examples/at__keytype.c++17.output rename to docs/mkdocs/docs/examples/at__keytype.c++17.output diff --git a/docs/examples/at__keytype_const.c++17.cpp b/docs/mkdocs/docs/examples/at__keytype_const.c++17.cpp similarity index 96% rename from docs/examples/at__keytype_const.c++17.cpp rename to docs/mkdocs/docs/examples/at__keytype_const.c++17.cpp index b08cd17b5..712d456e6 100644 --- a/docs/examples/at__keytype_const.c++17.cpp +++ b/docs/mkdocs/docs/examples/at__keytype_const.c++17.cpp @@ -36,7 +36,7 @@ int main() // try to read from a nonexisting key using string_view std::cout << object.at("the fast"sv) << '\n'; } - catch (const json::out_of_range) + catch (const json::out_of_range& e) { std::cout << "out of range" << '\n'; } diff --git a/docs/examples/at__keytype_const.c++17.output b/docs/mkdocs/docs/examples/at__keytype_const.c++17.output similarity index 100% rename from docs/examples/at__keytype_const.c++17.output rename to docs/mkdocs/docs/examples/at__keytype_const.c++17.output diff --git a/docs/examples/at__object_t_key_type.cpp b/docs/mkdocs/docs/examples/at__object_t_key_type.cpp similarity index 100% rename from docs/examples/at__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/at__object_t_key_type.cpp diff --git a/docs/examples/at__object_t_key_type.output b/docs/mkdocs/docs/examples/at__object_t_key_type.output similarity index 100% rename from docs/examples/at__object_t_key_type.output rename to docs/mkdocs/docs/examples/at__object_t_key_type.output diff --git a/docs/examples/at__object_t_key_type_const.cpp b/docs/mkdocs/docs/examples/at__object_t_key_type_const.cpp similarity index 100% rename from docs/examples/at__object_t_key_type_const.cpp rename to docs/mkdocs/docs/examples/at__object_t_key_type_const.cpp diff --git a/docs/examples/at__object_t_key_type_const.output b/docs/mkdocs/docs/examples/at__object_t_key_type_const.output similarity index 100% rename from docs/examples/at__object_t_key_type_const.output rename to docs/mkdocs/docs/examples/at__object_t_key_type_const.output diff --git a/docs/examples/at__size_type.cpp b/docs/mkdocs/docs/examples/at__size_type.cpp similarity index 100% rename from docs/examples/at__size_type.cpp rename to docs/mkdocs/docs/examples/at__size_type.cpp diff --git a/docs/examples/at__size_type.output b/docs/mkdocs/docs/examples/at__size_type.output similarity index 100% rename from docs/examples/at__size_type.output rename to docs/mkdocs/docs/examples/at__size_type.output diff --git a/docs/examples/at__size_type_const.cpp b/docs/mkdocs/docs/examples/at__size_type_const.cpp similarity index 100% rename from docs/examples/at__size_type_const.cpp rename to docs/mkdocs/docs/examples/at__size_type_const.cpp diff --git a/docs/examples/at__size_type_const.output b/docs/mkdocs/docs/examples/at__size_type_const.output similarity index 100% rename from docs/examples/at__size_type_const.output rename to docs/mkdocs/docs/examples/at__size_type_const.output diff --git a/docs/examples/back.cpp b/docs/mkdocs/docs/examples/back.cpp similarity index 100% rename from docs/examples/back.cpp rename to docs/mkdocs/docs/examples/back.cpp diff --git a/docs/examples/back.output b/docs/mkdocs/docs/examples/back.output similarity index 100% rename from docs/examples/back.output rename to docs/mkdocs/docs/examples/back.output diff --git a/docs/examples/basic_json__CompatibleType.cpp b/docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp similarity index 100% rename from docs/examples/basic_json__CompatibleType.cpp rename to docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp diff --git a/docs/examples/basic_json__CompatibleType.output b/docs/mkdocs/docs/examples/basic_json__CompatibleType.output similarity index 100% rename from docs/examples/basic_json__CompatibleType.output rename to docs/mkdocs/docs/examples/basic_json__CompatibleType.output diff --git a/docs/examples/basic_json__InputIt_InputIt.cpp b/docs/mkdocs/docs/examples/basic_json__InputIt_InputIt.cpp similarity index 100% rename from docs/examples/basic_json__InputIt_InputIt.cpp rename to docs/mkdocs/docs/examples/basic_json__InputIt_InputIt.cpp diff --git a/docs/examples/basic_json__InputIt_InputIt.output b/docs/mkdocs/docs/examples/basic_json__InputIt_InputIt.output similarity index 100% rename from docs/examples/basic_json__InputIt_InputIt.output rename to docs/mkdocs/docs/examples/basic_json__InputIt_InputIt.output diff --git a/docs/examples/basic_json__basic_json.cpp b/docs/mkdocs/docs/examples/basic_json__basic_json.cpp similarity index 100% rename from docs/examples/basic_json__basic_json.cpp rename to docs/mkdocs/docs/examples/basic_json__basic_json.cpp diff --git a/docs/examples/basic_json__basic_json.output b/docs/mkdocs/docs/examples/basic_json__basic_json.output similarity index 100% rename from docs/examples/basic_json__basic_json.output rename to docs/mkdocs/docs/examples/basic_json__basic_json.output diff --git a/docs/examples/basic_json__copyassignment.cpp b/docs/mkdocs/docs/examples/basic_json__copyassignment.cpp similarity index 100% rename from docs/examples/basic_json__copyassignment.cpp rename to docs/mkdocs/docs/examples/basic_json__copyassignment.cpp diff --git a/docs/examples/basic_json__copyassignment.output b/docs/mkdocs/docs/examples/basic_json__copyassignment.output similarity index 100% rename from docs/examples/basic_json__copyassignment.output rename to docs/mkdocs/docs/examples/basic_json__copyassignment.output diff --git a/docs/examples/basic_json__list_init_t.cpp b/docs/mkdocs/docs/examples/basic_json__list_init_t.cpp similarity index 100% rename from docs/examples/basic_json__list_init_t.cpp rename to docs/mkdocs/docs/examples/basic_json__list_init_t.cpp diff --git a/docs/examples/basic_json__list_init_t.output b/docs/mkdocs/docs/examples/basic_json__list_init_t.output similarity index 100% rename from docs/examples/basic_json__list_init_t.output rename to docs/mkdocs/docs/examples/basic_json__list_init_t.output diff --git a/docs/examples/basic_json__moveconstructor.cpp b/docs/mkdocs/docs/examples/basic_json__moveconstructor.cpp similarity index 100% rename from docs/examples/basic_json__moveconstructor.cpp rename to docs/mkdocs/docs/examples/basic_json__moveconstructor.cpp diff --git a/docs/examples/basic_json__moveconstructor.output b/docs/mkdocs/docs/examples/basic_json__moveconstructor.output similarity index 100% rename from docs/examples/basic_json__moveconstructor.output rename to docs/mkdocs/docs/examples/basic_json__moveconstructor.output diff --git a/docs/examples/basic_json__nullptr_t.cpp b/docs/mkdocs/docs/examples/basic_json__nullptr_t.cpp similarity index 100% rename from docs/examples/basic_json__nullptr_t.cpp rename to docs/mkdocs/docs/examples/basic_json__nullptr_t.cpp diff --git a/docs/examples/basic_json__nullptr_t.output b/docs/mkdocs/docs/examples/basic_json__nullptr_t.output similarity index 100% rename from docs/examples/basic_json__nullptr_t.output rename to docs/mkdocs/docs/examples/basic_json__nullptr_t.output diff --git a/docs/examples/basic_json__size_type_basic_json.cpp b/docs/mkdocs/docs/examples/basic_json__size_type_basic_json.cpp similarity index 100% rename from docs/examples/basic_json__size_type_basic_json.cpp rename to docs/mkdocs/docs/examples/basic_json__size_type_basic_json.cpp diff --git a/docs/examples/basic_json__size_type_basic_json.output b/docs/mkdocs/docs/examples/basic_json__size_type_basic_json.output similarity index 100% rename from docs/examples/basic_json__size_type_basic_json.output rename to docs/mkdocs/docs/examples/basic_json__size_type_basic_json.output diff --git a/docs/examples/basic_json__value_t.cpp b/docs/mkdocs/docs/examples/basic_json__value_t.cpp similarity index 100% rename from docs/examples/basic_json__value_t.cpp rename to docs/mkdocs/docs/examples/basic_json__value_t.cpp diff --git a/docs/examples/basic_json__value_t.output b/docs/mkdocs/docs/examples/basic_json__value_t.output similarity index 100% rename from docs/examples/basic_json__value_t.output rename to docs/mkdocs/docs/examples/basic_json__value_t.output diff --git a/docs/examples/begin.cpp b/docs/mkdocs/docs/examples/begin.cpp similarity index 100% rename from docs/examples/begin.cpp rename to docs/mkdocs/docs/examples/begin.cpp diff --git a/docs/examples/begin.output b/docs/mkdocs/docs/examples/begin.output similarity index 100% rename from docs/examples/begin.output rename to docs/mkdocs/docs/examples/begin.output diff --git a/docs/examples/binary.cpp b/docs/mkdocs/docs/examples/binary.cpp similarity index 100% rename from docs/examples/binary.cpp rename to docs/mkdocs/docs/examples/binary.cpp diff --git a/docs/examples/binary.output b/docs/mkdocs/docs/examples/binary.output similarity index 100% rename from docs/examples/binary.output rename to docs/mkdocs/docs/examples/binary.output diff --git a/docs/examples/binary_t.cpp b/docs/mkdocs/docs/examples/binary_t.cpp similarity index 100% rename from docs/examples/binary_t.cpp rename to docs/mkdocs/docs/examples/binary_t.cpp diff --git a/docs/examples/binary_t.output b/docs/mkdocs/docs/examples/binary_t.output similarity index 100% rename from docs/examples/binary_t.output rename to docs/mkdocs/docs/examples/binary_t.output diff --git a/docs/examples/boolean_t.cpp b/docs/mkdocs/docs/examples/boolean_t.cpp similarity index 100% rename from docs/examples/boolean_t.cpp rename to docs/mkdocs/docs/examples/boolean_t.cpp diff --git a/docs/examples/boolean_t.output b/docs/mkdocs/docs/examples/boolean_t.output similarity index 100% rename from docs/examples/boolean_t.output rename to docs/mkdocs/docs/examples/boolean_t.output diff --git a/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp similarity index 100% rename from docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp rename to docs/mkdocs/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp diff --git a/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output similarity index 100% rename from docs/examples/byte_container_with_subtype__byte_container_with_subtype.output rename to docs/mkdocs/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output diff --git a/docs/examples/byte_container_with_subtype__clear_subtype.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__clear_subtype.cpp similarity index 100% rename from docs/examples/byte_container_with_subtype__clear_subtype.cpp rename to docs/mkdocs/docs/examples/byte_container_with_subtype__clear_subtype.cpp diff --git a/docs/examples/byte_container_with_subtype__clear_subtype.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__clear_subtype.output similarity index 100% rename from docs/examples/byte_container_with_subtype__clear_subtype.output rename to docs/mkdocs/docs/examples/byte_container_with_subtype__clear_subtype.output diff --git a/docs/examples/byte_container_with_subtype__has_subtype.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__has_subtype.cpp similarity index 100% rename from docs/examples/byte_container_with_subtype__has_subtype.cpp rename to docs/mkdocs/docs/examples/byte_container_with_subtype__has_subtype.cpp diff --git a/docs/examples/byte_container_with_subtype__has_subtype.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__has_subtype.output similarity index 100% rename from docs/examples/byte_container_with_subtype__has_subtype.output rename to docs/mkdocs/docs/examples/byte_container_with_subtype__has_subtype.output diff --git a/docs/examples/byte_container_with_subtype__set_subtype.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__set_subtype.cpp similarity index 100% rename from docs/examples/byte_container_with_subtype__set_subtype.cpp rename to docs/mkdocs/docs/examples/byte_container_with_subtype__set_subtype.cpp diff --git a/docs/examples/byte_container_with_subtype__set_subtype.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__set_subtype.output similarity index 100% rename from docs/examples/byte_container_with_subtype__set_subtype.output rename to docs/mkdocs/docs/examples/byte_container_with_subtype__set_subtype.output diff --git a/docs/examples/byte_container_with_subtype__subtype.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__subtype.cpp similarity index 100% rename from docs/examples/byte_container_with_subtype__subtype.cpp rename to docs/mkdocs/docs/examples/byte_container_with_subtype__subtype.cpp diff --git a/docs/examples/byte_container_with_subtype__subtype.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__subtype.output similarity index 100% rename from docs/examples/byte_container_with_subtype__subtype.output rename to docs/mkdocs/docs/examples/byte_container_with_subtype__subtype.output diff --git a/docs/examples/cbegin.cpp b/docs/mkdocs/docs/examples/cbegin.cpp similarity index 100% rename from docs/examples/cbegin.cpp rename to docs/mkdocs/docs/examples/cbegin.cpp diff --git a/docs/examples/cbegin.output b/docs/mkdocs/docs/examples/cbegin.output similarity index 100% rename from docs/examples/cbegin.output rename to docs/mkdocs/docs/examples/cbegin.output diff --git a/docs/examples/cbor_tag_handler_t.cpp b/docs/mkdocs/docs/examples/cbor_tag_handler_t.cpp similarity index 100% rename from docs/examples/cbor_tag_handler_t.cpp rename to docs/mkdocs/docs/examples/cbor_tag_handler_t.cpp diff --git a/docs/examples/cbor_tag_handler_t.output b/docs/mkdocs/docs/examples/cbor_tag_handler_t.output similarity index 100% rename from docs/examples/cbor_tag_handler_t.output rename to docs/mkdocs/docs/examples/cbor_tag_handler_t.output diff --git a/docs/examples/cend.cpp b/docs/mkdocs/docs/examples/cend.cpp similarity index 100% rename from docs/examples/cend.cpp rename to docs/mkdocs/docs/examples/cend.cpp diff --git a/docs/examples/cend.output b/docs/mkdocs/docs/examples/cend.output similarity index 100% rename from docs/examples/cend.output rename to docs/mkdocs/docs/examples/cend.output diff --git a/docs/examples/clear.cpp b/docs/mkdocs/docs/examples/clear.cpp similarity index 100% rename from docs/examples/clear.cpp rename to docs/mkdocs/docs/examples/clear.cpp diff --git a/docs/examples/clear.output b/docs/mkdocs/docs/examples/clear.output similarity index 100% rename from docs/examples/clear.output rename to docs/mkdocs/docs/examples/clear.output diff --git a/docs/examples/contains__json_pointer.cpp b/docs/mkdocs/docs/examples/contains__json_pointer.cpp similarity index 100% rename from docs/examples/contains__json_pointer.cpp rename to docs/mkdocs/docs/examples/contains__json_pointer.cpp diff --git a/docs/examples/contains__json_pointer.output b/docs/mkdocs/docs/examples/contains__json_pointer.output similarity index 100% rename from docs/examples/contains__json_pointer.output rename to docs/mkdocs/docs/examples/contains__json_pointer.output diff --git a/docs/examples/contains__keytype.c++17.cpp b/docs/mkdocs/docs/examples/contains__keytype.c++17.cpp similarity index 100% rename from docs/examples/contains__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/contains__keytype.c++17.cpp diff --git a/docs/examples/contains__keytype.c++17.output b/docs/mkdocs/docs/examples/contains__keytype.c++17.output similarity index 100% rename from docs/examples/contains__keytype.c++17.output rename to docs/mkdocs/docs/examples/contains__keytype.c++17.output diff --git a/docs/examples/contains__object_t_key_type.cpp b/docs/mkdocs/docs/examples/contains__object_t_key_type.cpp similarity index 100% rename from docs/examples/contains__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/contains__object_t_key_type.cpp diff --git a/docs/examples/contains__object_t_key_type.output b/docs/mkdocs/docs/examples/contains__object_t_key_type.output similarity index 100% rename from docs/examples/contains__object_t_key_type.output rename to docs/mkdocs/docs/examples/contains__object_t_key_type.output diff --git a/docs/examples/count__keytype.c++17.cpp b/docs/mkdocs/docs/examples/count__keytype.c++17.cpp similarity index 100% rename from docs/examples/count__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/count__keytype.c++17.cpp diff --git a/docs/examples/count__keytype.c++17.output b/docs/mkdocs/docs/examples/count__keytype.c++17.output similarity index 100% rename from docs/examples/count__keytype.c++17.output rename to docs/mkdocs/docs/examples/count__keytype.c++17.output diff --git a/docs/examples/count__object_t_key_type.cpp b/docs/mkdocs/docs/examples/count__object_t_key_type.cpp similarity index 100% rename from docs/examples/count__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/count__object_t_key_type.cpp diff --git a/docs/examples/count__object_t_key_type.output b/docs/mkdocs/docs/examples/count__object_t_key_type.output similarity index 100% rename from docs/examples/count__object_t_key_type.output rename to docs/mkdocs/docs/examples/count__object_t_key_type.output diff --git a/docs/examples/crbegin.cpp b/docs/mkdocs/docs/examples/crbegin.cpp similarity index 100% rename from docs/examples/crbegin.cpp rename to docs/mkdocs/docs/examples/crbegin.cpp diff --git a/docs/examples/crbegin.output b/docs/mkdocs/docs/examples/crbegin.output similarity index 100% rename from docs/examples/crbegin.output rename to docs/mkdocs/docs/examples/crbegin.output diff --git a/docs/examples/crend.cpp b/docs/mkdocs/docs/examples/crend.cpp similarity index 100% rename from docs/examples/crend.cpp rename to docs/mkdocs/docs/examples/crend.cpp diff --git a/docs/examples/crend.output b/docs/mkdocs/docs/examples/crend.output similarity index 100% rename from docs/examples/crend.output rename to docs/mkdocs/docs/examples/crend.output diff --git a/docs/examples/default_object_comparator_t.cpp b/docs/mkdocs/docs/examples/default_object_comparator_t.cpp similarity index 100% rename from docs/examples/default_object_comparator_t.cpp rename to docs/mkdocs/docs/examples/default_object_comparator_t.cpp diff --git a/docs/examples/default_object_comparator_t.output b/docs/mkdocs/docs/examples/default_object_comparator_t.output similarity index 100% rename from docs/examples/default_object_comparator_t.output rename to docs/mkdocs/docs/examples/default_object_comparator_t.output diff --git a/docs/mkdocs/docs/examples/diagnostic_positions.cpp b/docs/mkdocs/docs/examples/diagnostic_positions.cpp new file mode 100644 index 000000000..259344cd0 --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostic_positions.cpp @@ -0,0 +1,51 @@ +#include + +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include + +using json = nlohmann::json; + +int main() +{ + std::string json_string = R"( + { + "address": { + "street": "Fake Street", + "housenumber": 1 + } + } + )"; + json j = json::parse(json_string); + + std::cout << "Root diagnostic positions: \n"; + std::cout << "\tstart_pos: " << j.start_pos() << '\n'; + std::cout << "\tend_pos:" << j.end_pos() << "\n"; + std::cout << "Original string: \n"; + std::cout << "{\n \"address\": {\n \"street\": \"Fake Street\",\n \"housenumber\": 1\n }\n }" << "\n"; + std::cout << "Parsed string: \n"; + std::cout << json_string.substr(j.start_pos(), j.end_pos() - j.start_pos()) << "\n\n"; + + std::cout << "address diagnostic positions: \n"; + std::cout << "\tstart_pos:" << j["address"].start_pos() << '\n'; + std::cout << "\tend_pos:" << j["address"].end_pos() << "\n\n"; + std::cout << "Original string: \n"; + std::cout << "{ \"street\": \"Fake Street\",\n \"housenumber\": 1\n }" << "\n"; + std::cout << "Parsed string: \n"; + std::cout << json_string.substr(j["address"].start_pos(), j["address"].end_pos() - j["address"].start_pos()) << "\n\n"; + + std::cout << "street diagnostic positions: \n"; + std::cout << "\tstart_pos:" << j["address"]["street"].start_pos() << '\n'; + std::cout << "\tend_pos:" << j["address"]["street"].end_pos() << "\n\n"; + std::cout << "Original string: \n"; + std::cout << "\"Fake Street\"" << "\n"; + std::cout << "Parsed string: \n"; + std::cout << json_string.substr(j["address"]["street"].start_pos(), j["address"]["street"].end_pos() - j["address"]["street"].start_pos()) << "\n\n"; + + std::cout << "housenumber diagnostic positions: \n"; + std::cout << "\tstart_pos:" << j["address"]["housenumber"].start_pos() << '\n'; + std::cout << "\tend_pos:" << j["address"]["housenumber"].end_pos() << "\n\n"; + std::cout << "Original string: \n"; + std::cout << "1" << "\n"; + std::cout << "Parsed string: \n"; + std::cout << json_string.substr(j["address"]["housenumber"].start_pos(), j["address"]["housenumber"].end_pos() - j["address"]["housenumber"].start_pos()) << "\n\n"; +} diff --git a/docs/mkdocs/docs/examples/diagnostic_positions.output b/docs/mkdocs/docs/examples/diagnostic_positions.output new file mode 100644 index 000000000..a6becc0e6 --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostic_positions.output @@ -0,0 +1,50 @@ +Root diagnostic positions: + start_pos: 5 + end_pos:109 +Original string: +{ + "address": { + "street": "Fake Street", + "housenumber": 1 + } + } +Parsed string: +{ + "address": { + "street": "Fake Street", + "housenumber": 1 + } + } + +address diagnostic positions: + start_pos:26 + end_pos:103 + +Original string: +{ "street": "Fake Street", + "housenumber": 1 + } +Parsed string: +{ + "street": "Fake Street", + "housenumber": 1 + } + +street diagnostic positions: + start_pos:50 + end_pos:63 + +Original string: +"Fake Street" +Parsed string: +"Fake Street" + +housenumber diagnostic positions: + start_pos:92 + end_pos:93 + +Original string: +1 +Parsed string: +1 + diff --git a/docs/mkdocs/docs/examples/diagnostic_positions_exception.cpp b/docs/mkdocs/docs/examples/diagnostic_positions_exception.cpp new file mode 100644 index 000000000..ea4c41393 --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostic_positions_exception.cpp @@ -0,0 +1,30 @@ +#include + +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include + +using json = nlohmann::json; + +/* Demonstration of type error exception with diagnostic postions support enabled */ +int main() +{ + //Invalid json string - housenumber type must be int instead of string + const std::string json_invalid_string = R"( + { + "address": { + "street": "Fake Street", + "housenumber": "1" + } + } + )"; + json j = json::parse(json_invalid_string); + try + { + int housenumber = j["address"]["housenumber"]; + std::cout << housenumber; + } + catch (const json::exception& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/diagnostic_positions_exception.output b/docs/mkdocs/docs/examples/diagnostic_positions_exception.output new file mode 100644 index 000000000..564deb34d --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostic_positions_exception.output @@ -0,0 +1 @@ +[json.exception.type_error.302] (bytes 92-95) type must be number, but is string diff --git a/docs/examples/diagnostics_extended.cpp b/docs/mkdocs/docs/examples/diagnostics_extended.cpp similarity index 100% rename from docs/examples/diagnostics_extended.cpp rename to docs/mkdocs/docs/examples/diagnostics_extended.cpp diff --git a/docs/examples/diagnostics_extended.output b/docs/mkdocs/docs/examples/diagnostics_extended.output similarity index 100% rename from docs/examples/diagnostics_extended.output rename to docs/mkdocs/docs/examples/diagnostics_extended.output diff --git a/docs/mkdocs/docs/examples/diagnostics_extended_positions.cpp b/docs/mkdocs/docs/examples/diagnostics_extended_positions.cpp new file mode 100644 index 000000000..0e0c02945 --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostics_extended_positions.cpp @@ -0,0 +1,31 @@ +#include + +#define JSON_DIAGNOSTICS 1 +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include + +using json = nlohmann::json; + +/* Demonstration of type error exception with diagnostic postions support enabled */ +int main() +{ + //Invalid json string - housenumber type must be int instead of string + const std::string json_invalid_string = R"( + { + "address": { + "street": "Fake Street", + "housenumber": "1" + } + } + )"; + json j = json::parse(json_invalid_string); + try + { + int housenumber = j["address"]["housenumber"]; + std::cout << housenumber; + } + catch (const json::exception& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/diagnostics_extended_positions.output b/docs/mkdocs/docs/examples/diagnostics_extended_positions.output new file mode 100644 index 000000000..35096d946 --- /dev/null +++ b/docs/mkdocs/docs/examples/diagnostics_extended_positions.output @@ -0,0 +1 @@ +[json.exception.type_error.302] (/address/housenumber) (bytes 92-95) type must be number, but is string diff --git a/docs/examples/diagnostics_standard.cpp b/docs/mkdocs/docs/examples/diagnostics_standard.cpp similarity index 100% rename from docs/examples/diagnostics_standard.cpp rename to docs/mkdocs/docs/examples/diagnostics_standard.cpp diff --git a/docs/examples/diagnostics_standard.output b/docs/mkdocs/docs/examples/diagnostics_standard.output similarity index 100% rename from docs/examples/diagnostics_standard.output rename to docs/mkdocs/docs/examples/diagnostics_standard.output diff --git a/docs/examples/diff.cpp b/docs/mkdocs/docs/examples/diff.cpp similarity index 100% rename from docs/examples/diff.cpp rename to docs/mkdocs/docs/examples/diff.cpp diff --git a/docs/examples/diff.output b/docs/mkdocs/docs/examples/diff.output similarity index 100% rename from docs/examples/diff.output rename to docs/mkdocs/docs/examples/diff.output diff --git a/docs/examples/dump.cpp b/docs/mkdocs/docs/examples/dump.cpp similarity index 100% rename from docs/examples/dump.cpp rename to docs/mkdocs/docs/examples/dump.cpp diff --git a/docs/examples/dump.output b/docs/mkdocs/docs/examples/dump.output similarity index 100% rename from docs/examples/dump.output rename to docs/mkdocs/docs/examples/dump.output diff --git a/docs/examples/emplace.cpp b/docs/mkdocs/docs/examples/emplace.cpp similarity index 100% rename from docs/examples/emplace.cpp rename to docs/mkdocs/docs/examples/emplace.cpp diff --git a/docs/examples/emplace.output b/docs/mkdocs/docs/examples/emplace.output similarity index 100% rename from docs/examples/emplace.output rename to docs/mkdocs/docs/examples/emplace.output diff --git a/docs/examples/emplace_back.cpp b/docs/mkdocs/docs/examples/emplace_back.cpp similarity index 100% rename from docs/examples/emplace_back.cpp rename to docs/mkdocs/docs/examples/emplace_back.cpp diff --git a/docs/examples/emplace_back.output b/docs/mkdocs/docs/examples/emplace_back.output similarity index 100% rename from docs/examples/emplace_back.output rename to docs/mkdocs/docs/examples/emplace_back.output diff --git a/docs/examples/empty.cpp b/docs/mkdocs/docs/examples/empty.cpp similarity index 100% rename from docs/examples/empty.cpp rename to docs/mkdocs/docs/examples/empty.cpp diff --git a/docs/examples/empty.output b/docs/mkdocs/docs/examples/empty.output similarity index 100% rename from docs/examples/empty.output rename to docs/mkdocs/docs/examples/empty.output diff --git a/docs/examples/end.cpp b/docs/mkdocs/docs/examples/end.cpp similarity index 100% rename from docs/examples/end.cpp rename to docs/mkdocs/docs/examples/end.cpp diff --git a/docs/examples/end.output b/docs/mkdocs/docs/examples/end.output similarity index 100% rename from docs/examples/end.output rename to docs/mkdocs/docs/examples/end.output diff --git a/docs/examples/erase__IteratorType.cpp b/docs/mkdocs/docs/examples/erase__IteratorType.cpp similarity index 100% rename from docs/examples/erase__IteratorType.cpp rename to docs/mkdocs/docs/examples/erase__IteratorType.cpp diff --git a/docs/examples/erase__IteratorType.output b/docs/mkdocs/docs/examples/erase__IteratorType.output similarity index 100% rename from docs/examples/erase__IteratorType.output rename to docs/mkdocs/docs/examples/erase__IteratorType.output diff --git a/docs/examples/erase__IteratorType_IteratorType.cpp b/docs/mkdocs/docs/examples/erase__IteratorType_IteratorType.cpp similarity index 100% rename from docs/examples/erase__IteratorType_IteratorType.cpp rename to docs/mkdocs/docs/examples/erase__IteratorType_IteratorType.cpp diff --git a/docs/examples/erase__IteratorType_IteratorType.output b/docs/mkdocs/docs/examples/erase__IteratorType_IteratorType.output similarity index 100% rename from docs/examples/erase__IteratorType_IteratorType.output rename to docs/mkdocs/docs/examples/erase__IteratorType_IteratorType.output diff --git a/docs/examples/erase__keytype.c++17.cpp b/docs/mkdocs/docs/examples/erase__keytype.c++17.cpp similarity index 100% rename from docs/examples/erase__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/erase__keytype.c++17.cpp diff --git a/docs/examples/erase__keytype.c++17.output b/docs/mkdocs/docs/examples/erase__keytype.c++17.output similarity index 100% rename from docs/examples/erase__keytype.c++17.output rename to docs/mkdocs/docs/examples/erase__keytype.c++17.output diff --git a/docs/examples/erase__object_t_key_type.cpp b/docs/mkdocs/docs/examples/erase__object_t_key_type.cpp similarity index 100% rename from docs/examples/erase__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/erase__object_t_key_type.cpp diff --git a/docs/examples/erase__object_t_key_type.output b/docs/mkdocs/docs/examples/erase__object_t_key_type.output similarity index 100% rename from docs/examples/erase__object_t_key_type.output rename to docs/mkdocs/docs/examples/erase__object_t_key_type.output diff --git a/docs/examples/erase__size_type.cpp b/docs/mkdocs/docs/examples/erase__size_type.cpp similarity index 100% rename from docs/examples/erase__size_type.cpp rename to docs/mkdocs/docs/examples/erase__size_type.cpp diff --git a/docs/examples/erase__size_type.output b/docs/mkdocs/docs/examples/erase__size_type.output similarity index 100% rename from docs/examples/erase__size_type.output rename to docs/mkdocs/docs/examples/erase__size_type.output diff --git a/docs/examples/error_handler_t.cpp b/docs/mkdocs/docs/examples/error_handler_t.cpp similarity index 100% rename from docs/examples/error_handler_t.cpp rename to docs/mkdocs/docs/examples/error_handler_t.cpp diff --git a/docs/examples/error_handler_t.output b/docs/mkdocs/docs/examples/error_handler_t.output similarity index 100% rename from docs/examples/error_handler_t.output rename to docs/mkdocs/docs/examples/error_handler_t.output diff --git a/docs/examples/exception.cpp b/docs/mkdocs/docs/examples/exception.cpp similarity index 100% rename from docs/examples/exception.cpp rename to docs/mkdocs/docs/examples/exception.cpp diff --git a/docs/examples/exception.output b/docs/mkdocs/docs/examples/exception.output similarity index 100% rename from docs/examples/exception.output rename to docs/mkdocs/docs/examples/exception.output diff --git a/docs/examples/find__keytype.c++17.cpp b/docs/mkdocs/docs/examples/find__keytype.c++17.cpp similarity index 100% rename from docs/examples/find__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/find__keytype.c++17.cpp diff --git a/docs/examples/find__keytype.c++17.output b/docs/mkdocs/docs/examples/find__keytype.c++17.output similarity index 100% rename from docs/examples/find__keytype.c++17.output rename to docs/mkdocs/docs/examples/find__keytype.c++17.output diff --git a/docs/examples/find__object_t_key_type.cpp b/docs/mkdocs/docs/examples/find__object_t_key_type.cpp similarity index 100% rename from docs/examples/find__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/find__object_t_key_type.cpp diff --git a/docs/examples/find__object_t_key_type.output b/docs/mkdocs/docs/examples/find__object_t_key_type.output similarity index 100% rename from docs/examples/find__object_t_key_type.output rename to docs/mkdocs/docs/examples/find__object_t_key_type.output diff --git a/docs/examples/flatten.cpp b/docs/mkdocs/docs/examples/flatten.cpp similarity index 100% rename from docs/examples/flatten.cpp rename to docs/mkdocs/docs/examples/flatten.cpp diff --git a/docs/examples/flatten.output b/docs/mkdocs/docs/examples/flatten.output similarity index 100% rename from docs/examples/flatten.output rename to docs/mkdocs/docs/examples/flatten.output diff --git a/docs/examples/from_bjdata.cpp b/docs/mkdocs/docs/examples/from_bjdata.cpp similarity index 100% rename from docs/examples/from_bjdata.cpp rename to docs/mkdocs/docs/examples/from_bjdata.cpp diff --git a/docs/examples/from_bjdata.output b/docs/mkdocs/docs/examples/from_bjdata.output similarity index 100% rename from docs/examples/from_bjdata.output rename to docs/mkdocs/docs/examples/from_bjdata.output diff --git a/docs/examples/from_bson.cpp b/docs/mkdocs/docs/examples/from_bson.cpp similarity index 100% rename from docs/examples/from_bson.cpp rename to docs/mkdocs/docs/examples/from_bson.cpp diff --git a/docs/examples/from_bson.output b/docs/mkdocs/docs/examples/from_bson.output similarity index 100% rename from docs/examples/from_bson.output rename to docs/mkdocs/docs/examples/from_bson.output diff --git a/docs/examples/from_cbor.cpp b/docs/mkdocs/docs/examples/from_cbor.cpp similarity index 100% rename from docs/examples/from_cbor.cpp rename to docs/mkdocs/docs/examples/from_cbor.cpp diff --git a/docs/examples/from_cbor.output b/docs/mkdocs/docs/examples/from_cbor.output similarity index 100% rename from docs/examples/from_cbor.output rename to docs/mkdocs/docs/examples/from_cbor.output diff --git a/docs/examples/from_json__default_constructible.cpp b/docs/mkdocs/docs/examples/from_json__default_constructible.cpp similarity index 100% rename from docs/examples/from_json__default_constructible.cpp rename to docs/mkdocs/docs/examples/from_json__default_constructible.cpp diff --git a/docs/examples/from_json__default_constructible.output b/docs/mkdocs/docs/examples/from_json__default_constructible.output similarity index 100% rename from docs/examples/from_json__default_constructible.output rename to docs/mkdocs/docs/examples/from_json__default_constructible.output diff --git a/docs/examples/from_json__non_default_constructible.cpp b/docs/mkdocs/docs/examples/from_json__non_default_constructible.cpp similarity index 100% rename from docs/examples/from_json__non_default_constructible.cpp rename to docs/mkdocs/docs/examples/from_json__non_default_constructible.cpp diff --git a/docs/examples/from_json__non_default_constructible.output b/docs/mkdocs/docs/examples/from_json__non_default_constructible.output similarity index 100% rename from docs/examples/from_json__non_default_constructible.output rename to docs/mkdocs/docs/examples/from_json__non_default_constructible.output diff --git a/docs/examples/from_msgpack.cpp b/docs/mkdocs/docs/examples/from_msgpack.cpp similarity index 100% rename from docs/examples/from_msgpack.cpp rename to docs/mkdocs/docs/examples/from_msgpack.cpp diff --git a/docs/examples/from_msgpack.output b/docs/mkdocs/docs/examples/from_msgpack.output similarity index 100% rename from docs/examples/from_msgpack.output rename to docs/mkdocs/docs/examples/from_msgpack.output diff --git a/docs/examples/from_ubjson.cpp b/docs/mkdocs/docs/examples/from_ubjson.cpp similarity index 100% rename from docs/examples/from_ubjson.cpp rename to docs/mkdocs/docs/examples/from_ubjson.cpp diff --git a/docs/examples/from_ubjson.output b/docs/mkdocs/docs/examples/from_ubjson.output similarity index 100% rename from docs/examples/from_ubjson.output rename to docs/mkdocs/docs/examples/from_ubjson.output diff --git a/docs/examples/front.cpp b/docs/mkdocs/docs/examples/front.cpp similarity index 100% rename from docs/examples/front.cpp rename to docs/mkdocs/docs/examples/front.cpp diff --git a/docs/examples/front.output b/docs/mkdocs/docs/examples/front.output similarity index 100% rename from docs/examples/front.output rename to docs/mkdocs/docs/examples/front.output diff --git a/docs/examples/get__PointerType.cpp b/docs/mkdocs/docs/examples/get__PointerType.cpp similarity index 100% rename from docs/examples/get__PointerType.cpp rename to docs/mkdocs/docs/examples/get__PointerType.cpp diff --git a/docs/examples/get__PointerType.output b/docs/mkdocs/docs/examples/get__PointerType.output similarity index 100% rename from docs/examples/get__PointerType.output rename to docs/mkdocs/docs/examples/get__PointerType.output diff --git a/docs/examples/get__ValueType_const.cpp b/docs/mkdocs/docs/examples/get__ValueType_const.cpp similarity index 100% rename from docs/examples/get__ValueType_const.cpp rename to docs/mkdocs/docs/examples/get__ValueType_const.cpp diff --git a/docs/examples/get__ValueType_const.output b/docs/mkdocs/docs/examples/get__ValueType_const.output similarity index 100% rename from docs/examples/get__ValueType_const.output rename to docs/mkdocs/docs/examples/get__ValueType_const.output diff --git a/docs/examples/get_allocator.cpp b/docs/mkdocs/docs/examples/get_allocator.cpp similarity index 100% rename from docs/examples/get_allocator.cpp rename to docs/mkdocs/docs/examples/get_allocator.cpp diff --git a/docs/examples/get_allocator.output b/docs/mkdocs/docs/examples/get_allocator.output similarity index 100% rename from docs/examples/get_allocator.output rename to docs/mkdocs/docs/examples/get_allocator.output diff --git a/docs/examples/get_binary.cpp b/docs/mkdocs/docs/examples/get_binary.cpp similarity index 100% rename from docs/examples/get_binary.cpp rename to docs/mkdocs/docs/examples/get_binary.cpp diff --git a/docs/examples/get_binary.output b/docs/mkdocs/docs/examples/get_binary.output similarity index 100% rename from docs/examples/get_binary.output rename to docs/mkdocs/docs/examples/get_binary.output diff --git a/docs/examples/get_ptr.cpp b/docs/mkdocs/docs/examples/get_ptr.cpp similarity index 100% rename from docs/examples/get_ptr.cpp rename to docs/mkdocs/docs/examples/get_ptr.cpp diff --git a/docs/examples/get_ptr.output b/docs/mkdocs/docs/examples/get_ptr.output similarity index 100% rename from docs/examples/get_ptr.output rename to docs/mkdocs/docs/examples/get_ptr.output diff --git a/docs/examples/get_ref.cpp b/docs/mkdocs/docs/examples/get_ref.cpp similarity index 100% rename from docs/examples/get_ref.cpp rename to docs/mkdocs/docs/examples/get_ref.cpp diff --git a/docs/examples/get_ref.output b/docs/mkdocs/docs/examples/get_ref.output similarity index 100% rename from docs/examples/get_ref.output rename to docs/mkdocs/docs/examples/get_ref.output diff --git a/docs/examples/get_to.cpp b/docs/mkdocs/docs/examples/get_to.cpp similarity index 100% rename from docs/examples/get_to.cpp rename to docs/mkdocs/docs/examples/get_to.cpp diff --git a/docs/examples/get_to.output b/docs/mkdocs/docs/examples/get_to.output similarity index 100% rename from docs/examples/get_to.output rename to docs/mkdocs/docs/examples/get_to.output diff --git a/docs/examples/insert.cpp b/docs/mkdocs/docs/examples/insert.cpp similarity index 100% rename from docs/examples/insert.cpp rename to docs/mkdocs/docs/examples/insert.cpp diff --git a/docs/examples/insert.output b/docs/mkdocs/docs/examples/insert.output similarity index 100% rename from docs/examples/insert.output rename to docs/mkdocs/docs/examples/insert.output diff --git a/docs/examples/insert__count.cpp b/docs/mkdocs/docs/examples/insert__count.cpp similarity index 100% rename from docs/examples/insert__count.cpp rename to docs/mkdocs/docs/examples/insert__count.cpp diff --git a/docs/examples/insert__count.output b/docs/mkdocs/docs/examples/insert__count.output similarity index 100% rename from docs/examples/insert__count.output rename to docs/mkdocs/docs/examples/insert__count.output diff --git a/docs/examples/insert__ilist.cpp b/docs/mkdocs/docs/examples/insert__ilist.cpp similarity index 100% rename from docs/examples/insert__ilist.cpp rename to docs/mkdocs/docs/examples/insert__ilist.cpp diff --git a/docs/examples/insert__ilist.output b/docs/mkdocs/docs/examples/insert__ilist.output similarity index 100% rename from docs/examples/insert__ilist.output rename to docs/mkdocs/docs/examples/insert__ilist.output diff --git a/docs/examples/insert__range.cpp b/docs/mkdocs/docs/examples/insert__range.cpp similarity index 100% rename from docs/examples/insert__range.cpp rename to docs/mkdocs/docs/examples/insert__range.cpp diff --git a/docs/examples/insert__range.output b/docs/mkdocs/docs/examples/insert__range.output similarity index 100% rename from docs/examples/insert__range.output rename to docs/mkdocs/docs/examples/insert__range.output diff --git a/docs/examples/insert__range_object.cpp b/docs/mkdocs/docs/examples/insert__range_object.cpp similarity index 100% rename from docs/examples/insert__range_object.cpp rename to docs/mkdocs/docs/examples/insert__range_object.cpp diff --git a/docs/examples/insert__range_object.output b/docs/mkdocs/docs/examples/insert__range_object.output similarity index 100% rename from docs/examples/insert__range_object.output rename to docs/mkdocs/docs/examples/insert__range_object.output diff --git a/docs/examples/invalid_iterator.cpp b/docs/mkdocs/docs/examples/invalid_iterator.cpp similarity index 100% rename from docs/examples/invalid_iterator.cpp rename to docs/mkdocs/docs/examples/invalid_iterator.cpp diff --git a/docs/examples/invalid_iterator.output b/docs/mkdocs/docs/examples/invalid_iterator.output similarity index 100% rename from docs/examples/invalid_iterator.output rename to docs/mkdocs/docs/examples/invalid_iterator.output diff --git a/docs/examples/is_array.cpp b/docs/mkdocs/docs/examples/is_array.cpp similarity index 100% rename from docs/examples/is_array.cpp rename to docs/mkdocs/docs/examples/is_array.cpp diff --git a/docs/examples/is_array.output b/docs/mkdocs/docs/examples/is_array.output similarity index 100% rename from docs/examples/is_array.output rename to docs/mkdocs/docs/examples/is_array.output diff --git a/docs/examples/is_binary.cpp b/docs/mkdocs/docs/examples/is_binary.cpp similarity index 100% rename from docs/examples/is_binary.cpp rename to docs/mkdocs/docs/examples/is_binary.cpp diff --git a/docs/examples/is_binary.output b/docs/mkdocs/docs/examples/is_binary.output similarity index 100% rename from docs/examples/is_binary.output rename to docs/mkdocs/docs/examples/is_binary.output diff --git a/docs/examples/is_boolean.cpp b/docs/mkdocs/docs/examples/is_boolean.cpp similarity index 100% rename from docs/examples/is_boolean.cpp rename to docs/mkdocs/docs/examples/is_boolean.cpp diff --git a/docs/examples/is_boolean.output b/docs/mkdocs/docs/examples/is_boolean.output similarity index 100% rename from docs/examples/is_boolean.output rename to docs/mkdocs/docs/examples/is_boolean.output diff --git a/docs/examples/is_discarded.cpp b/docs/mkdocs/docs/examples/is_discarded.cpp similarity index 100% rename from docs/examples/is_discarded.cpp rename to docs/mkdocs/docs/examples/is_discarded.cpp diff --git a/docs/examples/is_discarded.output b/docs/mkdocs/docs/examples/is_discarded.output similarity index 100% rename from docs/examples/is_discarded.output rename to docs/mkdocs/docs/examples/is_discarded.output diff --git a/docs/examples/is_null.cpp b/docs/mkdocs/docs/examples/is_null.cpp similarity index 100% rename from docs/examples/is_null.cpp rename to docs/mkdocs/docs/examples/is_null.cpp diff --git a/docs/examples/is_null.output b/docs/mkdocs/docs/examples/is_null.output similarity index 100% rename from docs/examples/is_null.output rename to docs/mkdocs/docs/examples/is_null.output diff --git a/docs/examples/is_number.cpp b/docs/mkdocs/docs/examples/is_number.cpp similarity index 100% rename from docs/examples/is_number.cpp rename to docs/mkdocs/docs/examples/is_number.cpp diff --git a/docs/examples/is_number.output b/docs/mkdocs/docs/examples/is_number.output similarity index 100% rename from docs/examples/is_number.output rename to docs/mkdocs/docs/examples/is_number.output diff --git a/docs/examples/is_number_float.cpp b/docs/mkdocs/docs/examples/is_number_float.cpp similarity index 100% rename from docs/examples/is_number_float.cpp rename to docs/mkdocs/docs/examples/is_number_float.cpp diff --git a/docs/examples/is_number_float.output b/docs/mkdocs/docs/examples/is_number_float.output similarity index 100% rename from docs/examples/is_number_float.output rename to docs/mkdocs/docs/examples/is_number_float.output diff --git a/docs/examples/is_number_integer.cpp b/docs/mkdocs/docs/examples/is_number_integer.cpp similarity index 100% rename from docs/examples/is_number_integer.cpp rename to docs/mkdocs/docs/examples/is_number_integer.cpp diff --git a/docs/examples/is_number_integer.output b/docs/mkdocs/docs/examples/is_number_integer.output similarity index 100% rename from docs/examples/is_number_integer.output rename to docs/mkdocs/docs/examples/is_number_integer.output diff --git a/docs/examples/is_number_unsigned.cpp b/docs/mkdocs/docs/examples/is_number_unsigned.cpp similarity index 100% rename from docs/examples/is_number_unsigned.cpp rename to docs/mkdocs/docs/examples/is_number_unsigned.cpp diff --git a/docs/examples/is_number_unsigned.output b/docs/mkdocs/docs/examples/is_number_unsigned.output similarity index 100% rename from docs/examples/is_number_unsigned.output rename to docs/mkdocs/docs/examples/is_number_unsigned.output diff --git a/docs/examples/is_object.cpp b/docs/mkdocs/docs/examples/is_object.cpp similarity index 100% rename from docs/examples/is_object.cpp rename to docs/mkdocs/docs/examples/is_object.cpp diff --git a/docs/examples/is_object.output b/docs/mkdocs/docs/examples/is_object.output similarity index 100% rename from docs/examples/is_object.output rename to docs/mkdocs/docs/examples/is_object.output diff --git a/docs/examples/is_primitive.cpp b/docs/mkdocs/docs/examples/is_primitive.cpp similarity index 100% rename from docs/examples/is_primitive.cpp rename to docs/mkdocs/docs/examples/is_primitive.cpp diff --git a/docs/examples/is_primitive.output b/docs/mkdocs/docs/examples/is_primitive.output similarity index 100% rename from docs/examples/is_primitive.output rename to docs/mkdocs/docs/examples/is_primitive.output diff --git a/docs/examples/is_string.cpp b/docs/mkdocs/docs/examples/is_string.cpp similarity index 100% rename from docs/examples/is_string.cpp rename to docs/mkdocs/docs/examples/is_string.cpp diff --git a/docs/examples/is_string.output b/docs/mkdocs/docs/examples/is_string.output similarity index 100% rename from docs/examples/is_string.output rename to docs/mkdocs/docs/examples/is_string.output diff --git a/docs/examples/is_structured.cpp b/docs/mkdocs/docs/examples/is_structured.cpp similarity index 100% rename from docs/examples/is_structured.cpp rename to docs/mkdocs/docs/examples/is_structured.cpp diff --git a/docs/examples/is_structured.output b/docs/mkdocs/docs/examples/is_structured.output similarity index 100% rename from docs/examples/is_structured.output rename to docs/mkdocs/docs/examples/is_structured.output diff --git a/docs/examples/items.cpp b/docs/mkdocs/docs/examples/items.cpp similarity index 100% rename from docs/examples/items.cpp rename to docs/mkdocs/docs/examples/items.cpp diff --git a/docs/examples/items.output b/docs/mkdocs/docs/examples/items.output similarity index 100% rename from docs/examples/items.output rename to docs/mkdocs/docs/examples/items.output diff --git a/docs/examples/json_base_class_t.cpp b/docs/mkdocs/docs/examples/json_base_class_t.cpp similarity index 96% rename from docs/examples/json_base_class_t.cpp rename to docs/mkdocs/docs/examples/json_base_class_t.cpp index d993522a7..3fb2d46a2 100644 --- a/docs/examples/json_base_class_t.cpp +++ b/docs/mkdocs/docs/examples/json_base_class_t.cpp @@ -79,8 +79,8 @@ int main() // visit and output j.visit( - [&](const json::json_pointer & p, - const json & j) + [&](const json::json_pointer & p, + const json & j) { std::cout << (p.empty() ? std::string{"/"} : p.to_string()) << " - metadata = " << j.metadata << " -> " << j.dump() << '\n'; diff --git a/docs/examples/json_base_class_t.output b/docs/mkdocs/docs/examples/json_base_class_t.output similarity index 100% rename from docs/examples/json_base_class_t.output rename to docs/mkdocs/docs/examples/json_base_class_t.output diff --git a/docs/examples/json_lines.cpp b/docs/mkdocs/docs/examples/json_lines.cpp similarity index 100% rename from docs/examples/json_lines.cpp rename to docs/mkdocs/docs/examples/json_lines.cpp diff --git a/docs/examples/json_lines.output b/docs/mkdocs/docs/examples/json_lines.output similarity index 100% rename from docs/examples/json_lines.output rename to docs/mkdocs/docs/examples/json_lines.output diff --git a/docs/examples/json_pointer.cpp b/docs/mkdocs/docs/examples/json_pointer.cpp similarity index 100% rename from docs/examples/json_pointer.cpp rename to docs/mkdocs/docs/examples/json_pointer.cpp diff --git a/docs/examples/json_pointer.output b/docs/mkdocs/docs/examples/json_pointer.output similarity index 100% rename from docs/examples/json_pointer.output rename to docs/mkdocs/docs/examples/json_pointer.output diff --git a/docs/examples/json_pointer__back.cpp b/docs/mkdocs/docs/examples/json_pointer__back.cpp similarity index 100% rename from docs/examples/json_pointer__back.cpp rename to docs/mkdocs/docs/examples/json_pointer__back.cpp diff --git a/docs/examples/json_pointer__back.output b/docs/mkdocs/docs/examples/json_pointer__back.output similarity index 100% rename from docs/examples/json_pointer__back.output rename to docs/mkdocs/docs/examples/json_pointer__back.output diff --git a/docs/examples/json_pointer__empty.cpp b/docs/mkdocs/docs/examples/json_pointer__empty.cpp similarity index 100% rename from docs/examples/json_pointer__empty.cpp rename to docs/mkdocs/docs/examples/json_pointer__empty.cpp diff --git a/docs/examples/json_pointer__empty.output b/docs/mkdocs/docs/examples/json_pointer__empty.output similarity index 100% rename from docs/examples/json_pointer__empty.output rename to docs/mkdocs/docs/examples/json_pointer__empty.output diff --git a/docs/examples/json_pointer__operator__equal.cpp b/docs/mkdocs/docs/examples/json_pointer__operator__equal.cpp similarity index 100% rename from docs/examples/json_pointer__operator__equal.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator__equal.cpp diff --git a/docs/examples/json_pointer__operator__equal.output b/docs/mkdocs/docs/examples/json_pointer__operator__equal.output similarity index 100% rename from docs/examples/json_pointer__operator__equal.output rename to docs/mkdocs/docs/examples/json_pointer__operator__equal.output diff --git a/docs/examples/json_pointer__operator__equal_stringtype.cpp b/docs/mkdocs/docs/examples/json_pointer__operator__equal_stringtype.cpp similarity index 100% rename from docs/examples/json_pointer__operator__equal_stringtype.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator__equal_stringtype.cpp diff --git a/docs/examples/json_pointer__operator__equal_stringtype.output b/docs/mkdocs/docs/examples/json_pointer__operator__equal_stringtype.output similarity index 100% rename from docs/examples/json_pointer__operator__equal_stringtype.output rename to docs/mkdocs/docs/examples/json_pointer__operator__equal_stringtype.output diff --git a/docs/examples/json_pointer__operator__notequal.cpp b/docs/mkdocs/docs/examples/json_pointer__operator__notequal.cpp similarity index 100% rename from docs/examples/json_pointer__operator__notequal.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator__notequal.cpp diff --git a/docs/examples/json_pointer__operator__notequal.output b/docs/mkdocs/docs/examples/json_pointer__operator__notequal.output similarity index 100% rename from docs/examples/json_pointer__operator__notequal.output rename to docs/mkdocs/docs/examples/json_pointer__operator__notequal.output diff --git a/docs/examples/json_pointer__operator__notequal_stringtype.cpp b/docs/mkdocs/docs/examples/json_pointer__operator__notequal_stringtype.cpp similarity index 100% rename from docs/examples/json_pointer__operator__notequal_stringtype.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator__notequal_stringtype.cpp diff --git a/docs/examples/json_pointer__operator__notequal_stringtype.output b/docs/mkdocs/docs/examples/json_pointer__operator__notequal_stringtype.output similarity index 100% rename from docs/examples/json_pointer__operator__notequal_stringtype.output rename to docs/mkdocs/docs/examples/json_pointer__operator__notequal_stringtype.output diff --git a/docs/examples/json_pointer__operator_add.cpp b/docs/mkdocs/docs/examples/json_pointer__operator_add.cpp similarity index 100% rename from docs/examples/json_pointer__operator_add.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator_add.cpp diff --git a/docs/examples/json_pointer__operator_add.output b/docs/mkdocs/docs/examples/json_pointer__operator_add.output similarity index 100% rename from docs/examples/json_pointer__operator_add.output rename to docs/mkdocs/docs/examples/json_pointer__operator_add.output diff --git a/docs/examples/json_pointer__operator_add_binary.cpp b/docs/mkdocs/docs/examples/json_pointer__operator_add_binary.cpp similarity index 100% rename from docs/examples/json_pointer__operator_add_binary.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator_add_binary.cpp diff --git a/docs/examples/json_pointer__operator_add_binary.output b/docs/mkdocs/docs/examples/json_pointer__operator_add_binary.output similarity index 100% rename from docs/examples/json_pointer__operator_add_binary.output rename to docs/mkdocs/docs/examples/json_pointer__operator_add_binary.output diff --git a/docs/examples/json_pointer__operator_string_t.cpp b/docs/mkdocs/docs/examples/json_pointer__operator_string_t.cpp similarity index 100% rename from docs/examples/json_pointer__operator_string_t.cpp rename to docs/mkdocs/docs/examples/json_pointer__operator_string_t.cpp diff --git a/docs/examples/json_pointer__operator_string_t.output b/docs/mkdocs/docs/examples/json_pointer__operator_string_t.output similarity index 100% rename from docs/examples/json_pointer__operator_string_t.output rename to docs/mkdocs/docs/examples/json_pointer__operator_string_t.output diff --git a/docs/examples/json_pointer__parent_pointer.cpp b/docs/mkdocs/docs/examples/json_pointer__parent_pointer.cpp similarity index 100% rename from docs/examples/json_pointer__parent_pointer.cpp rename to docs/mkdocs/docs/examples/json_pointer__parent_pointer.cpp diff --git a/docs/examples/json_pointer__parent_pointer.output b/docs/mkdocs/docs/examples/json_pointer__parent_pointer.output similarity index 100% rename from docs/examples/json_pointer__parent_pointer.output rename to docs/mkdocs/docs/examples/json_pointer__parent_pointer.output diff --git a/docs/examples/json_pointer__pop_back.cpp b/docs/mkdocs/docs/examples/json_pointer__pop_back.cpp similarity index 100% rename from docs/examples/json_pointer__pop_back.cpp rename to docs/mkdocs/docs/examples/json_pointer__pop_back.cpp diff --git a/docs/examples/json_pointer__pop_back.output b/docs/mkdocs/docs/examples/json_pointer__pop_back.output similarity index 100% rename from docs/examples/json_pointer__pop_back.output rename to docs/mkdocs/docs/examples/json_pointer__pop_back.output diff --git a/docs/examples/json_pointer__push_back.cpp b/docs/mkdocs/docs/examples/json_pointer__push_back.cpp similarity index 100% rename from docs/examples/json_pointer__push_back.cpp rename to docs/mkdocs/docs/examples/json_pointer__push_back.cpp diff --git a/docs/examples/json_pointer__push_back.output b/docs/mkdocs/docs/examples/json_pointer__push_back.output similarity index 100% rename from docs/examples/json_pointer__push_back.output rename to docs/mkdocs/docs/examples/json_pointer__push_back.output diff --git a/docs/examples/json_pointer__string_t.cpp b/docs/mkdocs/docs/examples/json_pointer__string_t.cpp similarity index 100% rename from docs/examples/json_pointer__string_t.cpp rename to docs/mkdocs/docs/examples/json_pointer__string_t.cpp diff --git a/docs/examples/json_pointer__string_t.output b/docs/mkdocs/docs/examples/json_pointer__string_t.output similarity index 100% rename from docs/examples/json_pointer__string_t.output rename to docs/mkdocs/docs/examples/json_pointer__string_t.output diff --git a/docs/examples/json_pointer__to_string.cpp b/docs/mkdocs/docs/examples/json_pointer__to_string.cpp similarity index 100% rename from docs/examples/json_pointer__to_string.cpp rename to docs/mkdocs/docs/examples/json_pointer__to_string.cpp diff --git a/docs/examples/json_pointer__to_string.output b/docs/mkdocs/docs/examples/json_pointer__to_string.output similarity index 100% rename from docs/examples/json_pointer__to_string.output rename to docs/mkdocs/docs/examples/json_pointer__to_string.output diff --git a/docs/examples/max_size.cpp b/docs/mkdocs/docs/examples/max_size.cpp similarity index 100% rename from docs/examples/max_size.cpp rename to docs/mkdocs/docs/examples/max_size.cpp diff --git a/docs/examples/max_size.output b/docs/mkdocs/docs/examples/max_size.output similarity index 100% rename from docs/examples/max_size.output rename to docs/mkdocs/docs/examples/max_size.output diff --git a/docs/examples/merge_patch.cpp b/docs/mkdocs/docs/examples/merge_patch.cpp similarity index 100% rename from docs/examples/merge_patch.cpp rename to docs/mkdocs/docs/examples/merge_patch.cpp diff --git a/docs/examples/merge_patch.output b/docs/mkdocs/docs/examples/merge_patch.output similarity index 100% rename from docs/examples/merge_patch.output rename to docs/mkdocs/docs/examples/merge_patch.output diff --git a/docs/examples/meta.cpp b/docs/mkdocs/docs/examples/meta.cpp similarity index 100% rename from docs/examples/meta.cpp rename to docs/mkdocs/docs/examples/meta.cpp diff --git a/docs/examples/meta.output b/docs/mkdocs/docs/examples/meta.output similarity index 61% rename from docs/examples/meta.output rename to docs/mkdocs/docs/examples/meta.output index 90390f96b..3cdaa24ea 100644 --- a/docs/examples/meta.output +++ b/docs/mkdocs/docs/examples/meta.output @@ -2,16 +2,16 @@ "compiler": { "c++": "201103", "family": "gcc", - "version": "12.3.0" + "version": "12.4.0" }, - "copyright": "(C) 2013-2022 Niels Lohmann", + "copyright": "(C) 2013-2025 Niels Lohmann", "name": "JSON for Modern C++", "platform": "apple", "url": "https://github.com/nlohmann/json", "version": { "major": 3, - "minor": 11, - "patch": 3, - "string": "3.11.3" + "minor": 12, + "patch": 0, + "string": "3.12.0" } } diff --git a/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.cpp new file mode 100644 index 000000000..0dca78162 --- /dev/null +++ b/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +using nlohmann::json; + +class A +{ + private: + double Aa = 0.0; + double Ab = 0.0; + + public: + A() = default; + A(double a, double b) : Aa(a), Ab(b) {} + NLOHMANN_DEFINE_TYPE_INTRUSIVE(A, Aa, Ab) +}; + +class B : public A +{ + private: + int Ba = 0; + int Bb = 0; + + public: + B() = default; + B(int a, int b, double aa, double ab) : A(aa, ab), Ba(a), Bb(b) {} + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(B, A, Ba, Bb) +}; + +int main() +{ + B example(23, 42, 3.142, 1.777); + json example_json = example; + + std::cout << std::setw(4) << example_json << std::endl; +} \ No newline at end of file diff --git a/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.output new file mode 100644 index 000000000..0f97be4a0 --- /dev/null +++ b/docs/mkdocs/docs/examples/nlohmann_define_derived_type_intrusive_macro.output @@ -0,0 +1,6 @@ +{ + "Aa": 3.142, + "Ab": 1.777, + "Ba": 23, + "Bb": 42 +} diff --git a/docs/examples/nlohmann_define_type_intrusive_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_explicit.cpp similarity index 85% rename from docs/examples/nlohmann_define_type_intrusive_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_explicit.cpp index de79bd37c..e2021e235 100644 --- a/docs/examples/nlohmann_define_type_intrusive_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_explicit.cpp @@ -19,14 +19,16 @@ class person : name(std::move(name_)), address(std::move(address_)), age(age_) {} - friend void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) + template + friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; nlohmann_json_j["age"] = nlohmann_json_t.age; } - friend void from_json(const nlohmann::json& nlohmann_json_j, person& nlohmann_json_t) + template + friend void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t) { nlohmann_json_t.name = nlohmann_json_j.at("name"); nlohmann_json_t.address = nlohmann_json_j.at("address"); diff --git a/docs/examples/nlohmann_define_type_intrusive_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_explicit.output diff --git a/docs/examples/nlohmann_define_type_intrusive_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_macro.cpp diff --git a/docs/examples/nlohmann_define_type_intrusive_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_macro.output diff --git a/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp similarity index 87% rename from docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp index ea422beb5..dd6a9a679 100644 --- a/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp @@ -19,7 +19,8 @@ class person : name(std::move(name_)), address(std::move(address_)), age(age_) {} - friend void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) + template + friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; diff --git a/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_explicit.output diff --git a/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.cpp diff --git a/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_only_serialize_macro.output diff --git a/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp similarity index 86% rename from docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp index 0fb2e1cb2..397795576 100644 --- a/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp @@ -19,14 +19,16 @@ class person : name(std::move(name_)), address(std::move(address_)), age(age_) {} - friend void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) + template + friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; nlohmann_json_j["age"] = nlohmann_json_t.age; } - friend void from_json(const nlohmann::json& nlohmann_json_j, person& nlohmann_json_t) + template + friend void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t) { person nlohmann_json_default_obj; nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name); diff --git a/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_with_default_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_explicit.output diff --git a/docs/examples/nlohmann_define_type_intrusive_with_default_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_with_default_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_macro.cpp diff --git a/docs/examples/nlohmann_define_type_intrusive_with_default_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_intrusive_with_default_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_intrusive_with_default_macro.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp similarity index 85% rename from docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp index a31a7eb8f..9f5cdc173 100644 --- a/docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_explicit.cpp @@ -13,14 +13,16 @@ struct person int age; }; -void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) +template +void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; nlohmann_json_j["age"] = nlohmann_json_t.age; } -void from_json(const nlohmann::json& nlohmann_json_j, person& nlohmann_json_t) +template +void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t) { nlohmann_json_t.name = nlohmann_json_j.at("name"); nlohmann_json_t.address = nlohmann_json_j.at("address"); diff --git a/docs/examples/nlohmann_define_type_non_intrusive_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_explicit.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_macro.cpp diff --git a/docs/examples/nlohmann_define_type_non_intrusive_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_macro.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp similarity index 84% rename from docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp index 8890e03af..ead75b74e 100644 --- a/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp @@ -13,7 +13,8 @@ struct person int age; }; -void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) +template +void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; diff --git a/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.cpp diff --git a/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_only_serialize_macro.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp similarity index 87% rename from docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp index 855ab52b8..1bdd25ed9 100644 --- a/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp +++ b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp @@ -18,14 +18,16 @@ struct person {} }; -void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t) +template +void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t) { nlohmann_json_j["name"] = nlohmann_json_t.name; nlohmann_json_j["address"] = nlohmann_json_t.address; nlohmann_json_j["age"] = nlohmann_json_t.age; } -void from_json(const nlohmann::json& nlohmann_json_j, person& nlohmann_json_t) +template +void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t) { person nlohmann_json_default_obj; nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name); diff --git a/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output diff --git a/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp diff --git a/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.output b/docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.output similarity index 100% rename from docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.output rename to docs/mkdocs/docs/examples/nlohmann_define_type_non_intrusive_with_default_macro.output diff --git a/docs/examples/nlohmann_json_namespace.cpp b/docs/mkdocs/docs/examples/nlohmann_json_namespace.cpp similarity index 100% rename from docs/examples/nlohmann_json_namespace.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_namespace.cpp diff --git a/docs/mkdocs/docs/examples/nlohmann_json_namespace.output b/docs/mkdocs/docs/examples/nlohmann_json_namespace.output new file mode 100644 index 000000000..e0cb53b10 --- /dev/null +++ b/docs/mkdocs/docs/examples/nlohmann_json_namespace.output @@ -0,0 +1 @@ +nlohmann::json_abi_v3_12_0 diff --git a/docs/examples/nlohmann_json_namespace_begin.c++17.cpp b/docs/mkdocs/docs/examples/nlohmann_json_namespace_begin.c++17.cpp similarity index 100% rename from docs/examples/nlohmann_json_namespace_begin.c++17.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_namespace_begin.c++17.cpp diff --git a/docs/examples/nlohmann_json_namespace_begin.c++17.output b/docs/mkdocs/docs/examples/nlohmann_json_namespace_begin.c++17.output similarity index 100% rename from docs/examples/nlohmann_json_namespace_begin.c++17.output rename to docs/mkdocs/docs/examples/nlohmann_json_namespace_begin.c++17.output diff --git a/docs/examples/nlohmann_json_namespace_no_version.cpp b/docs/mkdocs/docs/examples/nlohmann_json_namespace_no_version.cpp similarity index 100% rename from docs/examples/nlohmann_json_namespace_no_version.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_namespace_no_version.cpp diff --git a/docs/examples/nlohmann_json_namespace_no_version.output b/docs/mkdocs/docs/examples/nlohmann_json_namespace_no_version.output similarity index 100% rename from docs/examples/nlohmann_json_namespace_no_version.output rename to docs/mkdocs/docs/examples/nlohmann_json_namespace_no_version.output diff --git a/docs/examples/nlohmann_json_serialize_enum.cpp b/docs/mkdocs/docs/examples/nlohmann_json_serialize_enum.cpp similarity index 100% rename from docs/examples/nlohmann_json_serialize_enum.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_serialize_enum.cpp diff --git a/docs/examples/nlohmann_json_serialize_enum.output b/docs/mkdocs/docs/examples/nlohmann_json_serialize_enum.output similarity index 100% rename from docs/examples/nlohmann_json_serialize_enum.output rename to docs/mkdocs/docs/examples/nlohmann_json_serialize_enum.output diff --git a/docs/examples/nlohmann_json_serialize_enum_2.cpp b/docs/mkdocs/docs/examples/nlohmann_json_serialize_enum_2.cpp similarity index 100% rename from docs/examples/nlohmann_json_serialize_enum_2.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_serialize_enum_2.cpp diff --git a/docs/examples/nlohmann_json_serialize_enum_2.output b/docs/mkdocs/docs/examples/nlohmann_json_serialize_enum_2.output similarity index 100% rename from docs/examples/nlohmann_json_serialize_enum_2.output rename to docs/mkdocs/docs/examples/nlohmann_json_serialize_enum_2.output diff --git a/docs/examples/nlohmann_json_version.cpp b/docs/mkdocs/docs/examples/nlohmann_json_version.cpp similarity index 100% rename from docs/examples/nlohmann_json_version.cpp rename to docs/mkdocs/docs/examples/nlohmann_json_version.cpp diff --git a/docs/mkdocs/docs/examples/nlohmann_json_version.output b/docs/mkdocs/docs/examples/nlohmann_json_version.output new file mode 100644 index 000000000..0976940fc --- /dev/null +++ b/docs/mkdocs/docs/examples/nlohmann_json_version.output @@ -0,0 +1 @@ +JSON for Modern C++ version 3.12.0 diff --git a/docs/examples/number_float_t.cpp b/docs/mkdocs/docs/examples/number_float_t.cpp similarity index 100% rename from docs/examples/number_float_t.cpp rename to docs/mkdocs/docs/examples/number_float_t.cpp diff --git a/docs/examples/number_float_t.output b/docs/mkdocs/docs/examples/number_float_t.output similarity index 100% rename from docs/examples/number_float_t.output rename to docs/mkdocs/docs/examples/number_float_t.output diff --git a/docs/examples/number_integer_t.cpp b/docs/mkdocs/docs/examples/number_integer_t.cpp similarity index 100% rename from docs/examples/number_integer_t.cpp rename to docs/mkdocs/docs/examples/number_integer_t.cpp diff --git a/docs/examples/number_integer_t.output b/docs/mkdocs/docs/examples/number_integer_t.output similarity index 100% rename from docs/examples/number_integer_t.output rename to docs/mkdocs/docs/examples/number_integer_t.output diff --git a/docs/examples/number_unsigned_t.cpp b/docs/mkdocs/docs/examples/number_unsigned_t.cpp similarity index 100% rename from docs/examples/number_unsigned_t.cpp rename to docs/mkdocs/docs/examples/number_unsigned_t.cpp diff --git a/docs/examples/number_unsigned_t.output b/docs/mkdocs/docs/examples/number_unsigned_t.output similarity index 100% rename from docs/examples/number_unsigned_t.output rename to docs/mkdocs/docs/examples/number_unsigned_t.output diff --git a/docs/examples/object.cpp b/docs/mkdocs/docs/examples/object.cpp similarity index 100% rename from docs/examples/object.cpp rename to docs/mkdocs/docs/examples/object.cpp diff --git a/docs/examples/object.output b/docs/mkdocs/docs/examples/object.output similarity index 100% rename from docs/examples/object.output rename to docs/mkdocs/docs/examples/object.output diff --git a/docs/examples/object_comparator_t.cpp b/docs/mkdocs/docs/examples/object_comparator_t.cpp similarity index 100% rename from docs/examples/object_comparator_t.cpp rename to docs/mkdocs/docs/examples/object_comparator_t.cpp diff --git a/docs/examples/object_comparator_t.output b/docs/mkdocs/docs/examples/object_comparator_t.output similarity index 100% rename from docs/examples/object_comparator_t.output rename to docs/mkdocs/docs/examples/object_comparator_t.output diff --git a/docs/examples/object_t.cpp b/docs/mkdocs/docs/examples/object_t.cpp similarity index 100% rename from docs/examples/object_t.cpp rename to docs/mkdocs/docs/examples/object_t.cpp diff --git a/docs/examples/object_t.output b/docs/mkdocs/docs/examples/object_t.output similarity index 100% rename from docs/examples/object_t.output rename to docs/mkdocs/docs/examples/object_t.output diff --git a/docs/examples/operator__ValueType.cpp b/docs/mkdocs/docs/examples/operator__ValueType.cpp similarity index 100% rename from docs/examples/operator__ValueType.cpp rename to docs/mkdocs/docs/examples/operator__ValueType.cpp diff --git a/docs/examples/operator__ValueType.output b/docs/mkdocs/docs/examples/operator__ValueType.output similarity index 100% rename from docs/examples/operator__ValueType.output rename to docs/mkdocs/docs/examples/operator__ValueType.output diff --git a/docs/examples/operator__equal.cpp b/docs/mkdocs/docs/examples/operator__equal.cpp similarity index 100% rename from docs/examples/operator__equal.cpp rename to docs/mkdocs/docs/examples/operator__equal.cpp diff --git a/docs/examples/operator__equal.output b/docs/mkdocs/docs/examples/operator__equal.output similarity index 100% rename from docs/examples/operator__equal.output rename to docs/mkdocs/docs/examples/operator__equal.output diff --git a/docs/examples/operator__equal__nullptr_t.cpp b/docs/mkdocs/docs/examples/operator__equal__nullptr_t.cpp similarity index 100% rename from docs/examples/operator__equal__nullptr_t.cpp rename to docs/mkdocs/docs/examples/operator__equal__nullptr_t.cpp diff --git a/docs/examples/operator__equal__nullptr_t.output b/docs/mkdocs/docs/examples/operator__equal__nullptr_t.output similarity index 100% rename from docs/examples/operator__equal__nullptr_t.output rename to docs/mkdocs/docs/examples/operator__equal__nullptr_t.output diff --git a/docs/examples/operator__equal__specializations.cpp b/docs/mkdocs/docs/examples/operator__equal__specializations.cpp similarity index 100% rename from docs/examples/operator__equal__specializations.cpp rename to docs/mkdocs/docs/examples/operator__equal__specializations.cpp diff --git a/docs/examples/operator__equal__specializations.output b/docs/mkdocs/docs/examples/operator__equal__specializations.output similarity index 100% rename from docs/examples/operator__equal__specializations.output rename to docs/mkdocs/docs/examples/operator__equal__specializations.output diff --git a/docs/examples/operator__greater.cpp b/docs/mkdocs/docs/examples/operator__greater.cpp similarity index 100% rename from docs/examples/operator__greater.cpp rename to docs/mkdocs/docs/examples/operator__greater.cpp diff --git a/docs/examples/operator__greater.output b/docs/mkdocs/docs/examples/operator__greater.output similarity index 100% rename from docs/examples/operator__greater.output rename to docs/mkdocs/docs/examples/operator__greater.output diff --git a/docs/examples/operator__greaterequal.cpp b/docs/mkdocs/docs/examples/operator__greaterequal.cpp similarity index 100% rename from docs/examples/operator__greaterequal.cpp rename to docs/mkdocs/docs/examples/operator__greaterequal.cpp diff --git a/docs/examples/operator__greaterequal.output b/docs/mkdocs/docs/examples/operator__greaterequal.output similarity index 100% rename from docs/examples/operator__greaterequal.output rename to docs/mkdocs/docs/examples/operator__greaterequal.output diff --git a/docs/examples/operator__less.cpp b/docs/mkdocs/docs/examples/operator__less.cpp similarity index 100% rename from docs/examples/operator__less.cpp rename to docs/mkdocs/docs/examples/operator__less.cpp diff --git a/docs/examples/operator__less.output b/docs/mkdocs/docs/examples/operator__less.output similarity index 100% rename from docs/examples/operator__less.output rename to docs/mkdocs/docs/examples/operator__less.output diff --git a/docs/examples/operator__lessequal.cpp b/docs/mkdocs/docs/examples/operator__lessequal.cpp similarity index 100% rename from docs/examples/operator__lessequal.cpp rename to docs/mkdocs/docs/examples/operator__lessequal.cpp diff --git a/docs/examples/operator__lessequal.output b/docs/mkdocs/docs/examples/operator__lessequal.output similarity index 100% rename from docs/examples/operator__lessequal.output rename to docs/mkdocs/docs/examples/operator__lessequal.output diff --git a/docs/examples/operator__notequal.cpp b/docs/mkdocs/docs/examples/operator__notequal.cpp similarity index 100% rename from docs/examples/operator__notequal.cpp rename to docs/mkdocs/docs/examples/operator__notequal.cpp diff --git a/docs/examples/operator__notequal.output b/docs/mkdocs/docs/examples/operator__notequal.output similarity index 100% rename from docs/examples/operator__notequal.output rename to docs/mkdocs/docs/examples/operator__notequal.output diff --git a/docs/examples/operator__notequal__nullptr_t.cpp b/docs/mkdocs/docs/examples/operator__notequal__nullptr_t.cpp similarity index 100% rename from docs/examples/operator__notequal__nullptr_t.cpp rename to docs/mkdocs/docs/examples/operator__notequal__nullptr_t.cpp diff --git a/docs/examples/operator__notequal__nullptr_t.output b/docs/mkdocs/docs/examples/operator__notequal__nullptr_t.output similarity index 100% rename from docs/examples/operator__notequal__nullptr_t.output rename to docs/mkdocs/docs/examples/operator__notequal__nullptr_t.output diff --git a/docs/examples/operator__value_t.cpp b/docs/mkdocs/docs/examples/operator__value_t.cpp similarity index 100% rename from docs/examples/operator__value_t.cpp rename to docs/mkdocs/docs/examples/operator__value_t.cpp diff --git a/docs/examples/operator__value_t.output b/docs/mkdocs/docs/examples/operator__value_t.output similarity index 100% rename from docs/examples/operator__value_t.output rename to docs/mkdocs/docs/examples/operator__value_t.output diff --git a/docs/examples/operator_array__json_pointer.cpp b/docs/mkdocs/docs/examples/operator_array__json_pointer.cpp similarity index 100% rename from docs/examples/operator_array__json_pointer.cpp rename to docs/mkdocs/docs/examples/operator_array__json_pointer.cpp diff --git a/docs/examples/operator_array__json_pointer.output b/docs/mkdocs/docs/examples/operator_array__json_pointer.output similarity index 100% rename from docs/examples/operator_array__json_pointer.output rename to docs/mkdocs/docs/examples/operator_array__json_pointer.output diff --git a/docs/examples/operator_array__json_pointer_const.cpp b/docs/mkdocs/docs/examples/operator_array__json_pointer_const.cpp similarity index 100% rename from docs/examples/operator_array__json_pointer_const.cpp rename to docs/mkdocs/docs/examples/operator_array__json_pointer_const.cpp diff --git a/docs/examples/operator_array__json_pointer_const.output b/docs/mkdocs/docs/examples/operator_array__json_pointer_const.output similarity index 100% rename from docs/examples/operator_array__json_pointer_const.output rename to docs/mkdocs/docs/examples/operator_array__json_pointer_const.output diff --git a/docs/examples/operator_array__keytype.c++17.cpp b/docs/mkdocs/docs/examples/operator_array__keytype.c++17.cpp similarity index 100% rename from docs/examples/operator_array__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/operator_array__keytype.c++17.cpp diff --git a/docs/examples/operator_array__keytype.c++17.output b/docs/mkdocs/docs/examples/operator_array__keytype.c++17.output similarity index 100% rename from docs/examples/operator_array__keytype.c++17.output rename to docs/mkdocs/docs/examples/operator_array__keytype.c++17.output diff --git a/docs/examples/operator_array__keytype_const.c++17.cpp b/docs/mkdocs/docs/examples/operator_array__keytype_const.c++17.cpp similarity index 100% rename from docs/examples/operator_array__keytype_const.c++17.cpp rename to docs/mkdocs/docs/examples/operator_array__keytype_const.c++17.cpp diff --git a/docs/examples/operator_array__keytype_const.c++17.output b/docs/mkdocs/docs/examples/operator_array__keytype_const.c++17.output similarity index 100% rename from docs/examples/operator_array__keytype_const.c++17.output rename to docs/mkdocs/docs/examples/operator_array__keytype_const.c++17.output diff --git a/docs/examples/operator_array__object_t_key_type.cpp b/docs/mkdocs/docs/examples/operator_array__object_t_key_type.cpp similarity index 100% rename from docs/examples/operator_array__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/operator_array__object_t_key_type.cpp diff --git a/docs/examples/operator_array__object_t_key_type.output b/docs/mkdocs/docs/examples/operator_array__object_t_key_type.output similarity index 100% rename from docs/examples/operator_array__object_t_key_type.output rename to docs/mkdocs/docs/examples/operator_array__object_t_key_type.output diff --git a/docs/examples/operator_array__object_t_key_type_const.cpp b/docs/mkdocs/docs/examples/operator_array__object_t_key_type_const.cpp similarity index 100% rename from docs/examples/operator_array__object_t_key_type_const.cpp rename to docs/mkdocs/docs/examples/operator_array__object_t_key_type_const.cpp diff --git a/docs/examples/operator_array__object_t_key_type_const.output b/docs/mkdocs/docs/examples/operator_array__object_t_key_type_const.output similarity index 100% rename from docs/examples/operator_array__object_t_key_type_const.output rename to docs/mkdocs/docs/examples/operator_array__object_t_key_type_const.output diff --git a/docs/examples/operator_array__size_type.cpp b/docs/mkdocs/docs/examples/operator_array__size_type.cpp similarity index 100% rename from docs/examples/operator_array__size_type.cpp rename to docs/mkdocs/docs/examples/operator_array__size_type.cpp diff --git a/docs/examples/operator_array__size_type.output b/docs/mkdocs/docs/examples/operator_array__size_type.output similarity index 100% rename from docs/examples/operator_array__size_type.output rename to docs/mkdocs/docs/examples/operator_array__size_type.output diff --git a/docs/examples/operator_array__size_type_const.cpp b/docs/mkdocs/docs/examples/operator_array__size_type_const.cpp similarity index 100% rename from docs/examples/operator_array__size_type_const.cpp rename to docs/mkdocs/docs/examples/operator_array__size_type_const.cpp diff --git a/docs/examples/operator_array__size_type_const.output b/docs/mkdocs/docs/examples/operator_array__size_type_const.output similarity index 100% rename from docs/examples/operator_array__size_type_const.output rename to docs/mkdocs/docs/examples/operator_array__size_type_const.output diff --git a/docs/examples/operator_deserialize.cpp b/docs/mkdocs/docs/examples/operator_deserialize.cpp similarity index 100% rename from docs/examples/operator_deserialize.cpp rename to docs/mkdocs/docs/examples/operator_deserialize.cpp diff --git a/docs/examples/operator_deserialize.output b/docs/mkdocs/docs/examples/operator_deserialize.output similarity index 100% rename from docs/examples/operator_deserialize.output rename to docs/mkdocs/docs/examples/operator_deserialize.output diff --git a/docs/examples/operator_literal_json.cpp b/docs/mkdocs/docs/examples/operator_literal_json.cpp similarity index 100% rename from docs/examples/operator_literal_json.cpp rename to docs/mkdocs/docs/examples/operator_literal_json.cpp diff --git a/docs/examples/operator_literal_json.output b/docs/mkdocs/docs/examples/operator_literal_json.output similarity index 100% rename from docs/examples/operator_literal_json.output rename to docs/mkdocs/docs/examples/operator_literal_json.output diff --git a/docs/examples/operator_literal_json_pointer.cpp b/docs/mkdocs/docs/examples/operator_literal_json_pointer.cpp similarity index 100% rename from docs/examples/operator_literal_json_pointer.cpp rename to docs/mkdocs/docs/examples/operator_literal_json_pointer.cpp diff --git a/docs/examples/operator_literal_json_pointer.output b/docs/mkdocs/docs/examples/operator_literal_json_pointer.output similarity index 100% rename from docs/examples/operator_literal_json_pointer.output rename to docs/mkdocs/docs/examples/operator_literal_json_pointer.output diff --git a/docs/examples/operator_ltlt__basic_json.cpp b/docs/mkdocs/docs/examples/operator_ltlt__basic_json.cpp similarity index 100% rename from docs/examples/operator_ltlt__basic_json.cpp rename to docs/mkdocs/docs/examples/operator_ltlt__basic_json.cpp diff --git a/docs/examples/operator_ltlt__basic_json.output b/docs/mkdocs/docs/examples/operator_ltlt__basic_json.output similarity index 100% rename from docs/examples/operator_ltlt__basic_json.output rename to docs/mkdocs/docs/examples/operator_ltlt__basic_json.output diff --git a/docs/examples/operator_ltlt__json_pointer.cpp b/docs/mkdocs/docs/examples/operator_ltlt__json_pointer.cpp similarity index 100% rename from docs/examples/operator_ltlt__json_pointer.cpp rename to docs/mkdocs/docs/examples/operator_ltlt__json_pointer.cpp diff --git a/docs/examples/operator_ltlt__json_pointer.output b/docs/mkdocs/docs/examples/operator_ltlt__json_pointer.output similarity index 100% rename from docs/examples/operator_ltlt__json_pointer.output rename to docs/mkdocs/docs/examples/operator_ltlt__json_pointer.output diff --git a/docs/examples/operator_spaceship__const_reference.c++20.cpp b/docs/mkdocs/docs/examples/operator_spaceship__const_reference.c++20.cpp similarity index 100% rename from docs/examples/operator_spaceship__const_reference.c++20.cpp rename to docs/mkdocs/docs/examples/operator_spaceship__const_reference.c++20.cpp diff --git a/docs/examples/operator_spaceship__const_reference.c++20.output b/docs/mkdocs/docs/examples/operator_spaceship__const_reference.c++20.output similarity index 100% rename from docs/examples/operator_spaceship__const_reference.c++20.output rename to docs/mkdocs/docs/examples/operator_spaceship__const_reference.c++20.output diff --git a/docs/examples/operator_spaceship__scalartype.c++20.cpp b/docs/mkdocs/docs/examples/operator_spaceship__scalartype.c++20.cpp similarity index 100% rename from docs/examples/operator_spaceship__scalartype.c++20.cpp rename to docs/mkdocs/docs/examples/operator_spaceship__scalartype.c++20.cpp diff --git a/docs/examples/operator_spaceship__scalartype.c++20.output b/docs/mkdocs/docs/examples/operator_spaceship__scalartype.c++20.output similarity index 100% rename from docs/examples/operator_spaceship__scalartype.c++20.output rename to docs/mkdocs/docs/examples/operator_spaceship__scalartype.c++20.output diff --git a/docs/examples/ordered_json.cpp b/docs/mkdocs/docs/examples/ordered_json.cpp similarity index 100% rename from docs/examples/ordered_json.cpp rename to docs/mkdocs/docs/examples/ordered_json.cpp diff --git a/docs/examples/ordered_json.output b/docs/mkdocs/docs/examples/ordered_json.output similarity index 100% rename from docs/examples/ordered_json.output rename to docs/mkdocs/docs/examples/ordered_json.output diff --git a/docs/examples/ordered_map.cpp b/docs/mkdocs/docs/examples/ordered_map.cpp similarity index 100% rename from docs/examples/ordered_map.cpp rename to docs/mkdocs/docs/examples/ordered_map.cpp diff --git a/docs/examples/ordered_map.output b/docs/mkdocs/docs/examples/ordered_map.output similarity index 100% rename from docs/examples/ordered_map.output rename to docs/mkdocs/docs/examples/ordered_map.output diff --git a/docs/examples/other_error.cpp b/docs/mkdocs/docs/examples/other_error.cpp similarity index 100% rename from docs/examples/other_error.cpp rename to docs/mkdocs/docs/examples/other_error.cpp diff --git a/docs/examples/other_error.output b/docs/mkdocs/docs/examples/other_error.output similarity index 100% rename from docs/examples/other_error.output rename to docs/mkdocs/docs/examples/other_error.output diff --git a/docs/examples/out_of_range.cpp b/docs/mkdocs/docs/examples/out_of_range.cpp similarity index 100% rename from docs/examples/out_of_range.cpp rename to docs/mkdocs/docs/examples/out_of_range.cpp diff --git a/docs/examples/out_of_range.output b/docs/mkdocs/docs/examples/out_of_range.output similarity index 100% rename from docs/examples/out_of_range.output rename to docs/mkdocs/docs/examples/out_of_range.output diff --git a/docs/examples/parse__allow_exceptions.cpp b/docs/mkdocs/docs/examples/parse__allow_exceptions.cpp similarity index 100% rename from docs/examples/parse__allow_exceptions.cpp rename to docs/mkdocs/docs/examples/parse__allow_exceptions.cpp diff --git a/docs/examples/parse__allow_exceptions.output b/docs/mkdocs/docs/examples/parse__allow_exceptions.output similarity index 100% rename from docs/examples/parse__allow_exceptions.output rename to docs/mkdocs/docs/examples/parse__allow_exceptions.output diff --git a/docs/examples/parse__array__parser_callback_t.cpp b/docs/mkdocs/docs/examples/parse__array__parser_callback_t.cpp similarity index 100% rename from docs/examples/parse__array__parser_callback_t.cpp rename to docs/mkdocs/docs/examples/parse__array__parser_callback_t.cpp diff --git a/docs/examples/parse__array__parser_callback_t.output b/docs/mkdocs/docs/examples/parse__array__parser_callback_t.output similarity index 100% rename from docs/examples/parse__array__parser_callback_t.output rename to docs/mkdocs/docs/examples/parse__array__parser_callback_t.output diff --git a/docs/examples/parse__contiguouscontainer__parser_callback_t.cpp b/docs/mkdocs/docs/examples/parse__contiguouscontainer__parser_callback_t.cpp similarity index 100% rename from docs/examples/parse__contiguouscontainer__parser_callback_t.cpp rename to docs/mkdocs/docs/examples/parse__contiguouscontainer__parser_callback_t.cpp diff --git a/docs/examples/parse__contiguouscontainer__parser_callback_t.output b/docs/mkdocs/docs/examples/parse__contiguouscontainer__parser_callback_t.output similarity index 100% rename from docs/examples/parse__contiguouscontainer__parser_callback_t.output rename to docs/mkdocs/docs/examples/parse__contiguouscontainer__parser_callback_t.output diff --git a/docs/examples/parse__istream__parser_callback_t.cpp b/docs/mkdocs/docs/examples/parse__istream__parser_callback_t.cpp similarity index 100% rename from docs/examples/parse__istream__parser_callback_t.cpp rename to docs/mkdocs/docs/examples/parse__istream__parser_callback_t.cpp diff --git a/docs/examples/parse__istream__parser_callback_t.output b/docs/mkdocs/docs/examples/parse__istream__parser_callback_t.output similarity index 100% rename from docs/examples/parse__istream__parser_callback_t.output rename to docs/mkdocs/docs/examples/parse__istream__parser_callback_t.output diff --git a/docs/examples/parse__iterator_pair.cpp b/docs/mkdocs/docs/examples/parse__iterator_pair.cpp similarity index 100% rename from docs/examples/parse__iterator_pair.cpp rename to docs/mkdocs/docs/examples/parse__iterator_pair.cpp diff --git a/docs/examples/parse__iterator_pair.link b/docs/mkdocs/docs/examples/parse__iterator_pair.link similarity index 100% rename from docs/examples/parse__iterator_pair.link rename to docs/mkdocs/docs/examples/parse__iterator_pair.link diff --git a/docs/examples/parse__iterator_pair.output b/docs/mkdocs/docs/examples/parse__iterator_pair.output similarity index 100% rename from docs/examples/parse__iterator_pair.output rename to docs/mkdocs/docs/examples/parse__iterator_pair.output diff --git a/docs/examples/parse__pointers.cpp b/docs/mkdocs/docs/examples/parse__pointers.cpp similarity index 100% rename from docs/examples/parse__pointers.cpp rename to docs/mkdocs/docs/examples/parse__pointers.cpp diff --git a/docs/examples/parse__pointers.link b/docs/mkdocs/docs/examples/parse__pointers.link similarity index 100% rename from docs/examples/parse__pointers.link rename to docs/mkdocs/docs/examples/parse__pointers.link diff --git a/docs/examples/parse__pointers.output b/docs/mkdocs/docs/examples/parse__pointers.output similarity index 100% rename from docs/examples/parse__pointers.output rename to docs/mkdocs/docs/examples/parse__pointers.output diff --git a/docs/examples/parse__string__parser_callback_t.cpp b/docs/mkdocs/docs/examples/parse__string__parser_callback_t.cpp similarity index 100% rename from docs/examples/parse__string__parser_callback_t.cpp rename to docs/mkdocs/docs/examples/parse__string__parser_callback_t.cpp diff --git a/docs/examples/parse__string__parser_callback_t.output b/docs/mkdocs/docs/examples/parse__string__parser_callback_t.output similarity index 100% rename from docs/examples/parse__string__parser_callback_t.output rename to docs/mkdocs/docs/examples/parse__string__parser_callback_t.output diff --git a/docs/examples/parse_error.cpp b/docs/mkdocs/docs/examples/parse_error.cpp similarity index 100% rename from docs/examples/parse_error.cpp rename to docs/mkdocs/docs/examples/parse_error.cpp diff --git a/docs/examples/parse_error.output b/docs/mkdocs/docs/examples/parse_error.output similarity index 100% rename from docs/examples/parse_error.output rename to docs/mkdocs/docs/examples/parse_error.output diff --git a/docs/examples/patch.cpp b/docs/mkdocs/docs/examples/patch.cpp similarity index 100% rename from docs/examples/patch.cpp rename to docs/mkdocs/docs/examples/patch.cpp diff --git a/docs/examples/patch.output b/docs/mkdocs/docs/examples/patch.output similarity index 100% rename from docs/examples/patch.output rename to docs/mkdocs/docs/examples/patch.output diff --git a/docs/examples/patch_inplace.cpp b/docs/mkdocs/docs/examples/patch_inplace.cpp similarity index 100% rename from docs/examples/patch_inplace.cpp rename to docs/mkdocs/docs/examples/patch_inplace.cpp diff --git a/docs/examples/patch_inplace.output b/docs/mkdocs/docs/examples/patch_inplace.output similarity index 100% rename from docs/examples/patch_inplace.output rename to docs/mkdocs/docs/examples/patch_inplace.output diff --git a/docs/examples/push_back.cpp b/docs/mkdocs/docs/examples/push_back.cpp similarity index 100% rename from docs/examples/push_back.cpp rename to docs/mkdocs/docs/examples/push_back.cpp diff --git a/docs/examples/push_back.output b/docs/mkdocs/docs/examples/push_back.output similarity index 100% rename from docs/examples/push_back.output rename to docs/mkdocs/docs/examples/push_back.output diff --git a/docs/examples/push_back__initializer_list.cpp b/docs/mkdocs/docs/examples/push_back__initializer_list.cpp similarity index 100% rename from docs/examples/push_back__initializer_list.cpp rename to docs/mkdocs/docs/examples/push_back__initializer_list.cpp diff --git a/docs/examples/push_back__initializer_list.output b/docs/mkdocs/docs/examples/push_back__initializer_list.output similarity index 100% rename from docs/examples/push_back__initializer_list.output rename to docs/mkdocs/docs/examples/push_back__initializer_list.output diff --git a/docs/examples/push_back__object_t__value.cpp b/docs/mkdocs/docs/examples/push_back__object_t__value.cpp similarity index 100% rename from docs/examples/push_back__object_t__value.cpp rename to docs/mkdocs/docs/examples/push_back__object_t__value.cpp diff --git a/docs/examples/push_back__object_t__value.output b/docs/mkdocs/docs/examples/push_back__object_t__value.output similarity index 100% rename from docs/examples/push_back__object_t__value.output rename to docs/mkdocs/docs/examples/push_back__object_t__value.output diff --git a/docs/examples/rbegin.cpp b/docs/mkdocs/docs/examples/rbegin.cpp similarity index 100% rename from docs/examples/rbegin.cpp rename to docs/mkdocs/docs/examples/rbegin.cpp diff --git a/docs/examples/rbegin.output b/docs/mkdocs/docs/examples/rbegin.output similarity index 100% rename from docs/examples/rbegin.output rename to docs/mkdocs/docs/examples/rbegin.output diff --git a/docs/examples/rend.cpp b/docs/mkdocs/docs/examples/rend.cpp similarity index 100% rename from docs/examples/rend.cpp rename to docs/mkdocs/docs/examples/rend.cpp diff --git a/docs/examples/rend.output b/docs/mkdocs/docs/examples/rend.output similarity index 100% rename from docs/examples/rend.output rename to docs/mkdocs/docs/examples/rend.output diff --git a/docs/examples/sax_parse.cpp b/docs/mkdocs/docs/examples/sax_parse.cpp similarity index 100% rename from docs/examples/sax_parse.cpp rename to docs/mkdocs/docs/examples/sax_parse.cpp diff --git a/docs/examples/sax_parse.output b/docs/mkdocs/docs/examples/sax_parse.output similarity index 100% rename from docs/examples/sax_parse.output rename to docs/mkdocs/docs/examples/sax_parse.output diff --git a/docs/examples/sax_parse__binary.cpp b/docs/mkdocs/docs/examples/sax_parse__binary.cpp similarity index 100% rename from docs/examples/sax_parse__binary.cpp rename to docs/mkdocs/docs/examples/sax_parse__binary.cpp diff --git a/docs/examples/sax_parse__binary.output b/docs/mkdocs/docs/examples/sax_parse__binary.output similarity index 100% rename from docs/examples/sax_parse__binary.output rename to docs/mkdocs/docs/examples/sax_parse__binary.output diff --git a/docs/examples/size.cpp b/docs/mkdocs/docs/examples/size.cpp similarity index 100% rename from docs/examples/size.cpp rename to docs/mkdocs/docs/examples/size.cpp diff --git a/docs/examples/size.output b/docs/mkdocs/docs/examples/size.output similarity index 100% rename from docs/examples/size.output rename to docs/mkdocs/docs/examples/size.output diff --git a/docs/examples/std_hash.cpp b/docs/mkdocs/docs/examples/std_hash.cpp similarity index 100% rename from docs/examples/std_hash.cpp rename to docs/mkdocs/docs/examples/std_hash.cpp diff --git a/docs/examples/std_hash.output b/docs/mkdocs/docs/examples/std_hash.output similarity index 100% rename from docs/examples/std_hash.output rename to docs/mkdocs/docs/examples/std_hash.output diff --git a/docs/examples/std_swap.cpp b/docs/mkdocs/docs/examples/std_swap.cpp similarity index 100% rename from docs/examples/std_swap.cpp rename to docs/mkdocs/docs/examples/std_swap.cpp diff --git a/docs/examples/std_swap.output b/docs/mkdocs/docs/examples/std_swap.output similarity index 100% rename from docs/examples/std_swap.output rename to docs/mkdocs/docs/examples/std_swap.output diff --git a/docs/examples/string_t.cpp b/docs/mkdocs/docs/examples/string_t.cpp similarity index 100% rename from docs/examples/string_t.cpp rename to docs/mkdocs/docs/examples/string_t.cpp diff --git a/docs/examples/string_t.output b/docs/mkdocs/docs/examples/string_t.output similarity index 100% rename from docs/examples/string_t.output rename to docs/mkdocs/docs/examples/string_t.output diff --git a/docs/examples/swap__array_t.cpp b/docs/mkdocs/docs/examples/swap__array_t.cpp similarity index 100% rename from docs/examples/swap__array_t.cpp rename to docs/mkdocs/docs/examples/swap__array_t.cpp diff --git a/docs/examples/swap__array_t.output b/docs/mkdocs/docs/examples/swap__array_t.output similarity index 100% rename from docs/examples/swap__array_t.output rename to docs/mkdocs/docs/examples/swap__array_t.output diff --git a/docs/examples/swap__binary_t.cpp b/docs/mkdocs/docs/examples/swap__binary_t.cpp similarity index 100% rename from docs/examples/swap__binary_t.cpp rename to docs/mkdocs/docs/examples/swap__binary_t.cpp diff --git a/docs/examples/swap__binary_t.output b/docs/mkdocs/docs/examples/swap__binary_t.output similarity index 100% rename from docs/examples/swap__binary_t.output rename to docs/mkdocs/docs/examples/swap__binary_t.output diff --git a/docs/examples/swap__object_t.cpp b/docs/mkdocs/docs/examples/swap__object_t.cpp similarity index 100% rename from docs/examples/swap__object_t.cpp rename to docs/mkdocs/docs/examples/swap__object_t.cpp diff --git a/docs/examples/swap__object_t.output b/docs/mkdocs/docs/examples/swap__object_t.output similarity index 100% rename from docs/examples/swap__object_t.output rename to docs/mkdocs/docs/examples/swap__object_t.output diff --git a/docs/examples/swap__reference.cpp b/docs/mkdocs/docs/examples/swap__reference.cpp similarity index 100% rename from docs/examples/swap__reference.cpp rename to docs/mkdocs/docs/examples/swap__reference.cpp diff --git a/docs/examples/swap__reference.output b/docs/mkdocs/docs/examples/swap__reference.output similarity index 100% rename from docs/examples/swap__reference.output rename to docs/mkdocs/docs/examples/swap__reference.output diff --git a/docs/examples/swap__string_t.cpp b/docs/mkdocs/docs/examples/swap__string_t.cpp similarity index 100% rename from docs/examples/swap__string_t.cpp rename to docs/mkdocs/docs/examples/swap__string_t.cpp diff --git a/docs/examples/swap__string_t.output b/docs/mkdocs/docs/examples/swap__string_t.output similarity index 100% rename from docs/examples/swap__string_t.output rename to docs/mkdocs/docs/examples/swap__string_t.output diff --git a/docs/examples/to_bjdata.cpp b/docs/mkdocs/docs/examples/to_bjdata.cpp similarity index 100% rename from docs/examples/to_bjdata.cpp rename to docs/mkdocs/docs/examples/to_bjdata.cpp diff --git a/docs/examples/to_bjdata.output b/docs/mkdocs/docs/examples/to_bjdata.output similarity index 100% rename from docs/examples/to_bjdata.output rename to docs/mkdocs/docs/examples/to_bjdata.output diff --git a/docs/examples/to_bson.cpp b/docs/mkdocs/docs/examples/to_bson.cpp similarity index 100% rename from docs/examples/to_bson.cpp rename to docs/mkdocs/docs/examples/to_bson.cpp diff --git a/docs/examples/to_bson.output b/docs/mkdocs/docs/examples/to_bson.output similarity index 100% rename from docs/examples/to_bson.output rename to docs/mkdocs/docs/examples/to_bson.output diff --git a/docs/examples/to_cbor.cpp b/docs/mkdocs/docs/examples/to_cbor.cpp similarity index 100% rename from docs/examples/to_cbor.cpp rename to docs/mkdocs/docs/examples/to_cbor.cpp diff --git a/docs/examples/to_cbor.output b/docs/mkdocs/docs/examples/to_cbor.output similarity index 100% rename from docs/examples/to_cbor.output rename to docs/mkdocs/docs/examples/to_cbor.output diff --git a/docs/examples/to_json.cpp b/docs/mkdocs/docs/examples/to_json.cpp similarity index 100% rename from docs/examples/to_json.cpp rename to docs/mkdocs/docs/examples/to_json.cpp diff --git a/docs/examples/to_json.output b/docs/mkdocs/docs/examples/to_json.output similarity index 100% rename from docs/examples/to_json.output rename to docs/mkdocs/docs/examples/to_json.output diff --git a/docs/examples/to_msgpack.cpp b/docs/mkdocs/docs/examples/to_msgpack.cpp similarity index 100% rename from docs/examples/to_msgpack.cpp rename to docs/mkdocs/docs/examples/to_msgpack.cpp diff --git a/docs/examples/to_msgpack.output b/docs/mkdocs/docs/examples/to_msgpack.output similarity index 100% rename from docs/examples/to_msgpack.output rename to docs/mkdocs/docs/examples/to_msgpack.output diff --git a/docs/examples/to_string.cpp b/docs/mkdocs/docs/examples/to_string.cpp similarity index 100% rename from docs/examples/to_string.cpp rename to docs/mkdocs/docs/examples/to_string.cpp diff --git a/docs/examples/to_string.output b/docs/mkdocs/docs/examples/to_string.output similarity index 100% rename from docs/examples/to_string.output rename to docs/mkdocs/docs/examples/to_string.output diff --git a/docs/examples/to_ubjson.cpp b/docs/mkdocs/docs/examples/to_ubjson.cpp similarity index 100% rename from docs/examples/to_ubjson.cpp rename to docs/mkdocs/docs/examples/to_ubjson.cpp diff --git a/docs/examples/to_ubjson.output b/docs/mkdocs/docs/examples/to_ubjson.output similarity index 100% rename from docs/examples/to_ubjson.output rename to docs/mkdocs/docs/examples/to_ubjson.output diff --git a/docs/examples/type.cpp b/docs/mkdocs/docs/examples/type.cpp similarity index 100% rename from docs/examples/type.cpp rename to docs/mkdocs/docs/examples/type.cpp diff --git a/docs/examples/type.output b/docs/mkdocs/docs/examples/type.output similarity index 100% rename from docs/examples/type.output rename to docs/mkdocs/docs/examples/type.output diff --git a/docs/examples/type_error.cpp b/docs/mkdocs/docs/examples/type_error.cpp similarity index 100% rename from docs/examples/type_error.cpp rename to docs/mkdocs/docs/examples/type_error.cpp diff --git a/docs/examples/type_error.output b/docs/mkdocs/docs/examples/type_error.output similarity index 100% rename from docs/examples/type_error.output rename to docs/mkdocs/docs/examples/type_error.output diff --git a/docs/examples/type_name.cpp b/docs/mkdocs/docs/examples/type_name.cpp similarity index 100% rename from docs/examples/type_name.cpp rename to docs/mkdocs/docs/examples/type_name.cpp diff --git a/docs/examples/type_name.output b/docs/mkdocs/docs/examples/type_name.output similarity index 100% rename from docs/examples/type_name.output rename to docs/mkdocs/docs/examples/type_name.output diff --git a/docs/examples/unflatten.cpp b/docs/mkdocs/docs/examples/unflatten.cpp similarity index 100% rename from docs/examples/unflatten.cpp rename to docs/mkdocs/docs/examples/unflatten.cpp diff --git a/docs/examples/unflatten.output b/docs/mkdocs/docs/examples/unflatten.output similarity index 100% rename from docs/examples/unflatten.output rename to docs/mkdocs/docs/examples/unflatten.output diff --git a/docs/examples/update.cpp b/docs/mkdocs/docs/examples/update.cpp similarity index 100% rename from docs/examples/update.cpp rename to docs/mkdocs/docs/examples/update.cpp diff --git a/docs/examples/update.output b/docs/mkdocs/docs/examples/update.output similarity index 100% rename from docs/examples/update.output rename to docs/mkdocs/docs/examples/update.output diff --git a/docs/examples/update__range.cpp b/docs/mkdocs/docs/examples/update__range.cpp similarity index 100% rename from docs/examples/update__range.cpp rename to docs/mkdocs/docs/examples/update__range.cpp diff --git a/docs/examples/update__range.output b/docs/mkdocs/docs/examples/update__range.output similarity index 100% rename from docs/examples/update__range.output rename to docs/mkdocs/docs/examples/update__range.output diff --git a/docs/examples/value__json_ptr.cpp b/docs/mkdocs/docs/examples/value__json_ptr.cpp similarity index 100% rename from docs/examples/value__json_ptr.cpp rename to docs/mkdocs/docs/examples/value__json_ptr.cpp diff --git a/docs/examples/value__json_ptr.output b/docs/mkdocs/docs/examples/value__json_ptr.output similarity index 100% rename from docs/examples/value__json_ptr.output rename to docs/mkdocs/docs/examples/value__json_ptr.output diff --git a/docs/examples/value__keytype.c++17.cpp b/docs/mkdocs/docs/examples/value__keytype.c++17.cpp similarity index 100% rename from docs/examples/value__keytype.c++17.cpp rename to docs/mkdocs/docs/examples/value__keytype.c++17.cpp diff --git a/docs/examples/value__keytype.c++17.output b/docs/mkdocs/docs/examples/value__keytype.c++17.output similarity index 100% rename from docs/examples/value__keytype.c++17.output rename to docs/mkdocs/docs/examples/value__keytype.c++17.output diff --git a/docs/examples/value__object_t_key_type.cpp b/docs/mkdocs/docs/examples/value__object_t_key_type.cpp similarity index 100% rename from docs/examples/value__object_t_key_type.cpp rename to docs/mkdocs/docs/examples/value__object_t_key_type.cpp diff --git a/docs/examples/value__object_t_key_type.output b/docs/mkdocs/docs/examples/value__object_t_key_type.output similarity index 100% rename from docs/examples/value__object_t_key_type.output rename to docs/mkdocs/docs/examples/value__object_t_key_type.output diff --git a/docs/mkdocs/docs/examples/value__return_type.cpp b/docs/mkdocs/docs/examples/value__return_type.cpp new file mode 100644 index 000000000..51ab7afa0 --- /dev/null +++ b/docs/mkdocs/docs/examples/value__return_type.cpp @@ -0,0 +1,14 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + json j = json::parse(R"({"uint64": 18446744073709551615})"); + + std::cout << "operator[]: " << j["uint64"] << '\n' + << "default value (int): " << j.value("uint64", 0) << '\n' + << "default value (uint64_t): " << j.value("uint64", std::uint64_t(0)) << '\n' + << "explict return value type: " << j.value("uint64", 0) << '\n'; +} diff --git a/docs/mkdocs/docs/examples/value__return_type.output b/docs/mkdocs/docs/examples/value__return_type.output new file mode 100644 index 000000000..9d43f5e6e --- /dev/null +++ b/docs/mkdocs/docs/examples/value__return_type.output @@ -0,0 +1,4 @@ +operator[]: 18446744073709551615 +default value (int): -1 +default value (uint64_t): 18446744073709551615 +explict return value type: 18446744073709551615 diff --git a/docs/mkdocs/docs/features/arbitrary_types.md b/docs/mkdocs/docs/features/arbitrary_types.md index 9b54fcb3e..c0fa4515c 100644 --- a/docs/mkdocs/docs/features/arbitrary_types.md +++ b/docs/mkdocs/docs/features/arbitrary_types.md @@ -75,7 +75,7 @@ Likewise, when calling `template get()` or `get_to(your_type&)`, the Some important things: * Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). -* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. +* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [#1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `template get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](../api/basic_json/at.md) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. @@ -85,21 +85,41 @@ Some important things: If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. -There are four macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: +There are six macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: - [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_non_intrusive.md) is to be defined inside the namespace of the class/struct to create code for. It will throw an exception in `from_json()` due to a missing value in the JSON object. -- [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_non_intrusive.md) is to be defined inside the namespace of the class/struct to create code for. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from object which is default-constructed by the type. +- [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_non_intrusive.md) is to be defined inside the namespace of the class/struct to create code for. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from an object which is default-constructed by the type. +- [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_non_intrusive.md) is to be defined inside the namespace of the class/struct to create code for. It does not define a `from_json()` function which is needed in case the type does not have a default constructor. - [`NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_intrusive.md) is to be defined inside the class/struct to create code for. This macro can also access private members. It will throw an exception in `from_json()` due to a missing value in the JSON object. -- [`NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_intrusive.md) is to be defined inside the class/struct to create code for. This macro can also access private members. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from object which is default-constructed by the type. +- [`NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_intrusive.md) is to be defined inside the class/struct to create code for. This macro can also access private members. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from an object which is default-constructed by the type. +- [`NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(name, member1, member2, ...)`](../api/macros/nlohmann_define_type_intrusive.md) is to be defined inside the class/struct to create code for. This macro can also access private members. It does not define a `from_json()` function which is needed in case the type does not have a default constructor. -In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. You can read more docs about them starting from [here](macros.md#nlohmann_define_type_intrusivetype-member). +Furthermore, there exist versions to use in the case of derived classes: + +| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | +|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_type_intrusive.md) | +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_intrusive.md) | +|
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_type_intrusive.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE**](../api/macros/nlohmann_define_type_non_intrusive.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_non_intrusive.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_type_non_intrusive.md) | + +For _derived_ classes and structs, use the following macros + +| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro | +|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) | +|
:octicons-check-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) | +|
:octicons-check-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_derived_type.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) | +|
:octicons-x-circle-fill-24:
|
:octicons-check-circle-fill-24:
|
:octicons-skip-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE**](../api/macros/nlohmann_define_derived_type.md) | !!! info "Implementation limits" - The current macro implementations are limited to at most 64 member variables. If you want to serialize/deserialize types with more than 64 member variables, you need to define the `to_json`/`from_json` functions manually. - - The macros only work for the [`nlohmann::json`](../api/json.md) type; other specializations such as - [`nlohmann::ordered_json`](../api/ordered_json.md) are currently unsupported. ??? example @@ -129,9 +149,9 @@ In all macros, the first parameter is the name of the class/struct, and all rema ## How do I convert third-party types? -This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: +This requires a bit more advanced technique. But first, let us see how this conversion mechanism works: -The library uses **JSON Serializers** to convert types to json. +The library uses **JSON Serializers** to convert types to JSON. The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)). It is implemented like this (simplified): @@ -186,7 +206,7 @@ NLOHMANN_JSON_NAMESPACE_END ## How can I use `get()` for non-default constructible/non-copyable types? -There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: +There is a way if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: ```cpp struct move_only_type { @@ -221,7 +241,7 @@ namespace nlohmann { Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) in the test suite, to see a few examples. -If you write your own serializer, you'll need to do a few things: +If you write your own serializer, you will need to do a few things: - use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) - use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods @@ -265,7 +285,7 @@ struct bad_serializer } template - static void to_json(const BasicJsonType& j, T& value) { + static void from_json(const BasicJsonType& j, T& value) { // this calls BasicJsonType::json_serializer::from_json(j, value); // if BasicJsonType::json_serializer == bad_serializer ... oops! value = j.template template get(); // oops! diff --git a/docs/mkdocs/docs/features/assertions.md b/docs/mkdocs/docs/features/assertions.md index 2bad62e81..4d75d5a8a 100644 --- a/docs/mkdocs/docs/features/assertions.md +++ b/docs/mkdocs/docs/features/assertions.md @@ -1,7 +1,7 @@ # Runtime Assertions The code contains numerous debug assertions to ensure class invariants are valid or to detect undefined behavior. -Whereas the former class invariants are nothing to be concerned of, the latter checks for undefined behavior are to +Whereas the former class invariants are nothing to be concerned with, the latter checks for undefined behavior are to detect bugs in client code. ## Switch off runtime assertions @@ -19,8 +19,8 @@ before including the `json.hpp` header. ### Unchecked object access to a const value Function [`operator[]`](../api/basic_json/operator%5B%5D.md) implements unchecked access for objects. Whereas a missing -key is added in case of non-const objects, accessing a const object with a missing key is undefined behavior (think of a -dereferenced null pointer) and yields a runtime assertion. +key is added in the case of non-const objects, accessing a const object with a missing key is undefined behavior (think +of a dereferenced null pointer) and yields a runtime assertion. If you are not sure whether an element in an object exists, use checked access with the [`at` function](../api/basic_json/at.md) or call the [`contains` function](../api/basic_json/contains.md) before. @@ -103,29 +103,42 @@ behavior and yields a runtime assertion. Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368. ``` -### Reading from a null `FILE` pointer +## Changes -Reading from a null `#!cpp FILE` pointer is undefined behavior and yields a runtime assertion. This can happen when -calling `#!cpp std::fopen` on a nonexistent file. +### Reading from a null `FILE` or `char` pointer -??? example "Example 4: Uninitialized iterator" +Reading from a null `#!cpp FILE` or `#!cpp char` pointer in C++ is undefined behavior. Until version 3.12.0, this +library asserted that the pointer was not `nullptr` using a runtime assertion. If assertions were disabled, this would +result in undefined behavior. Since version 3.12.0, this library checks for `nullptr` and throws a +[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) to prevent the undefined behavior. + +??? example "Example 4: Reading from null pointer" The following code will trigger an assertion at runtime: ```cpp + #include #include using json = nlohmann::json; int main() { - std::FILE* f = std::fopen("nonexistent_file.json", "r"); - json j = json::parse(f); + std::FILE* f = std::fopen("nonexistent_file.json", "r"); + try { + json j = json::parse(f); + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + } } ``` Output: ``` - Assertion failed: (m_file != nullptr), function file_input_adapter, file input_adapters.hpp, line 55. + [json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON ``` + +## See also + +- [JSON_ASSERT](../api/macros/json_assert.md) - control behavior of runtime assertions diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md index a89a22885..acfdfb770 100644 --- a/docs/mkdocs/docs/features/binary_formats/bjdata.md +++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md @@ -2,15 +2,15 @@ The [BJData format](https://neurojson.org) was derived from and improved upon [Universal Binary JSON(UBJSON)](https://ubjson.org) specification (Draft 12). Specifically, it introduces an optimized -array container for efficient storage of N-dimensional packed arrays (**ND-arrays**); it also adds 4 new type markers - -`[u] - uint16`, `[m] - uint32`, `[M] - uint64` and `[h] - float16` - to unambiguously map common binary numeric types; -furthermore, it uses little-endian (LE) to store all numerics instead of big-endian (BE) as in UBJSON to avoid -unnecessary conversions on commonly available platforms. +array container for efficient storage of N-dimensional packed arrays (**ND-arrays**); it also adds 5 new type markers - +`[u] - uint16`, `[m] - uint32`, `[M] - uint64`, `[h] - float16` and `[B] - byte` - to unambiguously map common binary +numeric types; furthermore, it uses little-endian (LE) to store all numerics instead of big-endian (BE) as in UBJSON to +avoid unnecessary conversions on commonly available platforms. Compared to other binary JSON-like formats such as MessagePack and CBOR, both BJData and UBJSON demonstrate a rare combination of being both binary and **quasi-human-readable**. This is because all semantic elements in BJData and -UBJSON, including the data-type markers and name/string types are directly human-readable. Data stored in the -BJData/UBJSON format are not only compact in size, fast to read/write, but also can be directly searched or read using +UBJSON, including the data-type markers and name/string types, are directly human-readable. Data stored in the +BJData/UBJSON format is not only compact in size, fast to read/write, but also can be directly searched or read using simple processing. !!! abstract "References" @@ -49,6 +49,7 @@ The library uses the following mapping from JSON values types to BJData types ac | string | *with shortest length indicator* | string | `S` | | array | *see notes on optimized format/ND-array* | array | `[` | | object | *see notes on optimized format* | map | `{` | +| binary | *see notes on binary values* | array | `[$B` | !!! success "Complete mapping" @@ -128,15 +129,24 @@ The library uses the following mapping from JSON values types to BJData types ac Due to diminished space saving, hampered readability, and increased security risks, in BJData, the allowed data types following the `$` marker in an optimized array and object container are restricted to - **non-zero-fixed-length** data types. Therefore, the valid optimized type markers can only be one of `UiuImlMLhdDC`. - This also means other variable (`[{SH`) or zero-length types (`TFN`) can not be used in an optimized array or object - in BJData. + **non-zero-fixed-length** data types. Therefore, the valid optimized type markers can only be one of + `UiuImlMLhdDCB`. This also means other variable (`[{SH`) or zero-length types (`TFN`) can not be used in an + optimized array or object in BJData. !!! info "Binary values" - If the JSON data contains the binary type, the value stored is a list of integers, as suggested by the BJData - documentation. In particular, this means that the serialization and the deserialization of JSON containing binary - values into BJData and back will result in a different JSON object. + BJData provides a dedicated `B` marker (defined in the [BJData specification (Draft 3)][BJDataBinArr]) that is used + in optimized arrays to designate binary data. This means that, unlike UBJSON, binary data can be both serialized and + deserialized. + + To preserve compatibility with BJData Draft 2, the Draft 3 optimized binary array must be explicitly enabled using + the `version` parameter of [`to_bjdata`](../../api/basic_json/to_bjdata.md). + + In Draft2 mode (default), if the JSON data contains the binary type, the value stored as a list of integers, as + suggested by the BJData documentation. In particular, this means that the serialization and the deserialization of + JSON containing binary values into BJData and back will result in a different JSON object. + + [BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array) ??? example @@ -154,28 +164,30 @@ The library uses the following mapping from JSON values types to BJData types ac The library maps BJData types to JSON value types as follows: -| BJData type | JSON value type | marker | -|-------------|-----------------------------------------|--------| -| no-op | *no value, next value is read* | `N` | -| null | `null` | `Z` | -| false | `false` | `F` | -| true | `true` | `T` | -| float16 | number_float | `h` | -| float32 | number_float | `d` | -| float64 | number_float | `D` | -| uint8 | number_unsigned | `U` | -| int8 | number_integer | `i` | -| uint16 | number_unsigned | `u` | -| int16 | number_integer | `I` | -| uint32 | number_unsigned | `m` | -| int32 | number_integer | `l` | -| uint64 | number_unsigned | `M` | -| int64 | number_integer | `L` | -| string | string | `S` | -| char | string | `C` | -| array | array (optimized values are supported) | `[` | -| ND-array | object (in JData annotated array format)|`[$.#[.`| -| object | object (optimized values are supported) | `{` | +| BJData type | JSON value type | marker | +|-------------|------------------------------------------|----------| +| no-op | *no value, next value is read* | `N` | +| null | `null` | `Z` | +| false | `false` | `F` | +| true | `true` | `T` | +| float16 | number_float | `h` | +| float32 | number_float | `d` | +| float64 | number_float | `D` | +| uint8 | number_unsigned | `U` | +| int8 | number_integer | `i` | +| uint16 | number_unsigned | `u` | +| int16 | number_integer | `I` | +| uint32 | number_unsigned | `m` | +| int32 | number_integer | `l` | +| uint64 | number_unsigned | `M` | +| int64 | number_integer | `L` | +| byte | number_unsigned | `B` | +| string | string | `S` | +| char | string | `C` | +| array | array (optimized values are supported) | `[` | +| ND-array | object (in JData annotated array format) | `[$.#[.` | +| object | object (optimized values are supported) | `{` | +| binary | binary (strongly-typed byte array) | `[$B` | !!! success "Complete mapping" diff --git a/docs/mkdocs/docs/features/binary_formats/bson.md b/docs/mkdocs/docs/features/binary_formats/bson.md index f3b8cf18d..cf87731a0 100644 --- a/docs/mkdocs/docs/features/binary_formats/bson.md +++ b/docs/mkdocs/docs/features/binary_formats/bson.md @@ -23,7 +23,7 @@ The library uses the following mapping from JSON values types to BSON types: | number_integer | 2147483648..9223372036854775807 | int64 | 0x12 | | number_unsigned | 0..2147483647 | int32 | 0x10 | | number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 | -| number_unsigned | 9223372036854775808..18446744073709551615 | -- | -- | +| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | 0x11 | | number_float | *any value* | double | 0x01 | | string | *any value* | string | 0x02 | | array | *any value* | document | 0x04 | @@ -32,11 +32,8 @@ The library uses the following mapping from JSON values types to BSON types: !!! warning "Incomplete mapping" - The mapping is **incomplete**, since only JSON-objects (and things - contained therein) can be serialized to BSON. - Also, integers larger than 9223372036854775807 cannot be serialized to BSON, - and the keys may not contain U+0000, since they are serialized a - zero-terminated c-strings. + The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON. + Also, keys may not contain U+0000, since they are serialized a zero-terminated c-strings. ??? example @@ -73,7 +70,7 @@ The library maps BSON record types to JSON value types as follows: | Symbol | 0x0E | *unsupported* | | JavaScript Code | 0x0F | *unsupported* | | int32 | 0x10 | number_integer | -| Timestamp | 0x11 | *unsupported* | +| uint64(Timestamp) | 0x11 | number_unsigned | | 128-bit decimal float | 0x13 | *unsupported* | | Max Key | 0x7F | *unsupported* | | Min Key | 0xFF | *unsupported* | @@ -82,6 +79,10 @@ The library maps BSON record types to JSON value types as follows: The mapping is **incomplete**. The unsupported mappings are indicated in the table above. +!!! note "Handling of BSON type 0x11" + + BSON type 0x11 is used to represent uint64 numbers. This library treats these values purely as uint64 numbers + and does not parse them into date-related formats. ??? example diff --git a/docs/mkdocs/docs/features/binary_formats/index.md b/docs/mkdocs/docs/features/binary_formats/index.md index e74290b09..6714965bd 100644 --- a/docs/mkdocs/docs/features/binary_formats/index.md +++ b/docs/mkdocs/docs/features/binary_formats/index.md @@ -1,6 +1,6 @@ # Binary Formats -Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over +Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance, over a network. Hence, the library supports - [BJData](bjdata.md) (Binary JData), diff --git a/docs/mkdocs/docs/features/binary_values.md b/docs/mkdocs/docs/features/binary_values.md index 5ad6433cf..149eaaa5e 100644 --- a/docs/mkdocs/docs/features/binary_values.md +++ b/docs/mkdocs/docs/features/binary_values.md @@ -5,22 +5,24 @@ these formats support binary values; that is, values that have semantics define sequence of bytes to be stored. JSON itself does not have a binary value. As such, binary values are an extension that this library implements to store -values received by a binary format. Binary values are never created by the JSON parser, and are only part of a +values received by a binary format. Binary values are never created by the JSON parser and are only part of a serialized JSON text if they have been created manually or via a binary format. ## API for binary values -```plantuml -class json::binary_t { - -- setters -- +```mermaid +classDiagram + +class binary_t ["json::binary_t"] { +void set_subtype(std::uint64_t subtype) +void clear_subtype() - -- getters -- +std::uint64_t subtype() const +bool has_subtype() const } -"std::vector" <|-- json::binary_t +class vector ["std::vector"] + +vector <|-- binary_t ``` By default, binary values are stored as `std::vector`. This type can be changed by providing a template @@ -128,8 +130,8 @@ is an integer or `null`. ### BJData -[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes, and proposes to serialize binary values -as array of uint8 values. This translation is implemented by the library. +[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes and proposes to serialize binary values +as an array of uint8 values. The library implements this translation. ??? example @@ -313,8 +315,8 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used. ### UBJSON -[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes, and proposes to serialize binary values -as array of uint8 values. This translation is implemented by the library. +[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes and proposes to serialize binary values +as an array of uint8 values. The library implements this translation. ??? example diff --git a/docs/mkdocs/docs/features/comments.md b/docs/mkdocs/docs/features/comments.md index 61266d9ca..fca531112 100644 --- a/docs/mkdocs/docs/features/comments.md +++ b/docs/mkdocs/docs/features/comments.md @@ -5,11 +5,11 @@ This library does not support comments *by default*. It does so for three reason 1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: - > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. + > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. - > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. + > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. -3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. +3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. However, you can pass set parameter `ignore_comments` to `#!c true` in the parse function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. diff --git a/docs/mkdocs/docs/features/element_access/default_value.md b/docs/mkdocs/docs/features/element_access/default_value.md index 02b4fea3f..2603a2d18 100644 --- a/docs/mkdocs/docs/features/element_access/default_value.md +++ b/docs/mkdocs/docs/features/element_access/default_value.md @@ -2,7 +2,11 @@ ## Overview -In many situations such as configuration files, missing values are not exceptional, but may be treated as if a default value was present. +In many situations, such as configuration files, missing values are not exceptional, but may be treated as if a default +value was present. For this case, use [`value(key, default_value)`](../../api/basic_json/value.md) which takes the key +you want to access and a default value in case there is no value stored with that key. + +## Example ??? example @@ -17,16 +21,43 @@ In many situations such as configuration files, missing values are not exception Assume the value is parsed to a `json` variable `j`. - | expression | value | - | ---------- | ----- | - | `#!cpp j` | `#!json {"logOutput": "result.log", "append": true}` | - | `#!cpp j.value("logOutput", "logfile.log")` | `#!json "result.log"` | - | `#!cpp j.value("append", true)` | `#!json true` | - | `#!cpp j.value("append", false)` | `#!json true` | - | `#!cpp j.value("logLevel", "verbose")` | `#!json "verbose"` | + | expression | value | + |---------------------------------------------|------------------------------------------------------| + | `#!cpp j` | `#!json {"logOutput": "result.log", "append": true}` | + | `#!cpp j.value("logOutput", "logfile.log")` | `#!json "result.log"` | + | `#!cpp j.value("append", true)` | `#!json true` | + | `#!cpp j.value("append", false)` | `#!json true` | + | `#!cpp j.value("logLevel", "verbose")` | `#!json "verbose"` | -## Note +## Notes !!! failure "Exceptions" - `value` can only be used with objects. For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown. + +!!! warning "Return type" + + The value function is a template, and the return type of the function is determined by the type of the provided + default value unless otherwise specified. This can have unexpected effects. In the example below, we store a 64-bit + unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator[].md). However, + when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. The occurs, because `#!c 0` + has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`. + + To address this issue, either provide a correctly typed default value or use the template parameter to specify the + desired return type. Note that this issue occurs even when a value is stored at the provided key, and the default + value is not used as the return value. + + ```cpp + --8<-- "examples/value__return_type.cpp" + ``` + + Output: + + ```json + --8<-- "examples/value__return_type.output" + ``` + +## See also + +- [`value`](../../api/basic_json/value.md) for access with default value +- documentation on [checked access](checked_access.md) diff --git a/docs/mkdocs/docs/features/element_access/unchecked_access.md b/docs/mkdocs/docs/features/element_access/unchecked_access.md index 39f06dc9f..f2de067d3 100644 --- a/docs/mkdocs/docs/features/element_access/unchecked_access.md +++ b/docs/mkdocs/docs/features/element_access/unchecked_access.md @@ -29,7 +29,7 @@ similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively. | `#!cpp j["hobbies"][1]` | `#!json "reading"` | The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a -`#!json null` value is inserted which can be immediately be overwritten. +`#!json null` value is inserted which can immediately be overwritten. ??? example "Write access" diff --git a/docs/mkdocs/docs/features/enum_conversion.md b/docs/mkdocs/docs/features/enum_conversion.md index 1755bca2a..6bb3edbd3 100644 --- a/docs/mkdocs/docs/features/enum_conversion.md +++ b/docs/mkdocs/docs/features/enum_conversion.md @@ -1,7 +1,7 @@ # Specializing enum conversion By default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an -enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be +enum is modified or re-ordered after data has been serialized to JSON, the later deserialized JSON data may be undefined or a different enum value than was originally intended. It is possible to more precisely specify how a given enum is mapped to and from JSON as shown below: diff --git a/docs/mkdocs/docs/features/iterators.md b/docs/mkdocs/docs/features/iterators.md index ce627e012..ca303cb4a 100644 --- a/docs/mkdocs/docs/features/iterators.md +++ b/docs/mkdocs/docs/features/iterators.md @@ -100,7 +100,7 @@ for (auto& [key, val] : j_object.items()) !!! warning - Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See for more information. + Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See [#2040](https://github.com/nlohmann/json/issues/2040) for more information. ### Reverse iteration order diff --git a/docs/mkdocs/docs/features/json_pointer.md b/docs/mkdocs/docs/features/json_pointer.md index 04aeca504..df66ebffd 100644 --- a/docs/mkdocs/docs/features/json_pointer.md +++ b/docs/mkdocs/docs/features/json_pointer.md @@ -2,8 +2,8 @@ ## Introduction -The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address -structured values. A JSON Pointer is a string that identifies a specific value within a JSON document. +The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as an alternative means to +address structured values. A JSON Pointer is a string that identifies a specific value within a JSON document. Consider the following JSON document @@ -71,10 +71,10 @@ auto j = json::parse(R"({ })"); // access values -auto val = j["/"_json_pointer]; // {"array":["A","B","C"],...} +auto val = j[""_json_pointer]; // {"array":["A","B","C"],...} auto val1 = j["/nested/one"_json_pointer]; // 1 -auto val2 = j.at[json::json_pointer("/nested/three/1")]; // false -auto val3 = j.value[json::json_pointer("/nested/four", 0)]; // 0 +auto val2 = j.at(json::json_pointer("/nested/three/1")); // false +auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0 ``` ## Flatten / unflatten diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index 926741b09..a600edbdb 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -24,11 +24,26 @@ When enabled, exception messages contain a [JSON Pointer](json_pointer.md) to th exception, see [Extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) for an example. Note that enabling this macro increases the size of every JSON value by one pointer and adds some runtime overhead. -The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets -`JSON_DIAGNOSTICS` accordingly. +The diagnostics messages can also be controlled with the CMake option +[`JSON_Diagnostics`](../integration/cmake.md#json_diagnostics) (`OFF` by default) which sets `JSON_DIAGNOSTICS` +accordingly. See [full documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). +## `JSON_DIAGNOSTIC_POSITIONS` + +When enabled, two new member functions [`start_pos()`](../api/basic_json/start_pos.md) and +[`end_pos()`](../api/basic_json/end_pos.md) are added to [`basic_json`](../api/basic_json/index.md) values. If the value +was created by calling the[`parse`](../api/basic_json/parse.md) function, then these functions allow querying the byte +positions of the value in the input it was parsed from. The byte positions are also used in exceptions to help locate +errors. + +The diagnostics positions can also be controlled with the CMake option +[`JSON_Diagnostic_Positions`](../integration/cmake.md#json_diagnostic_positions) (`OFF` by default) which sets +`JSON_DIAGNOSTIC_POSITIONS` accordingly. + +See [full documentation of `JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) + ## `JSON_HAS_CPP_11`, `JSON_HAS_CPP_14`, `JSON_HAS_CPP_17`, `JSON_HAS_CPP_20` The library targets C++11, but also supports some features introduced in later C++ versions (e.g., `std::string_view` @@ -77,8 +92,8 @@ See [full documentation of `JSON_SKIP_LIBRARY_VERSION_CHECK`](../api/macros/json ## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK` -When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to -use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. +When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows +using the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. See [full documentation of `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`](../api/macros/json_skip_unsupported_compiler_check.md). @@ -100,57 +115,10 @@ When defined to `0`, implicit conversions are switched off. By default, implicit See [full documentation of `JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md). -## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)` +## `NLOHMANN_DEFINE_TYPE_*(...)`, `NLOHMANN_DEFINE_DERIVED_TYPE_*(...)` -This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as -serialization and (2) want to use the member variable names as object keys in that object. - -The macro is to be defined inside the class/struct to create code for. Unlike -[`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](#nlohmann_define_type_non_intrusivetype-member), it can access private members. -The first parameter is the name of the class/struct, and all remaining parameters name the members. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE`](../api/macros/nlohmann_define_type_intrusive.md). - -## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)` - -This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. It will not throw an exception in `from_json()` due to a -missing value in the JSON object, but can throw due to a mismatched type. The `from_json()` function default constructs -an object and uses its values as the defaults when calling the [`value`](../api/basic_json/value.md) function. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_intrusive.md). - -## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, member...)` - -This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE` except that it defines only the serialization code. This is -useful when the user type does not have a default constructor and only the serialization is required. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE`](../api/macros//nlohmann_define_type_intrusive.md). - -## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)` - -This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as -serialization and (2) want to use the member variable names as object keys in that object. - -The macro is to be defined inside the namespace of the class/struct to create code for. Private members cannot be -accessed. Use [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](#nlohmann_define_type_intrusivetype-member) in these scenarios. The -first parameter is the name of the class/struct, and all remaining parameters name the members. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](../api/macros/nlohmann_define_type_non_intrusive.md). - -## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)` - -This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. It will not throw an exception in `from_json()` due to a -missing value in the JSON object, but can throw due to a mismatched type. The `from_json()` function default constructs -an object and uses its values as the defaults when calling the [`value`](../api/basic_json/value.md) function. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_non_intrusive.md). - -## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, member...)` - -This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` except that it defines only the serialization code. This is -useful when the user type does not have a default constructor and only the serialization is required. - -See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE`](../api/macros//nlohmann_define_type_non_intrusive.md). +The library defines 12 macros to simplify the serialization/deserialization of types. See the page on +[arbitrary type conversion](arbitrary_types.md#simplify-your-life-with-macros) for a detailed discussion. ## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)` diff --git a/docs/mkdocs/docs/features/namespace.md b/docs/mkdocs/docs/features/namespace.md index 8cee2ccfe..460cb3be5 100644 --- a/docs/mkdocs/docs/features/namespace.md +++ b/docs/mkdocs/docs/features/namespace.md @@ -30,15 +30,16 @@ nlohmann::json_abi_diag_v3_11_2 Several incompatibilities have been observed. Amongst the most common ones is linking code compiled with different definitions of [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This is illustrated in the diagram below. -```plantuml -[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=0] as [json] -[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=1] as [json_diag] -[**some_library**] as [library] -[**application**] as [app] - -[library] ..|> [json] -[app] ..|> [json_diag] -[app] ..|>[library] +```mermaid +graph + json["nlohmann_json (v3.10.5)
JSON_DIAGNOSTICS=0"] + json_diag["nlohmann_json (v3.10.5)
JSON_DIAGNOSTICS=1"] + library["some library"] + app["application"] + + library --> json + app --> json_diag + app --> library ``` In releases prior to 3.11.0, mixing any version of the JSON library with different `JSON_DIAGNOSTICS` settings would diff --git a/docs/mkdocs/docs/features/parsing/sax_interface.md b/docs/mkdocs/docs/features/parsing/sax_interface.md index 0796a55f5..cfea680a4 100644 --- a/docs/mkdocs/docs/features/parsing/sax_interface.md +++ b/docs/mkdocs/docs/features/parsing/sax_interface.md @@ -2,27 +2,30 @@ The library uses a SAX-like interface with the following functions: -```plantuml -interface json::sax_t { - + {abstract} bool null() +```mermaid +classDiagram - + {abstract} bool boolean(bool val) - - + {abstract} bool number_integer(number_integer_t val) - + {abstract} bool number_unsigned(number_unsigned_t val) - - + {abstract} bool number_float(number_float_t val, const string_t& s) - - + {abstract} bool string(string_t& val) - + {abstract} bool binary(binary_t& val) - - + {abstract} bool start_object(std::size_t elements) - + {abstract} bool end_object() - + {abstract} bool start_array(std::size_t elements) - + {abstract} bool end_array() - + {abstract} bool key(string_t& val) - - + {abstract} bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) +class sax_t ["json::sax_t"] { + <> + +bool null()* + + +bool boolean(bool val)* + + +bool number_integer(number_integer_t val)* + +bool number_unsigned(number_unsigned_t val)* + + +bool number_float(number_float_t val, const string_t& s)* + + +bool string(string_t& val)* + +bool binary(binary_t& val)* + + +bool start_object(std::size_t elements)* + +bool end_object()* + +bool start_array(std::size_t elements)* + +bool end_array()* + +bool key(string_t& val)* + + +bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex)* } ``` @@ -43,7 +46,7 @@ bool number_float(number_float_t val, const string_t& s); // called when a string is parsed; value is passed and can be safely moved away bool string(string_t& val); // called when a binary value is parsed; value is passed and can be safely moved away -bool binary(binary& val); +bool binary(binary_t& val); // called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) bool start_object(std::size_t elements); diff --git a/docs/mkdocs/docs/features/types/index.md b/docs/mkdocs/docs/features/types/index.md index d9dfcc29a..56fb7ebe9 100644 --- a/docs/mkdocs/docs/features/types/index.md +++ b/docs/mkdocs/docs/features/types/index.md @@ -1,6 +1,6 @@ # Types -This page gives an overview how JSON values are stored and how this can be configured. +This page gives an overview of how JSON values are stored and how this can be configured. ## Overview @@ -19,8 +19,11 @@ Note there are three different types for numbers - when parsing JSON text, the b ## Storage -```plantuml -enum value_t { +```mermaid +classDiagram + +class value_t { + <> null object array @@ -33,7 +36,8 @@ enum value_t { discarded } -class json_value << (U,orchid) >> { +class json_value { + <> object_t* object array_t* array string_t* string @@ -45,17 +49,15 @@ class json_value << (U,orchid) >> { } class basic_json { - -- type and value -- - value_t m_type - json_value m_value - -- derived types -- - + typedef object_t - + typedef array_t - + typedef binary_t - + typedef boolean_t - + typedef number_integer_t - + typedef number_unsigned_t - + typedef number_float_t + -value_t m_type + -json_value m_value + +typedef object_t + +typedef array_t + +typedef binary_t + +typedef boolean_t + +typedef number_integer_t + +typedef number_unsigned_t + +typedef number_float_t } basic_json .. json_value @@ -135,7 +137,7 @@ The choice of `object_t` influences the behavior of the JSON class. With the def ### Key order -The order name/value pairs are added to the object is *not* preserved by the library. Therefore, iterating an object may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. +The order name/value pairs are added to the object are *not* preserved by the library. Therefore, iterating an object may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. ### Limits @@ -200,7 +202,7 @@ Strings are stored in UTF-8 encoding. Therefore, functions like `std::string::si [RFC 8259](https://tools.ietf.org/html/rfc8259) states: -> Software implementations are typically required to test names of object members for equality. Implementations that transform the textual representation into sequences of Unicode code units and then perform the comparison numerically, code unit by code unit, are interoperable in the sense that implementations will agree in all cases on equality or inequality of two strings. For example, implementations that compare strings with escaped characters unconverted may incorrectly find that `"a\\b"` and `"a\u005Cb"` are not equal. +> Software implementations are typically required to test names of object members for equality. Implementations that transform the textual representation into sequences of Unicode code units and then perform the comparison numerically, code unit by code unit are interoperable in the sense that implementations will agree in all cases on equality or inequality of two strings. For example, implementations that compare strings with escaped characters unconverted may incorrectly find that `"a\\b"` and `"a\u005Cb"` are not equal. This implementation is interoperable as it does compare strings code unit by code unit. @@ -229,7 +231,7 @@ See the [number handling](number_handling.md) article for a detailed discussion > The representation of numbers is similar to that used in most programming languages. A number is represented in base 10 using decimal digits. It contains an integer component that may be prefixed with an optional minus sign, which may be followed by a fraction part and/or an exponent part. Leading zeros are not allowed. (...) Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted. -This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, `number_integer_t`, `number_unsigned_t`, and `number_float_t` are used. +This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different types, `number_integer_t`, `number_unsigned_t`, and `number_float_t` are used. ### Default types @@ -239,7 +241,7 @@ With the default values for *NumberFloatType* (`#!cpp double`), the default valu ### Default behavior -- The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer literal `#!c 010` will be serialized to `#!c 8`. During deserialization, leading zeros yield an error. +- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ integer literal `#!c 010` will be serialized to `#!c 8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `#!json null`. ### Limits @@ -248,9 +250,9 @@ With the default values for *NumberFloatType* (`#!cpp double`), the default valu > An implementation may set limits on the range and precision of numbers. -When the default type is used, the maximal integer number that can be stored is `#!c 9223372036854775807` (`INT64_MAX`) and the minimal integer number that can be stored is `#!c -9223372036854775808` (`INT64_MIN`). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as `number_unsigned_t` or `number_float_t`. +When the default type is used, the maximal integer number that can be stored is `#!c 9223372036854775807` (`INT64_MAX`) and the minimal integer number that can be stored is `#!c -9223372036854775808` (`INT64_MIN`). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will automatically be stored as `number_unsigned_t` or `number_float_t`. -When the default type is used, the maximal unsigned integer number that can be stored is `#!c 18446744073709551615` (`UINT64_MAX`) and the minimal integer number that can be stored is `#!c 0`. Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as `number_integer_t` or `number_float_t`. +When the default type is used, the maximal unsigned integer number that can be stored is `#!c 18446744073709551615` (`UINT64_MAX`) and the minimal integer number that can be stored is `#!c 0`. Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will automatically be stored as `number_integer_t` or `number_float_t`. [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: diff --git a/docs/mkdocs/docs/features/types/number_handling.md b/docs/mkdocs/docs/features/types/number_handling.md index 3dcca76a4..87680ba06 100644 --- a/docs/mkdocs/docs/features/types/number_handling.md +++ b/docs/mkdocs/docs/features/types/number_handling.md @@ -54,13 +54,13 @@ On number interoperability, the following remarks are made: ## Library implementation -This section describes how the above number specification is implemented by this library. +This section describes how this library implements the above number specification. ### Number storage In the default [`json`](../../api/json.md) type, numbers are stored as `#!c std::uint64_t`, `#!c std::int64_t`, and -`#!c double`, respectively. Thereby, `#!c std::uint64_t` and `#!c std::int64_t` are used only if they can store the -number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as +`#!c double`, respectively. Thereby, `#!c std::uint64_t` and `#!c std::int64_t` are used only if they can store the +number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as `#!c double`. !!! info "Notes" @@ -116,7 +116,7 @@ That is, `-0` is stored as a signed integer, but the serialization does not repr - Integer numbers are serialized as is; that is, no scientific notation is used. - Floating-point numbers are serialized as specified by the `#!c %g` printf modifier with [`std::numeric_limits::max_digits10`](https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10) - significant digits. The rationale is to use the shortest representation while still allow round-tripping. + significant digits. The rationale is to use the shortest representation while still allowing round-tripping. !!! hint "Notes regarding precision of floating-point numbers" @@ -151,7 +151,7 @@ NaN (not-a-number) cannot be expressed with the number syntax described above an Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted. -That is, there is no way to *parse* a NaN value. However, NaN values can be stored in a JSON value by assignment. +That is, there is no way to *parse* a NaN value. However, assignments can store NaN values in a JSON value. This library serializes NaN values as `#!js null`. This corresponds to the behavior of JavaScript's [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp) function. @@ -230,7 +230,7 @@ Floating-point inside JSON values numbers are compared with `#!c json::number_fl ### Number conversion Just like the C++ language itself, the `get` family of functions allows conversions between unsigned and signed -integers, and between integers and floating-point values to integers. This behavior may be surprising. +integers, and between integers and floating-point values to integers. This behavior may be surprising. !!! warning "Unconditional number conversions" @@ -246,7 +246,7 @@ integers, and between integers and floating-point values to integers. This beha The rationale is twofold: 1. JSON does not define a number type or precision (see above). -2. C++ also allows to silently convert between number types. +2. C++ also allows silently converting between number types. !!! success "Conditional number conversion" diff --git a/docs/mkdocs/docs/home/architecture.md b/docs/mkdocs/docs/home/architecture.md new file mode 100644 index 000000000..aba2be580 --- /dev/null +++ b/docs/mkdocs/docs/home/architecture.md @@ -0,0 +1,124 @@ +# Architecture + +!!! info + + This page is still under construction. Its goal is to provide a high-level overview of the library's architecture. + This should help new contributors to get an idea of the used concepts and where to make changes. + +## Overview + +The main structure is class [nlohmann::basic_json](../api/basic_json/index.md). + +- public API +- container interface +- iterators + +## Template specializations + +- describe template parameters of `basic_json` +- [`json`](../api/json.md) +- [`ordered_json`](../api/ordered_json.md) via [`ordered_map`](../api/ordered_map.md) + +## Value storage + +Values are stored as a tagged union of [value_t](../api/basic_json/value_t.md) and json_value. + +```cpp +/// the type of the current element +value_t m_type = value_t::null; + +/// the value of the current element +json_value m_value = {}; +``` + +with + +```cpp +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +union json_value { + /// object (stored with pointer to save storage) + object_t *object; + /// array (stored with pointer to save storage) + array_t *array; + /// string (stored with pointer to save storage) + string_t *string; + /// binary (stored with pointer to save storage) + binary_t *binary; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; +}; +``` + +## Parsing inputs (deserialization) + +Input is read via **input adapters** that abstract a source with a common interface: + +```cpp +/// read a single character +std::char_traits::int_type get_character() noexcept; + +/// read multiple characters to a destination buffer and +/// returns the number of characters successfully read +template +std::size_t get_elements(T* dest, std::size_t count = 1); +``` + +List examples of input adapters. + +## SAX Interface + +TODO + +## Writing outputs (serialization) + +Output is written via **output adapters**: + +```cpp +template +void write_character(CharType c); + +template +void write_characters(const CharType* s, std::size_t length); +``` + +List examples of output adapters. + +## Value conversion + +```cpp +template +void to_json(basic_json& j, const T& t); + +template +void from_json(const basic_json& j, T& t); +``` + +## Additional features + +- JSON Pointers +- Binary formats +- Custom base class +- Conversion macros + +## Details namespace + +- C++ feature backports diff --git a/docs/mkdocs/docs/home/code_of_conduct.md b/docs/mkdocs/docs/home/code_of_conduct.md deleted file mode 100644 index 770b8173e..000000000 --- a/docs/mkdocs/docs/home/code_of_conduct.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mail@nlohmann.me. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/docs/mkdocs/docs/home/customers.md b/docs/mkdocs/docs/home/customers.md new file mode 100644 index 000000000..8e111652a --- /dev/null +++ b/docs/mkdocs/docs/home/customers.md @@ -0,0 +1,163 @@ +# Customers + +The library is used in multiple projects, applications, operating systems, etc. The list below is not exhaustive, but +the result of an internet search. If you know further customers of the library, [please let me know](mailto:mail@nlohmann.me). + +[![](../images/customers.png)](../images/customers.png) + +## Space Exploration + +- [**Peregrine Lunar Lander Flight 01**](https://en.wikipedia.org/wiki/Peregrine_Mission_One) - The library was used for payload management in the **Peregrine Moon Lander**, developed by **Astrobotic Technology** and launched as part of NASA's **Commercial Lunar Payload Services (CLPS)** program. After six days in orbit, the spacecraft was intentionally redirected into Earth's atmosphere, where it burned up over the Pacific Ocean on **January 18, 2024**. + +## Automotive + +- [**Alexa Auto SDK**](https://github.com/alexa/alexa-auto-sdk), a software development kit enabling the integration of Alexa into automotive systems +- [**Apollo**](https://github.com/ApolloAuto/apollo), a framework for building autonomous driving systems +- [**Automotive Grade Linux (AGL)**](https://download.automotivelinux.org/AGL/release/jellyfish/latest/qemux86-64/deploy/licenses/nlohmann-json/): a collaborative open-source platform for automotive software development +- [**Genesis Motor** (infotainment)](http://webmanual.genesis.com/ccIC/AVNT/JW/KOR/English/reference010.html), a luxury automotive brand +- [**Hyundai** (infotainment)](https://www.hyundai.com/wsvc/ww/download.file.do?id=/content/hyundai/ww/data/opensource/data/GN7-2022/licenseCode/info), a global automotive brand +- [**Kia** (infotainment)](http://webmanual.kia.com/PREM_GEN6/AVNT/RJPE/KOR/Korean/reference010.html), a global automotive brand +- [**Mercedes-Benz Operating System (MB.OS)**](https://group.mercedes-benz.com/careers/about-us/mercedes-benz-operating-system/), a core component of the vehicle software ecosystem from Mercedes-Benz +- [**Rivian** (infotainment)](https://assets.ctfassets.net/2md5qhoeajym/3cwyo4eoufk4yingUwusFt/ded2c47da620fdfc99c88c7156d2c1d8/In-Vehicle_OSS_Attribution_2024__11-24_.pdf), an electric vehicle manufacturer +- [**Suzuki** (infotainment)](https://www.globalsuzuki.com/motorcycle/ipc/oss/oss_48KA_00.pdf), a global automotive and motorcycle manufacturer + +## Gaming and Entertainment + +- [**Assassin's Creed: Mirage**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a stealth-action game set in the Middle East, focusing on the journey of a young assassin with classic parkour and stealth mechanics +- [**Chasm: The Rift**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a first-person shooter blending horror and adventure, where players navigate dark realms and battle monsters +- [**College Football 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a college football simulation game featuring gameplay that mimics real-life college teams and competitions +- [**Concepts**](https://concepts.app/en/licenses): a digital sketching app designed for creative professionals, offering flexible drawing tools for illustration, design, and brainstorming +- [**Depthkit**](https://www.depthkit.tv/third-party-licenses): a tool for creating and capturing volumetric video, enabling immersive 3D experiences and interactive content +- [**immersivetech**](https://immersitech.io/open-source-third-party-software/): a technology company focused on immersive experiences, providing tools and solutions for virtual and augmented reality applications +- [**LOOT**](https://loot.readthedocs.io/_/downloads/en/0.13.0/pdf/), a tool for optimizing the load order of game plugins, commonly used in The Elder Scrolls and Fallout series +- [**Madden NFL 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a sports simulation game capturing the excitement of American football with realistic gameplay and team management features +- [**Marne**](https://marne.io/licenses), an unofficial private server platform for hosting custom Battlefield 1 game experiences +- [**Minecraft**](https://www.minecraft.net/zh-hant/attribution), a popular sandbox video game +- [**NHL 22**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a hockey simulation game offering realistic gameplay, team management, and various modes to enhance the hockey experience +- [**Pixelpart**](https://pixelpart.net/documentation/book/third-party.html): a 2D animation and video compositing software that allows users to create animated graphics and visual effects with a focus on simplicity and ease of use +- [**Red Dead Redemption II**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): an open-world action-adventure game following an outlaw's story in the late 1800s, emphasizing deep storytelling and immersive gameplay +- [**Tactics Ogre: Reborn**](https://www.square-enix-games.com/en_US/documents/tactics-ogre-reborn-pc-installer-software-and-associated-plug-ins-disclosure), a tactical role-playing game featuring strategic battles and deep storytelling elements +- [**Throne and Liberty**](https://www.amazon.com/gp/help/customer/display.html?nodeId=T7fLNw5oAevCMtJFPj&pop-up=1), an MMORPG that offers an expansive fantasy world with dynamic gameplay and immersive storytelling +- [**Unity Vivox**](https://docs.unity3d.com/Packages/com.unity.services.vivox@15.1/license/Third%20Party%20Notices.html), a communication service that enables voice and text chat functionality in multiplayer games developed with Unity +- [**Zool: Redimensioned**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/): a modern reimagining of the classic platformer featuring fast-paced gameplay and vibrant environments + +## Consumer Electronics + +- [**Audinate**](https://www.audinate.com/legal/software-licensing/dante-av-h-open-source-licenses/): a provider of networked audio solutions specializing in Dante technology, which facilitates high-quality digital audio transport over IP networks +- [**Cisco Webex Desk Camera**](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf), a video camera designed for professional-quality video conferencing and remote collaboration +- [**Philips Hue Personal Wireless Lighting**](http://2ak5ape.257.cz/): a smart lighting system for customizable and wireless home illumination +- [**Ray-Ban Meta Smart glasses**](https://www.meta.com/de/en/legal/smart-glasses/third-party-notices-android/03/), a pair of smart glasses designed for capturing photos and videos with integrated connectivity and social features +- [**Siemens SINEMA Remote Connect**](https://cache.industry.siemens.com/dl/files/790/109793790/att_1054961/v2/OSS_SINEMA-RC_86.pdf), a remote connectivity solution for monitoring and managing industrial networks and devices securely +- [**Sony PlayStation 4**](https://doc.dl.playstation.net/doc/ps4-oss/index.html), a gaming console developed by Sony that offers a wide range of games and multimedia entertainment features +- [**Sony Virtual Webcam Driver for Remote Camera**](https://helpguide.sony.net/rc/vwd/v1/zh-cn/print.pdf), a software driver that enables the use of Sony cameras as virtual webcams for video conferencing and streaming + +## Operating Systems + +- [**Apple iOS and macOS**](https://www.apple.com/macos), a family of operating systems developed by Apple, including iOS for mobile devices and macOS for desktop computers +- [**Google Fuchsia**](https://fuchsia.googlesource.com/third_party/json/), an open-source operating system developed by Google, designed to be secure, updatable, and adaptable across various devices +- [**SerenityOS**](https://github.com/SerenityOS/serenity), an open-source operating system that aims to provide a simple and beautiful user experience with a focus on simplicity and elegance +- [**Yocto**](http://ftp.emacinc.com/openembedded-sw/kirkstone-icop-5.15-kirkstone-6.0/archive-2024-10/pn8m-090t-ppc/licenses/nlohmann-json/): a Linux-based build system for creating custom operating systems and software distributions, tailored for embedded devices and IoT applications + +## Development Tools and IDEs + +- [**Accentize SpectralBalance**](https://www.accentize.com/products/SpectralBalanceManual.pdf), an adaptive speech analysis tool designed to enhance audio quality by optimizing frequency balance in recordings +- [**Arm Compiler for Linux**](https://documentation-service.arm.com/static/66558e9d876c8d213b7843e4), a software development toolchain for compiling and optimizing applications on Arm-based Linux systems +- [**BBEdit**](https://s3.amazonaws.com/BBSW-download/BBEdit_15.1.2_User_Manual.pdf), a professional text and code editor for macOS +- [**CoderPad**](https://coderpad.io), a collaborative coding platform that enables real-time code interviews and assessments for developers; the library is included in every CoderPad instance and can be accessed with a simple `#include "json.hpp"` +- [**Compiler Explorer**](https://godbolt.org), a web-based tool that allows users to write, compile, and visualize the assembly output of code in various programming languages; the library is readily available and accessible with the directive `#include `. +- [**GitHub CodeQL**](https://github.com/github/codeql), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries +- [**Hex-Rays**](https://docs.hex-rays.com/user-guide/user-interface/licenses): a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis +- [**ImHex**](https://github.com/WerWolv/ImHex), a hex editor designed for reverse engineering, providing advanced features for data analysis and manipulation +- [**Intel GPA Framework**](https://intel.github.io/gpasdk-doc/src/licenses.html), a suite of cross-platform tools for capturing, analyzing, and optimizing graphics applications across different APIs +- [**Meta Yoga**](https://github.com/facebook/yoga), a layout engine that facilitates flexible and efficient user interface design across multiple platforms +- [**MKVToolNix**](https://mkvtoolnix.download/doc/README.md), a set of tools for creating, editing, and inspecting MKV (Matroska) multimedia container files +- [**NVIDIA Nsight Compute**](https://docs.nvidia.com/nsight-compute/2022.2/pdf/CopyrightAndLicenses.pdf), a performance analysis tool for CUDA applications that provides detailed insights into GPU performance metrics +- [**Notepad++**](https://github.com/notepad-plus-plus/notepad-plus-plus), a free source code editor that supports various programming languages +- [**OpenRGB**](https://gitlab.com/CalcProgrammer1/OpenRGB), an open source RGB lighting control that doesn't depend on manufacturer software +- [**OpenTelemetry C++**](https://github.com/open-telemetry/opentelemetry-cpp): a library for collecting and exporting observability data in C++, enabling developers to implement distributed tracing and metrics in their application +- [**Qt Creator**](https://doc.qt.io/qtcreator/qtcreator-attribution-json-nlohmann.html), an IDE for developing applications using the Qt application framework +- [**Scanbot SDK**](https://docs.scanbot.io/barcode-scanner-sdk/web/third-party-libraries/): a software development kit (SDK) that provides tools for integrating advanced document scanning and barcode scanning capabilities into applications + +## Machine Learning and AI + +- [**Apple Core ML Tools**](https://github.com/apple/coremltools), a set of tools for converting and configuring machine learning models for deployment in Apple's Core ML framework +- [**Avular Mobile Robotics**](https://www.avular.com/licenses/nlohmann-json-3.9.1.txt): a platform for developing and deploying mobile robotics solutions +- [**Google gemma.cpp**](https://github.com/google/gemma.cpp), a lightweight C++ inference engine designed for running AI models from the Gemma family +- [**llama.cpp**](https://github.com/ggerganov/llama.cpp), a C++ library designed for efficient inference of large language models (LLMs), enabling streamlined integration into applications +- [**MLX**](https://github.com/ml-explore/mlx), an array framework for machine learning on Apple Silicon +- [**Mozilla llamafile**](https://github.com/Mozilla-Ocho/llamafile), a tool designed for distributing and executing large language models (LLMs) efficiently using a single file format +- [**NVIDIA ACE**](https://docs.nvidia.com/ace/latest/index.html), a suite of real-time AI solutions designed for the development of interactive avatars and digital human applications, enabling scalable and sophisticated user interactions +- [**Peer**](https://support.peer.inc/hc/en-us/articles/17261335054235-Licenses): a platform offering personalized AI assistants for interactive learning and creative collaboration +- [**stable-diffusion.cpp**](https://github.com/leejet/stable-diffusion.cpp): a C++ implementation of the Stable Diffusion image generation model +- [**TanvasTouch**](https://tanvas.co/tanvastouch-sdk-third-party-acknowledgments): a software development kit (SDK) that enables developers to create tactile experiences on touchscreens, allowing users to feel textures and physical sensations in a digital environment +- [**TensorFlow**](https://github.com/tensorflow/tensorflow), a machine learning framework that facilitates the development and training of models, supporting data serialization and efficient data exchange between components + +## Scientific Research and Analysis + +- [**BLACK**](https://www.black-sat.org/en/stable/installation/linux.html), a bounded linear temporal logic (LTL) satisfiability checker +- [**CERN Atlas Athena**](https://gitlab.cern.ch/atlas/athena/-/blob/main/Control/PerformanceMonitoring/PerfMonComps/src/PerfMonMTSvc.h), a software framework used in the ATLAS experiment at the Large Hadron Collider (LHC) for performance monitoring +- [**KAMERA**](https://github.com/Kitware/kamera): a platform for synchronized data collection and real-time deep learning to map marine species like polar bears and seals, aiding Arctic ecosystem research +- [**KiCad**](https://gitlab.com/kicad/code/kicad/-/tree/master/thirdparty/nlohmann_json): a free and open-source software suite for electronic design automation +- [**MeVisLab**](https://mevislabdownloads.mevis.de/docs/current/MeVis/ThirdParty/Documentation/Publish/ThirdPartyReference/index.html): a software framework for medical image processing and visualization. +- [**OpenPMD API**](https://openpmd-api.readthedocs.io/en/0.8.0-alpha/backends/json.html): a versatile programming interface for accessing and managing scientific data, designed to facilitate the efficient storage, retrieval, and sharing of simulation data across various applications and platforms +- [**ParaView**](https://github.com/Kitware/ParaView): an open-source tool for large-scale data visualization and analysis across various scientific domains +- [**QGIS**](https://gitlab.b-data.ch/qgis/qgis/-/blob/backport-57658-to-release-3_34/external/nlohmann/json.hpp): a free and open-source geographic information system (GIS) application that allows users to create, edit, visualize, and analyze geospatial data across a variety of formats +- [**VTK**](https://github.com/Kitware/VTK): a software library for 3D computer graphics, image processing, and visualization +- [**VolView**](https://github.com/Kitware/VolView): a lightweight application for interactive visualization and analysis of 3D medical imaging data. + +## Business and Productivity Software + +- [**ArcGIS PRO**](https://www.esri.com/content/dam/esrisites/en-us/media/legal/open-source-acknowledgements/arcgis-pro-2-8-attribution-report.html), a desktop geographic information system (GIS) application developed by Esri for mapping and spatial analysis +- [**Autodesk Desktop**](https://damassets.autodesk.net/content/dam/autodesk/www/Company/legal-notices-trademarks/autodesk-desktop-platform-components/internal-autodesk-components-web-page-2023.pdf), a software platform developed by Autodesk for creating and managing desktop applications and services +- [**Check Point**](https://www.checkpoint.com/about-us/copyright-and-trademarks/): a cybersecurity company specializing in threat prevention and network security solutions, offering a range of products designed to protect enterprises from cyber threats and ensure data integrity +- [**Microsoft Office for Mac**](https://officecdnmac.microsoft.com/pr/legal/mac/OfficeforMacAttributions.html), a suite of productivity applications developed by Microsoft for macOS, including tools for word processing, spreadsheets, and presentations +- [**Microsoft Teams**](https://www.microsoft.com/microsoft-teams/), a team collaboration application offering workspace chat and video conferencing, file storage, and integration of proprietary and third-party applications and services +- [**Nexthink Infinity**](https://docs.nexthink.com/legal/services-terms/experience-open-source-software-licenses/infinity-2022.8-software-licenses): a digital employee experience management platform for monitoring and improving IT performance +- [**Sophos Connect Client**](https://docs.sophos.com/nsg/licenses/SophosConnect/SophosConnectAttribution.html): a secure VPN client from Sophos that allows remote users to connect to their corporate network, ensuring secure access to resources and data +- [**Stonebranch**](https://stonebranchdocs.atlassian.net/wiki/spaces/UA77/pages/799545647/Licenses+for+Third-Party+Libraries): a cloud-based cybersecurity solution that integrates backup, disaster recovery, and cybersecurity features to protect data and ensure business continuity for organizations +- [**Tablecruncher**](https://tablecruncher.com/): a data analysis tool that allows users to import, analyze, and visualize spreadsheet data, offering interactive features for better insights and decision-making +- [**magicplan**](https://help.magicplan.app/acknowledgments), a mobile application for creating floor plans and interior designs using augmented reality + +## Databases and Big Data + +- [**ADIOS2**](https://code.ornl.gov/ecpcitest/adios2/-/tree/pr4285_FFSUpstream/thirdparty/nlohmann_json?ref_type=heads): a data management framework designed for high-performance input and output operations +- [**Cribl Stream**](https://docs.cribl.io/stream/third-party-current-list/): a real-time data processing platform that enables organizations to collect, route, and transform observability data, enhancing visibility and insights into their systems +- [**DB Browser for SQLite**](https://github.com/sqlitebrowser/sqlitebrowser), a visual open-source tool for creating, designing, and editing SQLite database files +- [**MySQL Connector/C++**](https://docs.oracle.com/cd/E17952_01/connector-cpp-9.1-license-com-en/license-opentelemetry-cpp-com.html), a C++ library for connecting and interacting with MySQL databases +- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-9.0-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases +- [**PrestoDB**](https://github.com/prestodb/presto), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook +- [**ROOT Data Analysis Framework**](https://root.cern/doc/v614/classnlohmann_1_1basic__json.html), an open-source data analysis framework widely used in high-energy physics and other fields for data processing and visualization + +## Simulation and Modeling + +- [**Arcturus HoloSuite**](https://www.datocms-assets.com/104353/1698904597-holosuite-third-party-software-credits-and-attributions-2.pdf), a software toolset for capturing, editing, and streaming volumetric video, featuring advanced compression technologies for high-quality 3D content creation +- [**azul**](https://pure.tudelft.nl/ws/files/85338589/tgis.12673.pdf), a fast and efficient 3D city model viewer designed for visualizing urban environments and spatial data +- [**Blender**](https://projects.blender.org/blender/blender/search?q=nlohmann), a free and open-source 3D creation suite for modeling, animation, rendering, and more +- [**cpplot**](https://cpplot.readthedocs.io/en/latest/library_api/function_eigen_8h_1ac080eac0541014c5892a55e41bf785e6.html), a library for creating interactive graphs and charts in C++, which can be viewed in web browsers +- [**NVIDIA Omniverse**](https://docs.omniverse.nvidia.com/composer/latest/common/product-licenses/usd-explorer/usd-explorer-2023.2.0-licenses-manifest.html), a platform for 3D content creation and collaboration that enables real-time simulations and interactive experiences across various industries +- [**Pixar Renderman**](https://rmanwiki-26.pixar.com/space/REN26/19662083/Legal+Notice), a photorealistic 3D rendering software developed by Pixar, widely used in the film industry for creating high-quality visual effects and animations +- [**ROS - Robot Operating System**](http://docs.ros.org/en/noetic/api/behaviortree_cpp/html/json_8hpp_source.html), a set of software libraries and tools that assist in developing robot applications +- [**UBS**](https://www.ubs.com/), a multinational financial services and banking company +- [**GAMS**](https://www.gams.com/47/docs/THIRDPARTY.html): a high-performance mathematical modeling system for optimization and decision support +- [**M-Star**](https://docs.mstarcfd.com/3_Licensing/thirdparty-licenses.html): a computational fluid dynamics software for simulating and analyzing fluid flow +- [**MapleSim CAD Toolbox**](https://www.maplesoft.com/support/help/MapleSim/view.aspx?path=CADToolbox/copyright): a software extension for MapleSim that integrates CAD models, allowing users to import, manipulate, and analyze 3D CAD data within the MapleSim environment for enhanced modeling and simulation +- [**Kitware SMTK**](https://github.com/Kitware/SMTK): a software toolkit for managing simulation models and workflows in scientific and engineering applications + +## Enterprise and Cloud Applications + +- [**Acronis Cyber Protect Cloud**](https://care.acronis.com/s/article/59533-Third-party-software-used-in-Acronis-Cyber-Protect-Cloud?language=en_US): an all-in-one data protection solution that combines backup, disaster recovery, and cybersecurity to safeguard business data from threats like ransomware +- [**Baereos**](https://gitlab.tiger-computing.co.uk/packages/bareos/-/blob/tiger/bullseye/third-party/CLI11/examples/json.cpp): a backup solution that provides data protection and recovery options for various environments, including physical and virtual systems +- [**Bitdefender Home Scanner**](https://www.bitdefender.de/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers +- [**Citrix Provisioning**](https://docs.citrix.com/en-us/provisioning/2203-ltsr/downloads/pvs-third-party-notices-2203.pdf): a solution that streamlines the delivery of virtual desktops and applications by allowing administrators to manage and provision resources efficiently across multiple environments +- [**Citrix Virtual Apps and Desktops**](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/2305/downloads/third-party-notices-apps-and-desktops.pdf), a solution from Citrix that delivers virtual apps and desktops +- [**Cyberarc**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf): a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture +- [**Elster**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use): a digital platform developed by German tax authorities for secure and efficient electronic tax filing and management using secunet protect4use +- [**Egnyte Desktop**](https://helpdesk.egnyte.com/hc/en-us/articles/360007071732-Third-Party-Software-Acknowledgements): a secure cloud storage solution designed for businesses, enabling file sharing, collaboration, and data management across teams while ensuring compliance and data protection +- [**Ethereum Solidity**](https://github.com/ethereum/solidity), a high-level, object-oriented programming language designed for implementing smart contracts on the Ethereum platform +- [**Inciga**](https://fossies.org/linux/icinga2/third-party/nlohmann_json/json.hpp): a monitoring tool for IT infrastructure, designed to provide insights into system performance and availability through customizable dashboards and alerts +- [**Intel Accelerator Management Daemon for VMware ESXi**](https://downloadmirror.intel.com/772507/THIRD-PARTY.txt): a management tool designed for monitoring and controlling Intel hardware accelerators within VMware ESXi environments, optimizing performance and resource allocation +- [**Juniper Identity Management Service**](https://www.juniper.net/documentation/us/en/software/jims/jims-guide/jims-guide.pdf) +- [**Microsoft Azure IoT SDK**](https://library.e.abb.com/public/2779c5f85f30484192eb3cb3f666a201/IP%20Gateway%20Open%20License%20Declaration_9AKK108467A4095_Rev_C.pdf), a collection of tools and libraries to help developers connect, build, and deploy Internet of Things (IoT) solutions on the Azure cloud platform +- [**Microsoft WinGet**](https://github.com/microsoft/winget-cli), a command-line utility included in the Windows Package Manager +- [**Pointr**](https://docs-dev.pointr.tech/docs/8.x/Developer%20Portal/Open%20Source%20Licenses/): a platform for indoor positioning and navigation solutions, offering tools and SDKs for developers to create location-based applications +- [**secunet protect4use**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use): a secure, passwordless multifactor authentication solution that transforms smartphones into digital keyrings, ensuring high security for online services and digital identities diff --git a/docs/mkdocs/docs/home/design_goals.md b/docs/mkdocs/docs/home/design_goals.md index b80551fe9..0a0f77029 100644 --- a/docs/mkdocs/docs/home/design_goals.md +++ b/docs/mkdocs/docs/home/design_goals.md @@ -2,11 +2,11 @@ There are myriads of [JSON](https://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: -- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples), and you'll know what I mean. +- **Intuitive syntax**. In languages such as Python, JSON feels like a first-class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). +- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). Other aspects were not so important to us: diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index a0fee9e33..ea43e5975 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -6,24 +6,33 @@ All exceptions inherit from class `json::exception` (which in turn inherits from `std::exception`). It is used as the base class for all exceptions thrown by the `basic_json` class. This class can hence be used as "wildcard" to catch exceptions. -```plantuml -std::exception <|-- json::exception -json::exception <|-- json::parse_error -json::exception <|-- json::invalid_iterator -json::exception <|-- json::type_error -json::exception <|-- json::out_of_range -json::exception <|-- json::other_error +``` mermaid +classDiagram + direction LR + class `std::exception` { + <> + } -interface std::exception {} + class `json::exception` { + +const int id + +const char* what() const + } -class json::exception { - + const int id - + const char* what() const -} + class `json::parse_error` { + +const std::size_t byte + } -class json::parse_error { - + const std::size_t byte -} + class `json::invalid_iterator` + class `json::type_error` + class `json::out_of_range` + class `json::other_error` + + `std::exception` <|-- `json::exception` + `json::exception` <|-- `json::parse_error` + `json::exception` <|-- `json::invalid_iterator` + `json::exception` <|-- `json::type_error` + `json::exception` <|-- `json::out_of_range` + `json::exception` <|-- `json::other_error` ``` ### Switch off exceptions @@ -72,7 +81,7 @@ Exceptions in the library are thrown in the local context of the JSON value they This exception can be hard to debug if storing the value `#!c "12"` and accessing it is further apart. -To create better diagnostics messages, each JSON value needs a pointer to its parent value such that a global context (i.e., a path from the root value to the value that lead to the exception) can be created. That global context is provided as [JSON Pointer](../features/json_pointer.md). +To create better diagnostics messages, each JSON value needs a pointer to its parent value such that a global context (i.e., a path from the root value to the value that led to the exception) can be created. That global context is provided as [JSON Pointer](../features/json_pointer.md). As this global context comes at the price of storing one additional pointer per JSON value and runtime overhead to maintain the parent relation, extended diagnostics are disabled by default. They can, however, be enabled by defining the preprocessor symbol [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) to `1` before including `json.hpp`. @@ -94,7 +103,7 @@ See [documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) for ## Parse errors -This exception is thrown by the library when a parse error occurs. Parse errors +The library throws this exception when a parse error occurs. Parse errors can occur during the deserialization of JSON text, CBOR, MessagePack, as well as when using JSON Patch. @@ -471,7 +480,7 @@ The offset operators (`+`, `-`, `+=`, `-=`) cannot be used on iterators belongin ### json.exception.invalid_iterator.210 -The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (`first`, `last`) is invalid. +The iterator range passed to the insert function is not compatible, meaning they do not belong to the same container. Therefore, the range (`first`, `last`) is invalid. !!! failure "Example message" @@ -551,7 +560,7 @@ To create an object from an initializer list, the initializer list must consist ### json.exception.type_error.302 -During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +During implicit or explicit value conversion, the JSON type must be compatible with the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. !!! failure "Example messages" @@ -731,7 +740,7 @@ The `dump()` function only works with UTF-8 encoded strings; that is, if you ass ### json.exception.type_error.317 -The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) +The dynamic type of the object cannot be represented in the requested serialization format (e.g., a raw `true` or `null` JSON object cannot be serialized to BSON) !!! failure "Example messages" @@ -750,7 +759,7 @@ The dynamic type of the object cannot be represented in the requested serializat ## Out of range -This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance in case of array indices or nonexisting object keys. +This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance, in the case of array indices or nonexisting object keys. Exceptions have ids 4xx. @@ -810,7 +819,7 @@ A reference token in a JSON Pointer could not be resolved. ### json.exception.out_of_range.405 -The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +The JSON Patch operations 'remove' and 'add' cannot be applied to the root element of the JSON value. !!! failure "Example message" @@ -830,17 +839,14 @@ A parsed number could not be stored as without changing it to NaN or INF. ### json.exception.out_of_range.407 -UBJSON and BSON only support integer numbers up to 9223372036854775807. +This exception previously indicated that the UBJSON and BSON binary formats did not support integer numbers greater than +9223372036854775807 due to limitations in the implemented mapping. However, these limitations have since been resolved, +and this exception no longer occurs. -!!! failure "Example message" +!!! success "Exception cannot occur any more" - ``` - number overflow serializing '9223372036854775808' - ``` - -!!! note - - Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers, and this exception does not further occur. + - Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers. + - Since version 3.12.0, integer numbers beyond int64 are serialized as uint64 BSON numbers. ### json.exception.out_of_range.408 diff --git a/docs/mkdocs/docs/home/faq.md b/docs/mkdocs/docs/home/faq.md index dd426e073..6a5ca3960 100644 --- a/docs/mkdocs/docs/home/faq.md +++ b/docs/mkdocs/docs/home/faq.md @@ -46,7 +46,7 @@ for objects. Can you add an option to ignore trailing commas? -This library does not support any feature which would jeopardize interoperability. +This library does not support any feature that would jeopardize interoperability. ### Parse errors reading non-ASCII characters @@ -59,10 +59,10 @@ This library does not support any feature which would jeopardize interoperabilit The library supports **Unicode input** as follows: -- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1). +- Only **UTF-8** encoded input is supported, which is the default encoding for JSON, according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1). - `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers. - Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors. -- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. +- The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1). - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. - When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. @@ -177,4 +177,4 @@ The code compiles successfully with [Android NDK](https://developer.android.com/ - Why do I get a compilation error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`)? - Why does the code not compile with MinGW or Android SDK? -This is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). +This is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). diff --git a/docs/mkdocs/docs/home/license.md b/docs/mkdocs/docs/home/license.md index baef2f51b..b9a0c4f45 100644 --- a/docs/mkdocs/docs/home/license.md +++ b/docs/mkdocs/docs/home/license.md @@ -1,10 +1,10 @@ # License - + The class is licensed under the [MIT License](https://opensource.org/licenses/MIT): -Copyright © 2013-2022 [Niels Lohmann](https://nlohmann.me) +Copyright © 2013-2025 [Niels Lohmann](https://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/docs/mkdocs/docs/home/releases.md b/docs/mkdocs/docs/home/releases.md index 5237c4259..af4f3e615 100644 --- a/docs/mkdocs/docs/home/releases.md +++ b/docs/mkdocs/docs/home/releases.md @@ -596,7 +596,7 @@ This release adds support for the [**UBJSON**](http://ubjson.org) format and [** ### :sparkles: New features -- The library now supports [**UBJSON**](http://ubjson.org) (Universal Binary JSON Specification) as binary format to read and write JSON values space-efficiently. See the [documentation overview](https://github.com/nlohmann/json/blob/develop/doc/binary_formats.md) for a comparison of the different formats CBOR, MessagePack, and UBJSON. +- The library now supports [**UBJSON**](http://ubjson.org) (Universal Binary JSON Specification) as binary format to read and write JSON values space-efficiently. See the [documentation overview](https://json.nlohmann.me/features/binary_formats/) for a comparison of the different formats CBOR, MessagePack, and UBJSON. - [**JSON Merge Patch**](https://tools.ietf.org/html/rfc7386) (RFC 7386) offers an intuitive means to describe patches between JSON values (#876, #877). See the documentation of [`merge_patch`](http://nlohmann.github.io/json/doxygen/classnlohmann_1_1basic__json_a0ec0cd19cce42ae6071f3cc6870ea295.html#a0ec0cd19cce42ae6071f3cc6870ea295) for more information. ### :zap: Improvements @@ -688,7 +688,7 @@ This section describes changes that change the public API of the library and may - The library now uses [**user-defined exceptions**](http://nlohmann.github.io/json/doxygen/classnlohmann_1_1basic__json_a9a0aced019cb1d65bb49703406c84970.html#a9a0aced019cb1d65bb49703406c84970) instead of re-using those defined in `` (#244). This not only allows to add more information to the exceptions (every exception now has an identifier, and parse errors contain the position of the error), but also to easily catch all library exceptions with a single `catch(json::exception)`. - When strings with a different encoding as UTF-8 were stored in JSON values, their serialization could not be parsed by the library itself, as only UTF-8 is supported. To enforce this library limitation and improve consistency, **non-UTF-8 encoded strings now yield a `json::type_error` exception during serialization** (#838). The check for valid UTF-8 is realized with code from [Björn Hoehrmann](http://bjoern.hoehrmann.de/). - **NaN and infinity values can now be stored inside the JSON value** without throwing an exception. They are, however, still serialized as `null` (#388). -- The library's iterator tag was changed from RandomAccessIterator to **[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator)** (#593). Supporting RandomAccessIterator was incorrect as it assumed an ordering of values in a JSON objects which are unordered by definition. +- The library's iterator tag was changed from RandomAccessIterator to **[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator)** (#593). Supporting RandomAccessIterator was incorrect as it assumed an ordering of values in a JSON objects which are unordered by definition. - The library does not include the standard headers ``, ``, and `` any more. You may need to add these headers to code relying on them. - Removed constructor `explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)` which was deprecated in version 2.0.0 (#480). @@ -744,54 +744,54 @@ There are five different exceptions inheriting from [`json::exception`](http://n To support these exception, the `try`/`catch` blocks of your code need to be adjusted: -| new exception | previous exception | -|:--|:--| -| parse_error.101 | invalid_argument | -| parse_error.102 | invalid_argument | -| parse_error.103 | invalid_argument | -| parse_error.104 | invalid_argument | -| parse_error.105 | invalid_argument | -| parse_error.106 | domain_error | -| parse_error.107 | domain_error | -| parse_error.108 | domain_error | -| parse_error.109 | invalid_argument | -| parse_error.110 | out_of_range | -| parse_error.111 | invalid_argument | -| parse_error.112 | invalid_argument | -| invalid_iterator.201 | domain_error | -| invalid_iterator.202 | domain_error | -| invalid_iterator.203 | domain_error | -| invalid_iterator.204 | out_of_range | -| invalid_iterator.205 | out_of_range | -| invalid_iterator.206 | domain_error | -| invalid_iterator.207 | domain_error | -| invalid_iterator.208 | domain_error | -| invalid_iterator.209 | domain_error | -| invalid_iterator.210 | domain_error | -| invalid_iterator.211 | domain_error | -| invalid_iterator.212 | domain_error | -| invalid_iterator.213 | domain_error | -| invalid_iterator.214 | out_of_range | -| type_error.301 | domain_error | -| type_error.302 | domain_error | -| type_error.303 | domain_error | -| type_error.304 | domain_error | -| type_error.305 | domain_error | -| type_error.306 | domain_error | -| type_error.307 | domain_error | -| type_error.308 | domain_error | -| type_error.309 | domain_error | -| type_error.310 | domain_error | -| type_error.311 | domain_error | -| type_error.313 | domain_error | -| type_error.314 | domain_error | -| type_error.315 | domain_error | -| out_of_range.401 | out_of_range | -| out_of_range.402 | out_of_range | -| out_of_range.403 | out_of_range | -| out_of_range.404 | out_of_range | -| out_of_range.405 | domain_error | -| other_error.501 | domain_error | +| new exception | previous exception | +|:---------------------|:-------------------| +| parse_error.101 | invalid_argument | +| parse_error.102 | invalid_argument | +| parse_error.103 | invalid_argument | +| parse_error.104 | invalid_argument | +| parse_error.105 | invalid_argument | +| parse_error.106 | domain_error | +| parse_error.107 | domain_error | +| parse_error.108 | domain_error | +| parse_error.109 | invalid_argument | +| parse_error.110 | out_of_range | +| parse_error.111 | invalid_argument | +| parse_error.112 | invalid_argument | +| invalid_iterator.201 | domain_error | +| invalid_iterator.202 | domain_error | +| invalid_iterator.203 | domain_error | +| invalid_iterator.204 | out_of_range | +| invalid_iterator.205 | out_of_range | +| invalid_iterator.206 | domain_error | +| invalid_iterator.207 | domain_error | +| invalid_iterator.208 | domain_error | +| invalid_iterator.209 | domain_error | +| invalid_iterator.210 | domain_error | +| invalid_iterator.211 | domain_error | +| invalid_iterator.212 | domain_error | +| invalid_iterator.213 | domain_error | +| invalid_iterator.214 | out_of_range | +| type_error.301 | domain_error | +| type_error.302 | domain_error | +| type_error.303 | domain_error | +| type_error.304 | domain_error | +| type_error.305 | domain_error | +| type_error.306 | domain_error | +| type_error.307 | domain_error | +| type_error.308 | domain_error | +| type_error.309 | domain_error | +| type_error.310 | domain_error | +| type_error.311 | domain_error | +| type_error.313 | domain_error | +| type_error.314 | domain_error | +| type_error.315 | domain_error | +| out_of_range.401 | out_of_range | +| out_of_range.402 | out_of_range | +| out_of_range.403 | out_of_range | +| out_of_range.404 | out_of_range | +| out_of_range.405 | domain_error | +| other_error.501 | domain_error | #### Handling of NaN and INF @@ -939,8 +939,8 @@ This release implements with **[CBOR](http://cbor.io)** and **[MessagePack](http - :bug: fixed an overflow detection error in the number parser - :memo: updated [contribution guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md) to a list of frequentely asked features that will most likely be never added to the library - :memo: added a **table of contents** to the [README file](https://github.com/nlohmann/json/blob/develop/README.md) to add some structure -- :memo: mentioned the many [examples](https://github.com/nlohmann/json/tree/develop/doc/examples) and the [documentation](https://nlohmann.github.io/json/) in the [README file]() -- :hammer: split [unit tests](https://github.com/nlohmann/json/tree/develop/test/src) into individual independent binaries to speed up compilation and testing +- :memo: mentioned the many [examples](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples) and the [documentation](https://nlohmann.github.io/json/) in the [README file]() +- :hammer: split [unit tests](https://github.com/nlohmann/json/tree/develop/tests/src) into individual independent binaries to speed up compilation and testing - :white_check_mark: the test suite now contains **11201886** tests ## v2.0.8 @@ -982,10 +982,10 @@ This release combines a lot of small fixes and improvements. The fixes are backw ### Summary -This release fixes a few bugs in the JSON parser found in the [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.html) article. The fixes are backwards compatible. +This release fixes a few bugs in the JSON parser found in the [Parsing JSON is a Minefield 💣](https://seriot.ch/projects/parsing_json.html) article. The fixes are backwards compatible. ### Changes -- The article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.html) discusses a lot of pitfalls of the JSON specification. When investigating the published test cases, a few bugs in the library were found and fixed: +- The article [Parsing JSON is a Minefield 💣](https://seriot.ch/projects/parsing_json.html) discusses a lot of pitfalls of the JSON specification. When investigating the published test cases, a few bugs in the library were found and fixed: - Files with less than 5 bytes can now be parsed without error. - The library now properly rejects any file encoding other than UTF-8. Furthermore, incorrect surrogate pairs are properly detected and rejected. - The library now accepts all but one "yes" test (y_string_utf16.json): UTF-16 is not supported. diff --git a/docs/mkdocs/docs/home/sponsors.md b/docs/mkdocs/docs/home/sponsors.md index 9097049d4..7e3ef0284 100644 --- a/docs/mkdocs/docs/home/sponsors.md +++ b/docs/mkdocs/docs/home/sponsors.md @@ -2,6 +2,11 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). +## Priority Sponsor + +- [Martti Laine](https://github.com/codeclown) +- [Paul Harrington](https://github.com/phrrngtn) + ## Named Sponsors - [Michael Hartmann](https://github.com/reFX-Mike) @@ -9,5 +14,6 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl - [Steve Sperandeo](https://github.com/homer6) - [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe) - [Steve Wagner](https://github.com/ciroque) +- [Lion Yang](https://github.com/LionNatsu) Thanks everyone! diff --git a/docs/mkdocs/docs/images/customers.png b/docs/mkdocs/docs/images/customers.png new file mode 100644 index 000000000..acba03498 Binary files /dev/null and b/docs/mkdocs/docs/images/customers.png differ diff --git a/docs/mkdocs/docs/images/json.gif b/docs/mkdocs/docs/images/json.gif new file mode 100644 index 000000000..8b86b0375 Binary files /dev/null and b/docs/mkdocs/docs/images/json.gif differ diff --git a/docs/mkdocs/docs/images/package_managers/CPM.png b/docs/mkdocs/docs/images/package_managers/CPM.png new file mode 100644 index 000000000..4197541a1 Binary files /dev/null and b/docs/mkdocs/docs/images/package_managers/CPM.png differ diff --git a/docs/mkdocs/docs/images/package_managers/bazel.svg b/docs/mkdocs/docs/images/package_managers/bazel.svg new file mode 100644 index 000000000..ed5910e13 --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/bazel.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/docs/mkdocs/docs/images/package_managers/conan.svg b/docs/mkdocs/docs/images/package_managers/conan.svg new file mode 100644 index 000000000..15bcbdc92 --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/conan.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/mkdocs/docs/images/package_managers/conda.svg b/docs/mkdocs/docs/images/package_managers/conda.svg new file mode 100644 index 000000000..3ad2de74d --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/conda.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/mkdocs/docs/images/package_managers/homebrew.svg b/docs/mkdocs/docs/images/package_managers/homebrew.svg new file mode 100644 index 000000000..9d206f7c4 --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/homebrew.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mkdocs/docs/images/package_managers/macports.svg b/docs/mkdocs/docs/images/package_managers/macports.svg new file mode 100644 index 000000000..b09bff255 --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/macports.svg @@ -0,0 +1,81 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/docs/mkdocs/docs/images/package_managers/meson.svg b/docs/mkdocs/docs/images/package_managers/meson.svg new file mode 100644 index 000000000..a4136a1cf --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/meson.svg @@ -0,0 +1,2 @@ + +file_type_meson \ No newline at end of file diff --git a/docs/mkdocs/docs/images/package_managers/nuget.svg b/docs/mkdocs/docs/images/package_managers/nuget.svg new file mode 100644 index 000000000..1765dcc92 --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/nuget.svg @@ -0,0 +1,21 @@ + + + + nuget + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/docs/mkdocs/docs/images/package_managers/spack.svg b/docs/mkdocs/docs/images/package_managers/spack.svg new file mode 100644 index 000000000..a56eed57a --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/spack.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mkdocs/docs/images/package_managers/swift.svg b/docs/mkdocs/docs/images/package_managers/swift.svg new file mode 100644 index 000000000..5fe20abea --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/swift.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/mkdocs/docs/images/package_managers/vcpkg.png b/docs/mkdocs/docs/images/package_managers/vcpkg.png new file mode 100644 index 000000000..76d43a83d Binary files /dev/null and b/docs/mkdocs/docs/images/package_managers/vcpkg.png differ diff --git a/docs/mkdocs/docs/images/package_managers/xmake.svg b/docs/mkdocs/docs/images/package_managers/xmake.svg new file mode 100644 index 000000000..6bce7552c --- /dev/null +++ b/docs/mkdocs/docs/images/package_managers/xmake.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mkdocs/docs/integration/bazel/BUILD b/docs/mkdocs/docs/integration/bazel/BUILD new file mode 100644 index 000000000..ec223f14d --- /dev/null +++ b/docs/mkdocs/docs/integration/bazel/BUILD @@ -0,0 +1,5 @@ +cc_binary( + name = "main", + srcs = ["example.cpp"], + deps = ["@nlohmann_json//:json"], +) diff --git a/docs/mkdocs/docs/integration/bazel/MODULE.bazel b/docs/mkdocs/docs/integration/bazel/MODULE.bazel new file mode 100644 index 000000000..ba902be27 --- /dev/null +++ b/docs/mkdocs/docs/integration/bazel/MODULE.bazel @@ -0,0 +1 @@ +bazel_dep(name = "nlohmann_json", version = "3.11.3.bcr.1") diff --git a/docs/mkdocs/docs/integration/bazel/example.cpp b/docs/mkdocs/docs/integration/bazel/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/bazel/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/cget/CMakeLists.txt b/docs/mkdocs/docs/integration/cget/CMakeLists.txt new file mode 100644 index 000000000..e3fda5b9a --- /dev/null +++ b/docs/mkdocs/docs/integration/cget/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(json_example) + +find_package(nlohmann_json REQUIRED) + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/cget/example.cpp b/docs/mkdocs/docs/integration/cget/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/cget/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/cmake.md b/docs/mkdocs/docs/integration/cmake.md index 545f53f30..b89e4dbd3 100644 --- a/docs/mkdocs/docs/integration/cmake.md +++ b/docs/mkdocs/docs/integration/cmake.md @@ -15,10 +15,10 @@ and use the namespaced imported target from the generated package configuration: !!! example ```cmake title="CMakeLists.txt" - cmake_minimum_required(VERSION 3.1) + cmake_minimum_required(VERSION 3.5) project(ExampleProject LANGUAGES CXX) - find_package(nlohmann_json 3.11.3 REQUIRED) + find_package(nlohmann_json 3.12.0 REQUIRED) add_executable(example example.cpp) target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) @@ -35,7 +35,7 @@ To embed the library directly into an existing CMake project, place the entire s !!! example ```cmake title="CMakeLists.txt" - cmake_minimum_required(VERSION 3.1) + cmake_minimum_required(VERSION 3.5) project(ExampleProject LANGUAGES CXX) # If you only include this third party in PRIVATE source files, you do not need to install it @@ -77,7 +77,7 @@ to the following. ```cmake title="thirdparty/CMakeLists.txt" if(EXAMPLE_USE_EXTERNAL_JSON) - find_package(nlohmann_json 3.11.3 REQUIRED) + find_package(nlohmann_json 3.12.0 REQUIRED) else() set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(nlohmann_json) @@ -90,7 +90,7 @@ to the following. ### FetchContent Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can be used to -automatically download a release as a dependency at configure type. +automatically download a release as a dependency at configure time. !!! example @@ -100,7 +100,7 @@ automatically download a release as a dependency at configure type. include(FetchContent) - FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) + FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz) FetchContent_MakeAvailable(json) add_executable(example example.cpp) @@ -115,13 +115,11 @@ automatically download a release as a dependency at configure type. ```cmake FetchContent_Declare(json GIT_REPOSITORY https://github.com/nlohmann/json - GIT_TAG v3.11.3 + GIT_TAG v3.12.0 ) ``` - However, the repository download size is quite large. You might want to depend on - a smaller repository. For instance, you might want to replace the URL in the example by - . + However, the repository download size is quite large. ## CMake Options @@ -137,6 +135,10 @@ Enable CI build targets. The exact targets are used during the several CI steps Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default. +### `JSON_Diagnostic_Positions` + +Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is `OFF` by default. + ### `JSON_DisableEnumSerialization` Disable default `enum` serialization by defining the macro @@ -159,14 +161,18 @@ Enable implicit conversions by defining macro [`JSON_USE_IMPLICIT_CONVERSIONS`]( Install CMake targets during install step. This option is `ON` by default if the library's CMake project is the top project. +### `JSON_LegacyDiscardedValueComparison` + +Enable the (incorrect) legacy comparison behavior of discarded JSON values by defining macro [`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md). This option is `OFF` by default. + ### `JSON_MultipleHeaders` -Use non-amalgamated version of the library. This option is `OFF` by default. +Use the non-amalgamated version of the library. This option is `OFF` by default. ### `JSON_SystemInclude` -Treat the library headers like system headers (i.e., adding `SYSTEM` to the [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) call) to checks for this library by tools like Clang-Tidy. This option is `OFF` by default. +Treat the library headers like system headers (i.e., adding `SYSTEM` to the [`target_include_directories`](https://cmake.org/cmake/help/latest/command/target_include_directories.html) call) to check for this library by tools like Clang-Tidy. This option is `OFF` by default. ### `JSON_Valgrind` -Execute test suite with [Valgrind](https://valgrind.org). This option is `OFF` by default. Depends on `JSON_BuildTests`. +Execute the test suite with [Valgrind](https://valgrind.org). This option is `OFF` by default. Depends on `JSON_BuildTests`. diff --git a/docs/mkdocs/docs/integration/conan/CMakeLists.txt b/docs/mkdocs/docs/integration/conan/CMakeLists.txt index fd3e9ca71..e3fda5b9a 100644 --- a/docs/mkdocs/docs/integration/conan/CMakeLists.txt +++ b/docs/mkdocs/docs/integration/conan/CMakeLists.txt @@ -1,9 +1,7 @@ +cmake_minimum_required(VERSION 3.15) project(json_example) -cmake_minimum_required(VERSION 2.8.12) -add_definitions("-std=c++11") -include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup() +find_package(nlohmann_json REQUIRED) add_executable(json_example example.cpp) -target_link_libraries(json_example ${CONAN_LIBS}) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/conan/Conanfile.txt b/docs/mkdocs/docs/integration/conan/Conanfile.txt index a8a3e7037..d8a6295bb 100644 --- a/docs/mkdocs/docs/integration/conan/Conanfile.txt +++ b/docs/mkdocs/docs/integration/conan/Conanfile.txt @@ -1,5 +1,6 @@ [requires] -nlohmann_json/3.7.3 +nlohmann_json/3.12.0 [generators] -cmake +CMakeToolchain +CMakeDeps diff --git a/docs/mkdocs/docs/integration/conan/example.cpp b/docs/mkdocs/docs/integration/conan/example.cpp index e5a31be4b..1a7ac4de2 100644 --- a/docs/mkdocs/docs/integration/conan/example.cpp +++ b/docs/mkdocs/docs/integration/conan/example.cpp @@ -1,9 +1,10 @@ #include #include +#include using json = nlohmann::json; int main() { - std::cout << json::meta() << std::endl; + std::cout << std::setw(4) << json::meta() << std::endl; } diff --git a/docs/mkdocs/docs/integration/conda/example.cpp b/docs/mkdocs/docs/integration/conda/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/conda/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/cpm/CMakeLists.txt b/docs/mkdocs/docs/integration/cpm/CMakeLists.txt new file mode 100644 index 000000000..69e36b782 --- /dev/null +++ b/docs/mkdocs/docs/integration/cpm/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) +project(json_example) + +include(${CMAKE_SOURCE_DIR}/cmake/CPM.cmake) + +CPMAddPackage("gh:nlohmann/json@3.12.0") + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/cpm/example.cpp b/docs/mkdocs/docs/integration/cpm/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/cpm/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/homebrew/CMakeLists.txt b/docs/mkdocs/docs/integration/homebrew/CMakeLists.txt new file mode 100644 index 000000000..12f4ae1f2 --- /dev/null +++ b/docs/mkdocs/docs/integration/homebrew/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(json_example) + +find_package(nlohmann_json CONFIG REQUIRED) + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/homebrew/example.cpp b/docs/mkdocs/docs/integration/homebrew/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/homebrew/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/hunter/CMakeLists.txt b/docs/mkdocs/docs/integration/hunter/CMakeLists.txt new file mode 100644 index 000000000..4acc32586 --- /dev/null +++ b/docs/mkdocs/docs/integration/hunter/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.15) + +include("cmake/HunterGate.cmake") +HunterGate( + URL "https://github.com/cpp-pm/hunter/archive/v0.23.297.tar.gz" + SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3" +) + +project(json_example) + +hunter_add_package(nlohmann_json) +find_package(nlohmann_json CONFIG REQUIRED) + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/hunter/example.cpp b/docs/mkdocs/docs/integration/hunter/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/hunter/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/macports/CMakeLists.txt b/docs/mkdocs/docs/integration/macports/CMakeLists.txt new file mode 100644 index 000000000..12f4ae1f2 --- /dev/null +++ b/docs/mkdocs/docs/integration/macports/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(json_example) + +find_package(nlohmann_json CONFIG REQUIRED) + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/macports/example.cpp b/docs/mkdocs/docs/integration/macports/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/macports/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/meson/example.cpp b/docs/mkdocs/docs/integration/meson/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/meson/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/meson/meson.build b/docs/mkdocs/docs/integration/meson/meson.build new file mode 100644 index 000000000..ec6d2343b --- /dev/null +++ b/docs/mkdocs/docs/integration/meson/meson.build @@ -0,0 +1,12 @@ +project('json_example', 'cpp', + version: '1.0', + default_options: ['cpp_std=c++11'] +) + +dependency_json = dependency('nlohmann_json', required: true) + +executable('json_example', + sources: ['example.cpp'], + dependencies: [dependency_json], + install: true +) diff --git a/docs/mkdocs/docs/integration/migration_guide.md b/docs/mkdocs/docs/integration/migration_guide.md index d250f5b20..423b746d2 100644 --- a/docs/mkdocs/docs/integration/migration_guide.md +++ b/docs/mkdocs/docs/integration/migration_guide.md @@ -260,5 +260,5 @@ exact version and configuration is relevant, use macro ## Do not use the `details` namespace -The `details` namespace is not part of the public API of the library and can change in any version without announcement. -Do not rely on any function or type in the `details` namespace. +The `details` namespace is not part of the public API of the library and can change in any version without an +announcement. Do not rely on any function or type in the `details` namespace. diff --git a/docs/mkdocs/docs/integration/nuget/nuget-package-content.png b/docs/mkdocs/docs/integration/nuget/nuget-package-content.png new file mode 100644 index 000000000..cc975b98b Binary files /dev/null and b/docs/mkdocs/docs/integration/nuget/nuget-package-content.png differ diff --git a/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png b/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png new file mode 100644 index 000000000..eb2a520a8 Binary files /dev/null and b/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png differ diff --git a/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png b/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png new file mode 100644 index 000000000..74657f264 Binary files /dev/null and b/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png differ diff --git a/docs/mkdocs/docs/integration/nuget/nuget-search-package.png b/docs/mkdocs/docs/integration/nuget/nuget-search-package.png new file mode 100644 index 000000000..da4c6e6dc Binary files /dev/null and b/docs/mkdocs/docs/integration/nuget/nuget-search-package.png differ diff --git a/docs/mkdocs/docs/integration/nuget/nuget-select-package.png b/docs/mkdocs/docs/integration/nuget/nuget-select-package.png new file mode 100644 index 000000000..b80ebc7bb Binary files /dev/null and b/docs/mkdocs/docs/integration/nuget/nuget-select-package.png differ diff --git a/docs/mkdocs/docs/integration/package_managers.md b/docs/mkdocs/docs/integration/package_managers.md index c9a273a50..1fc2460d7 100644 --- a/docs/mkdocs/docs/integration/package_managers.md +++ b/docs/mkdocs/docs/integration/package_managers.md @@ -1,5 +1,24 @@ # Package Managers +
+![Homebrew](../images/package_managers/homebrew.svg){: style="height:1em"} [**Homebrew**](#homebrew) `nlohmann-json`   +![Meson](../images/package_managers/meson.svg){: style="height:1em"} [**Meson**](#meson) `nlohmann_json`   +![Bazel](../images/package_managers/bazel.svg){: style="height:1em"} [**Bazel**](#bazel) `nlohmann_json`
+![Conan](../images/package_managers/conan.svg){: style="height:1em"} [**Conan**](#conan) `nlohmann_json`   +![Spack](../images/package_managers/spack.svg){: style="height:1em"} [**Spack**](#spack) `nlohmann-json`   +[**Hunter**](#hunter) `nlohmann_json`
+![vcpkg](../images/package_managers/vcpkg.png){: style="height:1em"} [**vcpkg**](#vcpkg) `nlohmann-json`   +[**cget**](#cget) `nlohmann/json`   +![Swift Package Manager](../images/package_managers/swift.svg){: style="height:1em"} [**Swift Package Manager**](#swift-package-manager) `nlohmann/json`
+![Nuget](../images/package_managers/nuget.svg){: style="height:1em"} [**NuGet**](#nuget) `nlohmann.json`   +![Conda](../images/package_managers/conda.svg){: style="height:1em"} [**Conda**](#conda) `nlohmann_json`   +![MacPorts](../images/package_managers/macports.svg){: style="height:1em"} [**MacPorts**](#macports) `nlohmann-json`
+![cpm.cmake](../images/package_managers/CPM.png){: style="height:1em"} [**CPM.cmake**](#cpmcmake) `gh:nlohmann/json` +![xmake](../images/package_managers/xmake.svg){: style="height:1em"} [**xmake**](#xmake) `nlohmann_json` +
+ +## Running example + Throughout this page, we will describe how to compile the example file `example.cpp` below. ```cpp @@ -14,61 +33,177 @@ When executed, this program should create output similar to ## Homebrew -If you are using OS X and [Homebrew](http://brew.sh), just type +!!! abstract "Summary" + + formula: [**`nlohmann-json`**](https://formulae.brew.sh/formula/nlohmann-json) + + - [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - :octicons-tag-24: Availalbe versions: current version and development version (with `--HEAD` parameter) + - :octicons-rocket-24: The formula is updated with every release. + - :octicons-person-24: Maintainer: Niels Lohmann + - :octicons-file-24: File issues at the [Homebrew issue tracker](https://github.com/Homebrew/homebrew-core/issues) + - :octicons-question-24: [Homebrew website](https://brew.sh) + +If you are using [Homebrew](http://brew.sh), you can install the library with ```sh brew install nlohmann-json ``` -and you're set. If you want the bleeding edge rather than the latest release, use +The header can be used directly in your code or via CMake. -```sh -brew install nlohmann-json --HEAD -``` - -instead. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information. - -??? example +??? example "Example: Raw compilation" 1. Create the following file: ```cpp title="example.cpp" - --8<-- "integration/example.cpp" + --8<-- "integration/homebrew/example.cpp" ``` - 2. Install the package + 2. Install the package: ```sh brew install nlohmann-json ``` - 3. Determine the include path, which defaults to `/usr/local/Cellar/nlohmann-json/$version/include`, where `$version` is the version of the library, e.g. `3.7.3`. The path of the library can be determined with + 3. Compile the code and pass the Homebrew prefix to the include path such that the library can be found: ```sh - brew list nlohmann-json + c++ example.cpp -I$(brew --prefix nlohmann-json)/include -std=c++11 -o example ``` - 4. Compile the code. For instance, the code can be compiled using Clang with +??? example "Example: CMake" + + 1. Create the following files: + + ```cpp title="example.cpp" + --8<-- "integration/homebrew/example.cpp" + ``` + + ```cmake title="CMakeLists.txt" + --8<-- "integration/homebrew/CMakeLists.txt" + ``` + + 2. Install the package: ```sh - clang++ example.cpp -I/usr/local/Cellar/nlohmann-json/3.7.3/include -std=c++11 -o example + brew install nlohmann-json ``` -:material-update: The [formula](https://formulae.brew.sh/formula/nlohmann-json) is updated automatically. + 3. Compile the code and pass the Homebrew prefix to CMake to find installed packages via `#!cmake find_package`: + + ```sh + CMAKE_PREFIX_PATH=$(brew --prefix) cmake -S . -B build + cmake --build build + ``` ## Meson -If you are using the [Meson Build System](http://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging. +!!! abstract "Summary" -The provided `meson.build` can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly. + wrap: **`nlohmann_json`** + + - :octicons-tag-24: Availalbe versions: current version and select older versions (see + [WrapDB](https://mesonbuild.com/Wrapdb-projects.html)) + - :octicons-rocket-24: The package is update automatically from file + [`meson.build`](https://github.com/nlohmann/json/blob/develop/meson.build). + - :octicons-file-24: File issues at the [library issue tracker](https://github.com/nlohmann/json/issues) + - :octicons-question-24: [Meson website](https://mesonbuild.com/index.html) + +If you are using the [Meson Build System](http://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the +`include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, +you can get a wrap file by downloading it from [Meson WrapDB](https://mesonbuild.com/Wrapdb-projects.html), or use + +```shell +meson wrap install nlohmann_json +``` + +Please see the Meson project for any issues regarding the packaging. + +The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in +which case a pkg-config file is installed. To use it, have your build system require the `nlohmann_json` +pkg-config dependency. In Meson, it is preferred to use the +[`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than +using the subproject directly. + +??? example "Example: Wrap" + + 1. Create the following files: + + ```ini title="meson.build" + --8<-- "integration/meson/meson.build" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/meson/example.cpp" + ``` + + 2. Use the Meson WrapDB to fetch the nlohmann/json wrap: + + ```shell + mkdir subprojects + meson wrap install nlohmann_json + ``` + + 3. Build: + + ```shell + meson setup build + meson compile -C build + ``` ## Bazel -This repository provides a [Bazel](https://bazel.build/) `WORKSPACE.bazel` and a corresponding `BUILD.bazel` file. Therefore, this repository can be referenced by workspace rules such as `http_archive`, `git_repository`, or `local_repository` from other Bazel workspaces. To use the library you only need to depend on the target `@nlohmann_json//:json` (e.g. via `deps` attribute). +!!! abstract "Summary" + + use `bazel_dep`, `git_override`, or `local_path_override` + + - :octicons-tag-24: Any version, that is available via [Bazel Central Registry](https://registry.bazel.build/modules/nlohmann_json) + - :octicons-file-24: File issues at the [library issue tracker](https://github.com/nlohmann/json/issues) + - :octicons-question-24: [Bazel website](https://bazel.build) + +This repository provides a [Bazel](https://bazel.build/) `MODULE.bazel` and a corresponding `BUILD.bazel` file. Therefore, this +repository can be referenced within a `MODULE.bazel` by rules such as `archive_override`, `git_override`, or `local_path_override`. To use the library, you need to depend on the target `@nlohmann_json//:json` (i.e., via `deps` attribute). + +??? example + + 1. Create the following files: + + ```ini title="BUILD" + --8<-- "integration/bazel/BUILD" + ``` + + ```ini title="WORKSPACE" + --8<-- "integration/bazel/MODULE.bazel" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/bazel/example.cpp" + ``` + + 2. Build and run: + + ```shell + bazel build //:main + bazel run //:main + ``` ## Conan -If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nlohmann_json/x.y.z` to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages. +!!! abstract "Summary" + + recipe: [**`nlohmann_json`**](https://conan.io/center/recipes/nlohmann_json) + + - [![ConanCenter package](https://repology.org/badge/version-for-repo/conancenter/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - :octicons-tag-24: Availalbe versions: current version and older versions (see + [Conan Center](https://conan.io/center/recipes/nlohmann_json)) + - :octicons-rocket-24: The package is update automatically via + [this recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/nlohmann_json). + - :octicons-file-24: File issues at the [Conan Center issue tracker](https://github.com/conan-io/conan-center-index/issues) + - :octicons-question-24: [Conan website](https://conan.io) + +If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nlohmann_json/x.y.z` to your `conanfile`'s +requires, where `x.y.z` is the release version you want to use. ??? example @@ -86,33 +221,140 @@ If you are using [Conan](https://www.conan.io/) to manage your dependencies, mer --8<-- "integration/conan/example.cpp" ``` - 2. Build: + 2. Call Conan: ```sh - mkdir build - cd build - conan install .. - cmake .. - cmake --build . + conan install . --output-folder=build --build=missing ``` -:material-update: The [package](https://conan.io/center/nlohmann_json) is updated automatically. + 3. Build: + + ```sh + cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release + cmake --build build + ``` ## Spack -If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. +!!! abstract "Summary" + + package: [**`nlohmann-json`**](https://packages.spack.io/package.html?name=nlohmann-json) + + - [![Spack package](https://repology.org/badge/version-for-repo/spack/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - :octicons-tag-24: Availalbe versions: current version and older versions (see + [Spack package](https://packages.spack.io/package.html?name=nlohmann-json)) + - :octicons-rocket-24: The package is updated with every release. + - :octicons-person-24: Maintainer: [Axel Huebl](https://github.com/ax3l) + - :octicons-file-24: File issues at the [Spack issue tracker](https://github.com/spack/spack/issues) + - :octicons-question-24: [Spack website](https://spack.io) + +If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the +[`nlohmann-json` package](https://packages.spack.io/package.html?name=nlohmann-json) via + +```shell +spack install nlohmann-json +``` + +Please see the [Spack project](https://github.com/spack/spack) for any issues regarding the packaging. + +??? example + + 1. Create the following files: + + ```cmake title="CMakeLists.txt" + --8<-- "integration/spack/CMakeLists.txt" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/spack/example.cpp" + ``` + + 2. Install the library: + + ```sh + spack install nlohmann-json + ``` + + 3. Load the environment for your Spack-installed packages: + + ```sh + spack load nlohmann-json + ``` + + 4. Build the project with CMake: + + ```sh + cmake -S . -B build -DCMAKE_PREFIX_PATH=$(spack location -i nlohmann-json) + cmake --build build + ``` ## Hunter -If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. +!!! abstract "Summary" -## Buckaroo + package: [**`nlohmann_json`**](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html) -If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example). + - :octicons-tag-24: Availalbe versions: current version and older versions (see + [Hunter package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html)) + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [Hunter issue tracker](https://github.com/cpp-pm/hunter/issues) + - :octicons-question-24: [Hunter website](https://hunter.readthedocs.io/en/latest/) + +If you are using [Hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use +the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html) via + +```cmake +hunter_add_package(nlohmann_json) +``` + +Please see the Hunter project for any issues regarding the packaging. + +??? example + + 1. Create the following files: + + ```cmake title="CMakeLists.txt" + --8<-- "integration/hunter/CMakeLists.txt" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/hunter/example.cpp" + ``` + + 2. Download required files + + ```shell + mkdir cmake + wget https://raw.githubusercontent.com/cpp-pm/gate/master/cmake/HunterGate.cmake -O cmake/HunterGate.cmake + ``` + + 3. Build the project with CMake: + + ```shell + cmake -S . -B build + cmake --build build + ``` ## vcpkg -If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. +!!! abstract "Summary" + + package: [**`nlohmann-json`**](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) + + - [![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - :octicons-tag-24: Availalbe versions: current version + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [vcpkg issue tracker](https://github.com/microsoft/vcpkg/issues) + - :octicons-question-24: [vcpkg website](https://vcpkg.io/) + +If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can +install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with + +```shell +vcpkg install nlohmann-json +``` + +and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. ??? example @@ -135,64 +377,450 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo 3. Build: ```sh - mkdir build - cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake - cmake --build . + cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake + cmake --build build ``` - Note you need to adjust `/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake` to your system. - ## cget -If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). +!!! abstract "Summary" -:material-update: cget reads directly from the [GitHub repository](https://github.com/nlohmann/json) and is always up-to-date. + package: [**`nlohmann/json`**](https://github.com/pfultz2/cget-recipes/blob/master/recipes/nlohmann/json/package.txt) -## CocoaPods + - :octicons-tag-24: Availalbe versions: current version and older versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [cget issue tracker](https://github.com/pfultz2/cget-recipes/issues) + - :octicons-question-24: [cget website](https://cget.readthedocs.io/) -If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). +If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest `master` version with + +```shell +cget install nlohmann/json +``` + +A specific version can be installed with `cget install nlohmann/json@v3.12.0`. Also, the multiple header version can be +installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). + +??? example + + 1. Create the following files: + + ```cmake title="CMakeLists.txt" + --8<-- "integration/vcpkg/CMakeLists.txt" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/vcpkg/example.cpp" + ``` + + 2. Initialize cget + + ```shell + cget init + ``` + + 3. Install the library + + ```shell + cget install nlohmann/json + ``` + + 4. Build + + ```shell + cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=cget/cget/cget.cmake + cmake --build build + ``` + +## Swift Package Manager + +!!! abstract "Summary" + + package: **`nlohmann/json`** + + - :octicons-tag-24: Availalbe versions: current version and older versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [library issue tracker](https://github.com/nlohmann/json/issues) + - :octicons-question-24: [Xcode documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) ## NuGet -If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please file issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). +!!! abstract "Summary" + + package: [**`nlohmann.json`**](https://www.nuget.org/packages/nlohmann.json/) + + - :octicons-tag-24: Availalbe versions: current and previous versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-person-24: Maintainer: [Hani Kaabi](https://github.com/hnkb) + - :octicons-file-24: File issues at the [maintainer's issue tracker](https://github.com/hnkb/nlohmann-json-nuget/issues) + - :octicons-question-24: [NuGet website](https://www.nuget.org) + +If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/) +with + +```shell +dotnet add package nlohmann.json +``` + +??? example + + Probably the easiest way to use NuGet packages is through Visual Studio graphical interface. Just right-click on a + project (any C++ project would do) in “Solution Explorer” and select “Manage NuGet Packages…” + + ![](nuget/nuget-search-package.png) + + Now you can click on “Browse” tab and find the package you like to install. + + ![](nuget/nuget-select-package.png) + + Most of the packages in NuGet gallery are .NET packages and would not be useful in a C++ project. Microsoft + recommends adding “native” and “nativepackage” tags to C++ NuGet packages to distinguish them, but even adding + “native” to search query would still show many .NET-only packages in the list. + + Nevertheless, after finding the package you want, click on “Install” button and accept confirmation dialogs. + After the package is successfully added to the projects, you should be able to build and execute the project + without the need for making any more changes to build settings. + + !!! note + + A few notes: + + - NuGet packages are installed per project and not system-wide. The header and binaries for the package are only + available to the project it is added to, and not other projects (obviously unless we add the package to those + projects as well) + - One of the many great things about your elegant work is that it is a header-only library, which makes + deployment very straightforward. In case of libraries which need binary deployment (`.lib`, `.dll` and `.pdb` + for debug info) the different binaries for each supported compiler version must be added to the NuGet package. + Some library creators cram binary versions for all supported Visual C++ compiler versions in the same package, + so a single package will support all compilers. Some others create a different package for each compiler + version (and you usually see things like “v140” or “vc141” in package name to clarify which VC++ compiler this + package supports). + - Packages can have dependency to other packages, and in this case, NuGet will install all dependencies as well + as the requested package recursively. + + **What happens behind the scenes** + + After you add a NuGet package, three changes occur in the project source directory. Of course, we could make these + changes manually instead of using GUI: + + ![](nuget/nuget-project-changes.png) + + 1. A `packages.config` file will be created (or updated to include the package name if one such file already + exists). This file contains a list of the packages required by this project (name and minimum version) and must + be added to the project source code repository, so if you move the source code to a new machine, MSBuild/NuGet + knows which packages it has to restore (which it does automatically before each build). + + ```xml + + + + + ``` + + 2. A `packages` folder which contains actual files in the packages (these are header and binary files required for + a successful build, plus a few metadata files). In case of this library for example, it contains `json.hpp`: + + ![](nuget/nuget-package-content.png) + + !!! note + + This directory should not be added to the project source code repository, as it will be restored before each + build by MSBuild/NuGet. If you go ahead and delete this folder, then build the project again, it will + magically re-appear! + + 3. Project MSBuild makefile (which for Visual C++ projects has a .vcxproj extension) will be updated to include + settings from the package. + + ![](nuget/nuget-project-makefile.png) + + The important bit for us here is line 170, which tells MSBuild to import settings from + `packages\nlohmann.json.3.5.0\build\native\nlohmann.json.targets` file. This is a file the package creator + created and added to the package (you can see it is one of the two files I created in this repository, the other + just contains package attributes like name and version number). What does it contain? + + For our header-only repository, the only setting we need is to add our include directory to the list of + `AdditionalIncludeDirectories`: + + ```xml + + + + + $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories) + + + + ``` + + For libraries with binary files, we will need to add `.lib` files to linker inputs and add settings to copy + `.dll` and other redistributable files to output directory, if needed. + + There are other changes to the makefile as well: + + - Lines 165-167 add the `packages.config` as one of project files (so it is shown in Solution Explorer tree + view). It is added as None (no build action) and removing it wouldn’t affect build. + + - Lines 172-177 check to ensure the required packages are present. This will display a build error if package + directory is empty (for example when NuGet cannot restore packages because Internet connection is down). + Again, if you omit this section, the only change in build would be a more cryptic error message if build + fails. + + !!! note + + Changes to .vcxproj makefile should also be added to project source code repository. + + As you can see, the mechanism NuGet uses to modify project settings is through MSBuild makefiles, so using NuGet + with other build systems and compilers (like CMake) as a dependency manager is either impossible or more problematic + than useful. + +Please refer to [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) for +more information. ## Conda -If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). +!!! abstract "Summary" + + package: [**`nlohmann_json`**](https://anaconda.org/conda-forge/nlohmann_json) + + - ![](https://img.shields.io/conda/v/conda-forge/nlohmann_json) + - :octicons-tag-24: Availalbe versions: current and previous versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [feedstock's issue tracker](https://github.com/conda-forge/nlohmann_json-feedstock/issues) + - :octicons-question-24: [Conda documentation](https://docs.conda.io/projects/conda/en/stable/user-guide/getting-started.html) + +If you are using [conda](https://conda.io/), you can use the package +[nlohmann_json](https://anaconda.org/conda-forge/nlohmann_json) from [conda-forge](https://conda-forge.org) executing + +```shell +conda install -c conda-forge nlohmann_json +``` + +??? example + + 1. Create the following file: + + ```cpp title="example.cpp" + --8<-- "integration/conda/example.cpp" + ``` + + 2. Create and activate an anvironment "json`: + + ```shell + conda create -n json + conda activate json + ``` + + 3. Install the package: + + ```shell + conda install -c conda-forge nlohmann_json + ``` + + 4. Build the code: + + ```shell + g++ -std=c++11 -I$(conda info --base)/envs/json/include example.cpp -o example + ``` ## MSYS2 -If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. +If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. + +[![MSYS2 clang64 package](https://repology.org/badge/version-for-repo/msys2_clang64/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) +[![MSYS2 clangarm64 package](https://repology.org/badge/version-for-repo/msys2_clangarm64/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) +[![MSYS2 mingw package](https://repology.org/badge/version-for-repo/msys2_mingw/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) +[![MSYS2 ucrt64 package](https://repology.org/badge/version-for-repo/msys2_ucrt64/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) :material-update: The [package](https://packages.msys2.org/base/mingw-w64-nlohmann-json) is updated automatically. ## MacPorts -If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. +!!! abstract "Summary" -:material-update: The [package](https://ports.macports.org/port/nlohmann-json/) is updated automatically. + port: [**`nlohmann-json`**](https://ports.macports.org/port/nlohmann-json/) + + - [![MacPorts package](https://repology.org/badge/version-for-repo/macports/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - :octicons-tag-24: Availalbe versions: current version + - :octicons-rocket-24: The port is updated with every release. + - :octicons-file-24: File issues at the [MacPorts issue tracker](https://trac.macports.org/newticket?port=nlohmann-json) + - :octicons-question-24: [MacPorts website](https://www.macports.org) + +If you are using [MacPorts](https://ports.macports.org), execute + +```shell +sudo port install nlohmann-json +``` + +to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. + +??? example "Example: Raw compilation" + + 1. Create the following file: + + ```cpp title="example.cpp" + --8<-- "integration/macports/example.cpp" + ``` + + 2. Install the package: + + ```sh + sudo port install nlohmann-json + ``` + + 3. Compile the code and pass the Homebrew prefix to the include path such that the library can be found: + + ```sh + c++ example.cpp -I/opt/local/include -std=c++11 -o example + ``` + +??? example "Example: CMake" + + 1. Create the following files: + + ```cpp title="example.cpp" + --8<-- "integration/homebrew/example.cpp" + ``` + + ```cmake title="CMakeLists.txt" + --8<-- "integration/homebrew/CMakeLists.txt" + ``` + + 2. Install the package: + + ```sh + sudo port install nlohmann-json + ``` + + 3. Compile the code: + + ```sh + cmake -S . -B build + cmake --build build + ``` ## build2 -If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). +If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) +package from the public repository or directly from the +[package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, +add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages. :material-update: The [package](https://cppget.org/nlohmann-json) is updated automatically. -## wsjcpp - -If you are using [`wsjcpp`](http://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. - -:material-update: wsjcpp reads directly from the [GitHub repository](https://github.com/nlohmann/json) and is always up-to-date. +```shell +bdep new -t exe -l c++ +``` ## CPM.cmake -If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake: +!!! abstract "Summary" + + package: **`gh:nlohmann/json`** + + - :octicons-tag-24: Availalbe versions: current and previous versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [CPM.cmake issue tracker](https://github.com/cpm-cmake/CPM.cmake/issues) + - :octicons-question-24: [CPM.cmake website](https://github.com/cpm-cmake/CPM.cmake) + +If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), add the +[CPM.cmake script](https://github.com/TheLartians/CPM.cmake#adding-cpm) and the following snippet to your CMake project: ```cmake -CPMAddPackage( - NAME nlohmann_json - GITHUB_REPOSITORY nlohmann/json - VERSION 3.9.1) +CPMAddPackage("gh:nlohmann/json@3.12.0") ``` + +??? example + + 1. Create the following files: + + ```cpp title="example.cpp" + --8<-- "integration/cpm/example.cpp" + ``` + + ```cmake title="CMakeLists.txt" + --8<-- "integration/cpm/CMakeLists.txt" + ``` + + 2. Download CPM.cmake + + ```shell + mkdir -p cmake + wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake + ``` + + 3. Build + + ```shell + cmake -S . -B build + cmake --build build + ``` + +## xmake + +!!! abstract "Summary" + + package: [**`nlohmann_json`**](https://github.com/xmake-io/xmake-repo/blob/master/packages/n/nlohmann_json/xmake.lua) + + - :octicons-tag-24: Availalbe versions: current and previous versions + - :octicons-rocket-24: The package is updated with every release. + - :octicons-file-24: File issues at the [xmake issue tracker](https://github.com/xmake-io/xmake-repo/issues) + - :octicons-question-24: [xmake website](https://xmake.io/#/) + +??? example + + 1. Create the following files: + + ```cpp title="example.cpp" + --8<-- "integration/xmake/example.cpp" + ``` + + ```lua title="xmake.lua" + --8<-- "integration/xmake/xmake.lua" + ``` + + 2. Build + + ```shell + xmake + ``` + + 3. Run + + ```shell + xmake run + ``` + +* * * + +## Other package managers + +The library is also contained in many other package repositories: [![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + +??? example "Package version overview" + + [![Packaging status](https://repology.org/badge/vertical-allrepos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + + +* * * + +## Buckaroo + +If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example). + +!!! warning + + The module is outdated as the respective [repository](https://github.com/buckaroo-pm/nlohmann-json) has not been + updated in years. + +## CocoaPods + +If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` +to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues +[here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). + +![](https://img.shields.io/cocoapods/v/nlohmann_json) + +!!! warning + + The module is outdated as the respective [pod](https://cocoapods.org/pods/nlohmann_json) has not been updated in years. diff --git a/docs/mkdocs/docs/integration/spack/CMakeLists.txt b/docs/mkdocs/docs/integration/spack/CMakeLists.txt new file mode 100644 index 000000000..e3fda5b9a --- /dev/null +++ b/docs/mkdocs/docs/integration/spack/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(json_example) + +find_package(nlohmann_json REQUIRED) + +add_executable(json_example example.cpp) +target_link_libraries(json_example PRIVATE nlohmann_json::nlohmann_json) diff --git a/docs/mkdocs/docs/integration/spack/example.cpp b/docs/mkdocs/docs/integration/spack/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/spack/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/vcpkg/CMakeLists.txt b/docs/mkdocs/docs/integration/vcpkg/CMakeLists.txt index d31f4e835..12f4ae1f2 100644 --- a/docs/mkdocs/docs/integration/vcpkg/CMakeLists.txt +++ b/docs/mkdocs/docs/integration/vcpkg/CMakeLists.txt @@ -1,5 +1,5 @@ +cmake_minimum_required(VERSION 3.15) project(json_example) -cmake_minimum_required(VERSION 2.8.12) find_package(nlohmann_json CONFIG REQUIRED) diff --git a/docs/mkdocs/docs/integration/vcpkg/example.cpp b/docs/mkdocs/docs/integration/vcpkg/example.cpp index e5a31be4b..1a7ac4de2 100644 --- a/docs/mkdocs/docs/integration/vcpkg/example.cpp +++ b/docs/mkdocs/docs/integration/vcpkg/example.cpp @@ -1,9 +1,10 @@ #include #include +#include using json = nlohmann::json; int main() { - std::cout << json::meta() << std::endl; + std::cout << std::setw(4) << json::meta() << std::endl; } diff --git a/docs/mkdocs/docs/integration/xmake/example.cpp b/docs/mkdocs/docs/integration/xmake/example.cpp new file mode 100644 index 000000000..1a7ac4de2 --- /dev/null +++ b/docs/mkdocs/docs/integration/xmake/example.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::setw(4) << json::meta() << std::endl; +} diff --git a/docs/mkdocs/docs/integration/xmake/xmake.lua b/docs/mkdocs/docs/integration/xmake/xmake.lua new file mode 100644 index 000000000..c5b332897 --- /dev/null +++ b/docs/mkdocs/docs/integration/xmake/xmake.lua @@ -0,0 +1,8 @@ +add_requires("nlohmann_json") + +add_rules("mode.debug", "mode.release") +target("xm") + set_kind("binary") + add_files("example.cpp") + add_packages("nlohmann_json") + set_languages("cxx11") diff --git a/docs/mkdocs/includes/glossary.md b/docs/mkdocs/includes/glossary.md new file mode 100644 index 000000000..afc7ebc6a --- /dev/null +++ b/docs/mkdocs/includes/glossary.md @@ -0,0 +1,36 @@ + + +*[ADL]: Argument-dependent lookup +*[API]: Application Programming Interfaces +*[ASCII]: American Standard Code for Information Interchange +*[BDFL]: Benevolent Dictator for Life +*[BJData]: Binary JData +*[BSON]: Binary JSON +*[CBOR]: Concise Binary Object Representation +*[CC0]: Creative Commons Zero +*[CI]: Continuous Integration +*[DOM]: Document Object Model +*[EOF]: End of File +*[FAQ]: Frequently Asked Questions +*[GCC]: GNU Compiler Collection +*[HTTP]: Hypertext Transfer Protocol +*[ICC]: Intel C++ Compiler +*[IEEE]: Institute of Electrical and Electronics Engineers +*[ISO]: International Organization for Standardization +*[JSON]: JavaScript Object Notation +*[MIT]: Massachusetts Institute of Technology +*[MSVC]: Microsoft Visual C++ +*[MsgPack]: MessagePack +*[NASA]: National Aeronautics and Space Administration +*[NDK]: Native Development Kit +*[NaN]: Not a Number +*[RFC]: Request for Comments +*[RTTI]: Runtime Type Information +*[SAX]: Simple API for XML +*[SDK]: Software Development Kit +*[SFINAE]: Substitution failure is not an error +*[SHA]: Secure Hash Algorithm +*[SPDX]: Software Package Data Exchange +*[STL]: Standard Template Library +*[UBJSON]: Universal Binary JSON +*[UTF]: Unicode Transformation Format diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 5e66db596..7a89219fb 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -9,7 +9,7 @@ repo_url: https://github.com/nlohmann/json edit_uri: edit/develop/docs/mkdocs/docs # Copyright -copyright: Copyright © 2013 - 2023 Niels Lohmann +copyright: Copyright © 2013-2025 Niels Lohmann # Configuration theme: @@ -21,7 +21,7 @@ theme: primary: indigo accent: indigo toggle: - icon: material/brightness-7 + icon: material/brightness-7 name: Switch to dark mode - media: '(prefers-color-scheme: dark)' scheme: slate @@ -30,7 +30,8 @@ theme: toggle: icon: material/brightness-4 name: Switch to light mode - + icon: + repo: fontawesome/brands/github font: text: Roboto code: JetBrains Mono @@ -41,266 +42,266 @@ theme: - navigation.indexes - navigation.top - content.tabs.link + - content.action.edit + - content.action.view nav: - Home: - - index.md - - home/license.md - - "Code of Conduct": home/code_of_conduct.md - - "FAQ": home/faq.md - - home/exceptions.md - - home/releases.md - - home/design_goals.md - - home/sponsors.md + - index.md + - home/license.md + - "FAQ": home/faq.md + - home/exceptions.md + - home/releases.md + - home/design_goals.md + - home/architecture.md + - home/customers.md + - home/sponsors.md - Features: - - features/arbitrary_types.md - - Binary Formats: - - features/binary_formats/index.md - - features/binary_formats/bjdata.md - - features/binary_formats/bson.md - - features/binary_formats/cbor.md - - features/binary_formats/messagepack.md - - features/binary_formats/ubjson.md - - features/binary_values.md - - features/comments.md - - Element Access: - - features/element_access/index.md - - features/element_access/unchecked_access.md - - features/element_access/checked_access.md - - features/element_access/default_value.md - - features/iterators.md - - features/json_pointer.md - - features/json_patch.md - - features/merge_patch.md - - 'nlohmann Namespace': features/namespace.md - - features/object_order.md - - Parsing: - - features/parsing/index.md - - features/parsing/json_lines.md - - features/parsing/parse_exceptions.md - - features/parsing/parser_callbacks.md - - features/parsing/sax_interface.md - - features/assertions.md - - features/enum_conversion.md - - features/macros.md - - Types: - - features/types/index.md - - features/types/number_handling.md + - features/arbitrary_types.md + - Binary Formats: + - features/binary_formats/index.md + - features/binary_formats/bjdata.md + - features/binary_formats/bson.md + - features/binary_formats/cbor.md + - features/binary_formats/messagepack.md + - features/binary_formats/ubjson.md + - features/binary_values.md + - features/comments.md + - Element Access: + - features/element_access/index.md + - features/element_access/unchecked_access.md + - features/element_access/checked_access.md + - features/element_access/default_value.md + - features/iterators.md + - features/json_pointer.md + - features/json_patch.md + - features/merge_patch.md + - 'nlohmann Namespace': features/namespace.md + - features/object_order.md + - Parsing: + - features/parsing/index.md + - features/parsing/json_lines.md + - features/parsing/parse_exceptions.md + - features/parsing/parser_callbacks.md + - features/parsing/sax_interface.md + - features/assertions.md + - features/enum_conversion.md + - features/macros.md + - Types: + - features/types/index.md + - features/types/number_handling.md - Integration: - - integration/index.md - - integration/migration_guide.md - - integration/cmake.md - - integration/package_managers.md - - integration/pkg-config.md + - integration/index.md + - integration/migration_guide.md + - integration/cmake.md + - integration/package_managers.md + - integration/pkg-config.md - API Documentation: - basic_json: - - 'Overview': api/basic_json/index.md - - '(Constructor)': api/basic_json/basic_json.md - - '(Destructor)': api/basic_json/~basic_json.md - - 'accept': api/basic_json/accept.md - - 'array': api/basic_json/array.md - - 'array_t': api/basic_json/array_t.md - - 'at': api/basic_json/at.md - - 'back': api/basic_json/back.md - - 'begin': api/basic_json/begin.md - - 'binary': api/basic_json/binary.md - - 'binary_t': api/basic_json/binary_t.md - - 'boolean_t': api/basic_json/boolean_t.md - - 'cbegin': api/basic_json/cbegin.md - - 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md - - 'cend': api/basic_json/cend.md - - 'clear': api/basic_json/clear.md - - 'contains': api/basic_json/contains.md - - 'count': api/basic_json/count.md - - 'crbegin': api/basic_json/crbegin.md - - 'crend': api/basic_json/crend.md - - 'default_object_comparator_t': api/basic_json/default_object_comparator_t.md - - 'diff': api/basic_json/diff.md - - 'dump': api/basic_json/dump.md - - 'emplace': api/basic_json/emplace.md - - 'emplace_back': api/basic_json/emplace_back.md - - 'empty': api/basic_json/empty.md - - 'end': api/basic_json/end.md - - 'erase': api/basic_json/erase.md - - 'error_handler_t': api/basic_json/error_handler_t.md - - 'exception': api/basic_json/exception.md - - 'find': api/basic_json/find.md - - 'flatten': api/basic_json/flatten.md - - 'from_bjdata': api/basic_json/from_bjdata.md - - 'from_bson': api/basic_json/from_bson.md - - 'from_cbor': api/basic_json/from_cbor.md - - 'from_msgpack': api/basic_json/from_msgpack.md - - 'from_ubjson': api/basic_json/from_ubjson.md - - 'front': api/basic_json/front.md - - 'get': api/basic_json/get.md - - 'get_allocator': api/basic_json/get_allocator.md - - 'get_binary': api/basic_json/get_binary.md - - 'get_ptr': api/basic_json/get_ptr.md - - 'get_ref': api/basic_json/get_ref.md - - 'get_to': api/basic_json/get_to.md - - 'std::hash<basic_json>': api/basic_json/std_hash.md - - 'input_format_t': api/basic_json/input_format_t.md - - 'insert': api/basic_json/insert.md - - 'invalid_iterator': api/basic_json/invalid_iterator.md - - 'is_array': api/basic_json/is_array.md - - 'is_binary': api/basic_json/is_binary.md - - 'is_boolean': api/basic_json/is_boolean.md - - 'is_discarded': api/basic_json/is_discarded.md - - 'is_null': api/basic_json/is_null.md - - 'is_number': api/basic_json/is_number.md - - 'is_number_float': api/basic_json/is_number_float.md - - 'is_number_integer': api/basic_json/is_number_integer.md - - 'is_number_unsigned': api/basic_json/is_number_unsigned.md - - 'is_object': api/basic_json/is_object.md - - 'is_primitive': api/basic_json/is_primitive.md - - 'is_string': api/basic_json/is_string.md - - 'is_structured': api/basic_json/is_structured.md - - 'items': api/basic_json/items.md - - 'json_base_class_t': api/basic_json/json_base_class_t.md - - 'json_serializer': api/basic_json/json_serializer.md - - 'max_size': api/basic_json/max_size.md - - 'meta': api/basic_json/meta.md - - 'merge_patch': api/basic_json/merge_patch.md - - 'number_float_t': api/basic_json/number_float_t.md - - 'number_integer_t': api/basic_json/number_integer_t.md - - 'number_unsigned_t': api/basic_json/number_unsigned_t.md - - 'object': api/basic_json/object.md - - 'object_comparator_t': api/basic_json/object_comparator_t.md - - 'object_t': api/basic_json/object_t.md - - 'operator ValueType': api/basic_json/operator_ValueType.md - - 'operator value_t': api/basic_json/operator_value_t.md - - 'operator[]': api/basic_json/operator[].md - - 'operator=': api/basic_json/operator=.md - - 'operator+=': api/basic_json/operator+=.md - - 'operator==': api/basic_json/operator_eq.md - - 'operator!=': api/basic_json/operator_ne.md - - 'operator<': api/basic_json/operator_lt.md - - 'operator>': api/basic_json/operator_gt.md - - 'operator<=': api/basic_json/operator_le.md - - 'operator>=': api/basic_json/operator_ge.md - - 'operator<=>': api/basic_json/operator_spaceship.md - - 'out_of_range': api/basic_json/out_of_range.md - - 'other_error': api/basic_json/other_error.md - - 'parse': api/basic_json/parse.md - - 'parse_error': api/basic_json/parse_error.md - - 'parse_event_t': api/basic_json/parse_event_t.md - - 'parser_callback_t': api/basic_json/parser_callback_t.md - - 'patch': api/basic_json/patch.md - - 'patch_inplace': api/basic_json/patch_inplace.md - - 'push_back': api/basic_json/push_back.md - - 'rbegin': api/basic_json/rbegin.md - - 'rend': api/basic_json/rend.md - - 'sax_parse': api/basic_json/sax_parse.md - - 'size': api/basic_json/size.md - - 'string_t': api/basic_json/string_t.md - - 'swap': api/basic_json/swap.md - - 'std::swap<basic_json>': api/basic_json/std_swap.md - - 'to_bjdata': api/basic_json/to_bjdata.md - - 'to_bson': api/basic_json/to_bson.md - - 'to_cbor': api/basic_json/to_cbor.md - - 'to_msgpack': api/basic_json/to_msgpack.md - - 'to_string': api/basic_json/to_string.md - - 'to_ubjson': api/basic_json/to_ubjson.md - - 'type': api/basic_json/type.md - - 'type_error': api/basic_json/type_error.md - - 'type_name': api/basic_json/type_name.md - - 'unflatten': api/basic_json/unflatten.md - - 'update': api/basic_json/update.md - - 'value': api/basic_json/value.md - - 'value_t': api/basic_json/value_t.md + - 'Overview': api/basic_json/index.md + - '(Constructor)': api/basic_json/basic_json.md + - '(Destructor)': api/basic_json/~basic_json.md + - 'accept': api/basic_json/accept.md + - 'array': api/basic_json/array.md + - 'array_t': api/basic_json/array_t.md + - 'at': api/basic_json/at.md + - 'back': api/basic_json/back.md + - 'begin': api/basic_json/begin.md + - 'binary': api/basic_json/binary.md + - 'binary_t': api/basic_json/binary_t.md + - 'boolean_t': api/basic_json/boolean_t.md + - 'cbegin': api/basic_json/cbegin.md + - 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md + - 'cend': api/basic_json/cend.md + - 'clear': api/basic_json/clear.md + - 'contains': api/basic_json/contains.md + - 'count': api/basic_json/count.md + - 'crbegin': api/basic_json/crbegin.md + - 'crend': api/basic_json/crend.md + - 'default_object_comparator_t': api/basic_json/default_object_comparator_t.md + - 'diff': api/basic_json/diff.md + - 'dump': api/basic_json/dump.md + - 'emplace': api/basic_json/emplace.md + - 'emplace_back': api/basic_json/emplace_back.md + - 'empty': api/basic_json/empty.md + - 'end': api/basic_json/end.md + - 'end_pos': api/basic_json/end_pos.md + - 'erase': api/basic_json/erase.md + - 'error_handler_t': api/basic_json/error_handler_t.md + - 'exception': api/basic_json/exception.md + - 'find': api/basic_json/find.md + - 'flatten': api/basic_json/flatten.md + - 'from_bjdata': api/basic_json/from_bjdata.md + - 'from_bson': api/basic_json/from_bson.md + - 'from_cbor': api/basic_json/from_cbor.md + - 'from_msgpack': api/basic_json/from_msgpack.md + - 'from_ubjson': api/basic_json/from_ubjson.md + - 'front': api/basic_json/front.md + - 'get': api/basic_json/get.md + - 'get_allocator': api/basic_json/get_allocator.md + - 'get_binary': api/basic_json/get_binary.md + - 'get_ptr': api/basic_json/get_ptr.md + - 'get_ref': api/basic_json/get_ref.md + - 'get_to': api/basic_json/get_to.md + - 'std::hash<basic_json>': api/basic_json/std_hash.md + - 'input_format_t': api/basic_json/input_format_t.md + - 'insert': api/basic_json/insert.md + - 'invalid_iterator': api/basic_json/invalid_iterator.md + - 'is_array': api/basic_json/is_array.md + - 'is_binary': api/basic_json/is_binary.md + - 'is_boolean': api/basic_json/is_boolean.md + - 'is_discarded': api/basic_json/is_discarded.md + - 'is_null': api/basic_json/is_null.md + - 'is_number': api/basic_json/is_number.md + - 'is_number_float': api/basic_json/is_number_float.md + - 'is_number_integer': api/basic_json/is_number_integer.md + - 'is_number_unsigned': api/basic_json/is_number_unsigned.md + - 'is_object': api/basic_json/is_object.md + - 'is_primitive': api/basic_json/is_primitive.md + - 'is_string': api/basic_json/is_string.md + - 'is_structured': api/basic_json/is_structured.md + - 'items': api/basic_json/items.md + - 'json_base_class_t': api/basic_json/json_base_class_t.md + - 'json_serializer': api/basic_json/json_serializer.md + - 'max_size': api/basic_json/max_size.md + - 'meta': api/basic_json/meta.md + - 'merge_patch': api/basic_json/merge_patch.md + - 'number_float_t': api/basic_json/number_float_t.md + - 'number_integer_t': api/basic_json/number_integer_t.md + - 'number_unsigned_t': api/basic_json/number_unsigned_t.md + - 'object': api/basic_json/object.md + - 'object_comparator_t': api/basic_json/object_comparator_t.md + - 'object_t': api/basic_json/object_t.md + - 'operator ValueType': api/basic_json/operator_ValueType.md + - 'operator value_t': api/basic_json/operator_value_t.md + - 'operator[]': api/basic_json/operator[].md + - 'operator=': api/basic_json/operator=.md + - 'operator+=': api/basic_json/operator+=.md + - 'operator==': api/basic_json/operator_eq.md + - 'operator!=': api/basic_json/operator_ne.md + - 'operator<': api/basic_json/operator_lt.md + - 'operator>': api/basic_json/operator_gt.md + - 'operator<=': api/basic_json/operator_le.md + - 'operator>=': api/basic_json/operator_ge.md + - 'operator<=>': api/basic_json/operator_spaceship.md + - 'out_of_range': api/basic_json/out_of_range.md + - 'other_error': api/basic_json/other_error.md + - 'parse': api/basic_json/parse.md + - 'parse_error': api/basic_json/parse_error.md + - 'parse_event_t': api/basic_json/parse_event_t.md + - 'parser_callback_t': api/basic_json/parser_callback_t.md + - 'patch': api/basic_json/patch.md + - 'patch_inplace': api/basic_json/patch_inplace.md + - 'push_back': api/basic_json/push_back.md + - 'rbegin': api/basic_json/rbegin.md + - 'rend': api/basic_json/rend.md + - 'sax_parse': api/basic_json/sax_parse.md + - 'size': api/basic_json/size.md + - 'start_pos': api/basic_json/start_pos.md + - 'string_t': api/basic_json/string_t.md + - 'swap': api/basic_json/swap.md + - 'std::swap<basic_json>': api/basic_json/std_swap.md + - 'to_bjdata': api/basic_json/to_bjdata.md + - 'to_bson': api/basic_json/to_bson.md + - 'to_cbor': api/basic_json/to_cbor.md + - 'to_msgpack': api/basic_json/to_msgpack.md + - 'to_string': api/basic_json/to_string.md + - 'to_ubjson': api/basic_json/to_ubjson.md + - 'type': api/basic_json/type.md + - 'type_error': api/basic_json/type_error.md + - 'type_name': api/basic_json/type_name.md + - 'unflatten': api/basic_json/unflatten.md + - 'update': api/basic_json/update.md + - 'value': api/basic_json/value.md + - 'value_t': api/basic_json/value_t.md - byte_container_with_subtype: - - 'Overview': api/byte_container_with_subtype/index.md - - '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md - - 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md - - 'has_subtype': api/byte_container_with_subtype/has_subtype.md - - 'set_subtype': api/byte_container_with_subtype/set_subtype.md - - 'subtype': api/byte_container_with_subtype/subtype.md + - 'Overview': api/byte_container_with_subtype/index.md + - '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md + - 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md + - 'has_subtype': api/byte_container_with_subtype/has_subtype.md + - 'set_subtype': api/byte_container_with_subtype/set_subtype.md + - 'subtype': api/byte_container_with_subtype/subtype.md - adl_serializer: - - 'Overview': api/adl_serializer/index.md - - 'from_json': api/adl_serializer/from_json.md - - 'to_json': api/adl_serializer/to_json.md + - 'Overview': api/adl_serializer/index.md + - 'from_json': api/adl_serializer/from_json.md + - 'to_json': api/adl_serializer/to_json.md - 'json': api/json.md - json_pointer: - - 'Overview': api/json_pointer/index.md - - '(Constructor)': api/json_pointer/json_pointer.md - - 'back': api/json_pointer/back.md - - 'empty': api/json_pointer/empty.md - - 'operator string_t': api/json_pointer/operator_string_t.md - - 'operator==': api/json_pointer/operator_eq.md - - 'operator!=': api/json_pointer/operator_ne.md - - 'operator/': api/json_pointer/operator_slash.md - - 'operator/=': api/json_pointer/operator_slasheq.md - - 'parent_pointer': api/json_pointer/parent_pointer.md - - 'pop_back': api/json_pointer/pop_back.md - - 'push_back': api/json_pointer/push_back.md - - 'string_t': api/json_pointer/string_t.md - - 'to_string': api/json_pointer/to_string.md + - 'Overview': api/json_pointer/index.md + - '(Constructor)': api/json_pointer/json_pointer.md + - 'back': api/json_pointer/back.md + - 'empty': api/json_pointer/empty.md + - 'operator string_t': api/json_pointer/operator_string_t.md + - 'operator==': api/json_pointer/operator_eq.md + - 'operator!=': api/json_pointer/operator_ne.md + - 'operator/': api/json_pointer/operator_slash.md + - 'operator/=': api/json_pointer/operator_slasheq.md + - 'parent_pointer': api/json_pointer/parent_pointer.md + - 'pop_back': api/json_pointer/pop_back.md + - 'push_back': api/json_pointer/push_back.md + - 'string_t': api/json_pointer/string_t.md + - 'to_string': api/json_pointer/to_string.md - json_sax: - - 'Overview': api/json_sax/index.md - - 'binary': api/json_sax/binary.md - - 'boolean': api/json_sax/boolean.md - - 'end_array': api/json_sax/end_array.md - - 'end_object': api/json_sax/end_object.md - - 'key': api/json_sax/key.md - - 'null': api/json_sax/null.md - - 'number_float': api/json_sax/number_float.md - - 'number_integer': api/json_sax/number_integer.md - - 'number_unsigned': api/json_sax/number_unsigned.md - - 'parse_error': api/json_sax/parse_error.md - - 'start_array': api/json_sax/start_array.md - - 'start_object': api/json_sax/start_object.md - - 'string': api/json_sax/string.md - - 'operator<<(basic_json)': api/operator_ltlt.md - - 'operator<<(json_pointer)': api/operator_ltlt.md + - 'Overview': api/json_sax/index.md + - 'binary': api/json_sax/binary.md + - 'boolean': api/json_sax/boolean.md + - 'end_array': api/json_sax/end_array.md + - 'end_object': api/json_sax/end_object.md + - 'key': api/json_sax/key.md + - 'null': api/json_sax/null.md + - 'number_float': api/json_sax/number_float.md + - 'number_integer': api/json_sax/number_integer.md + - 'number_unsigned': api/json_sax/number_unsigned.md + - 'parse_error': api/json_sax/parse_error.md + - 'start_array': api/json_sax/start_array.md + - 'start_object': api/json_sax/start_object.md + - 'string': api/json_sax/string.md + - 'operator<<(basic_json), operator<<(json_pointer)': api/operator_ltlt.md - 'operator>>(basic_json)': api/operator_gtgt.md - 'operator""_json': api/operator_literal_json.md - 'operator""_json_pointer': api/operator_literal_json_pointer.md - 'ordered_json': api/ordered_json.md - 'ordered_map': api/ordered_map.md - macros: - - 'Overview': api/macros/index.md - - 'JSON_ASSERT': api/macros/json_assert.md - - 'JSON_CATCH_USER': api/macros/json_throw_user.md - - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md - - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md - - 'JSON_HAS_CPP_11': api/macros/json_has_cpp_11.md - - 'JSON_HAS_CPP_14': api/macros/json_has_cpp_11.md - - 'JSON_HAS_CPP_17': api/macros/json_has_cpp_11.md - - 'JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md - - 'JSON_HAS_EXPERIMENTAL_FILESYSTEM': api/macros/json_has_filesystem.md - - 'JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md - - 'JSON_HAS_RANGES': api/macros/json_has_ranges.md - - 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md - - 'JSON_HAS_THREE_WAY_COMPARISON': api/macros/json_has_three_way_comparison.md - - 'JSON_NOEXCEPTION': api/macros/json_noexception.md - - 'JSON_NO_IO': api/macros/json_no_io.md - - 'JSON_SKIP_LIBRARY_VERSION_CHECK': api/macros/json_skip_library_version_check.md - - 'JSON_SKIP_UNSUPPORTED_COMPILER_CHECK': api/macros/json_skip_unsupported_compiler_check.md - - 'JSON_THROW_USER': api/macros/json_throw_user.md - - 'JSON_TRY_USER': api/macros/json_throw_user.md - - 'JSON_USE_GLOBAL_UDLS': api/macros/json_use_global_udls.md - - 'JSON_USE_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.md - - 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md - - 'NLOHMANN_DEFINE_TYPE_INTRUSIVE': api/macros/nlohmann_define_type_intrusive.md - - 'NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_intrusive.md - - 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE': api/macros/nlohmann_define_type_non_intrusive.md - - 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_non_intrusive.md - - 'NLOHMANN_JSON_NAMESPACE': api/macros/nlohmann_json_namespace.md - - 'NLOHMANN_JSON_NAMESPACE_BEGIN': api/macros/nlohmann_json_namespace_begin.md - - 'NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md - - 'NLOHMANN_JSON_NAMESPACE_NO_VERSION': api/macros/nlohmann_json_namespace_no_version.md - - 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md - - 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md - - 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md - - 'NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md + - 'Overview': api/macros/index.md + - 'JSON_ASSERT': api/macros/json_assert.md + - 'JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER': api/macros/json_throw_user.md + - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md + - 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md + - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md + - 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md + - 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md + - 'JSON_HAS_RANGES': api/macros/json_has_ranges.md + - 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md + - 'JSON_HAS_THREE_WAY_COMPARISON': api/macros/json_has_three_way_comparison.md + - 'JSON_NOEXCEPTION': api/macros/json_noexception.md + - 'JSON_NO_IO': api/macros/json_no_io.md + - 'JSON_SKIP_LIBRARY_VERSION_CHECK': api/macros/json_skip_library_version_check.md + - 'JSON_SKIP_UNSUPPORTED_COMPILER_CHECK': api/macros/json_skip_unsupported_compiler_check.md + - 'JSON_USE_GLOBAL_UDLS': api/macros/json_use_global_udls.md + - 'JSON_USE_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.md + - 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md + - 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md + - 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md + - 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_non_intrusive.md + - 'NLOHMANN_JSON_NAMESPACE': api/macros/nlohmann_json_namespace.md + - 'NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md + - 'NLOHMANN_JSON_NAMESPACE_NO_VERSION': api/macros/nlohmann_json_namespace_no_version.md + - 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md + - 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md + - Community: + - community/index.md + - "Code of Conduct": community/code_of_conduct.md + - community/contribution_guidelines.md + - community/quality_assurance.md + - community/governance.md + - community/security_policy.md # Extras extra: social: - icon: fontawesome/brands/github link: https://github.com/nlohmann - - icon: fontawesome/brands/twitter - link: https://twitter.com/nlohmann - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/nielslohmann/ - icon: fontawesome/brands/xing @@ -332,7 +333,11 @@ markdown_extensions: - pymdownx.magiclink - pymdownx.mark #- pymdownx.smartsymbols - - pymdownx.superfences + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format - pymdownx.tasklist: custom_checkbox: true - pymdownx.tabbed: @@ -341,26 +346,35 @@ markdown_extensions: - pymdownx.snippets: base_path: docs check_paths: true - - plantuml_markdown: - format: svg + restrict_base_path: false # needed to allow including files from the .github folder + auto_append: + - ../includes/glossary.md plugins: - - search: - separator: '[\s\-\.]' - lang: en - - minify: - minify_html: true - - git-revision-date-localized - - redirects: - redirect_maps: - 'api/basic_json/operator_gtgt.md': api/operator_gtgt.md - 'api/basic_json/operator_ltlt.md': api/operator_ltlt.md - 'api/basic_json/operator_literal_json.md': api/operator_literal_json.md - 'api/basic_json/operator_literal_json_pointer.md': api/operator_literal_json_pointer.md - 'api/json_pointer/operator_string.md': api/json_pointer/operator_string_t.md + - search: + separator: '[\s\-\.]' + lang: en + - minify: + minify_html: true + - git-revision-date-localized + - redirects: + redirect_maps: + 'api/basic_json/operator_gtgt.md': api/operator_gtgt.md + 'api/basic_json/operator_ltlt.md': api/operator_ltlt.md + 'api/basic_json/operator_literal_json.md': api/operator_literal_json.md + 'api/basic_json/operator_literal_json_pointer.md': api/operator_literal_json_pointer.md + 'api/json_pointer/operator_string.md': api/json_pointer/operator_string_t.md + 'home/code_of_conduct.md': community/code_of_conduct.md + - htmlproofer: # see https://github.com/manuzhang/mkdocs-htmlproofer-plugin + enabled: !ENV [ENABLED_HTMLPROOFER, False] + ignore_urls: + - http://nlohmann.github.io/json/* + - https://nlohmann.github.io/json/* + - mailto:* + - privacy extra_css: - - css/custom.css + - css/custom.css extra_javascript: - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML diff --git a/docs/mkdocs/requirements.txt b/docs/mkdocs/requirements.txt index b397d545d..4e23e1cad 100644 --- a/docs/mkdocs/requirements.txt +++ b/docs/mkdocs/requirements.txt @@ -1,49 +1,11 @@ -Babel==2.13.1 -certifi==2023.7.22 -charset-normalizer==3.3.1 -click==8.1.7 -csscompressor==0.9.5 -future==0.18.3 -ghp-import==2.1.0 -gitdb==4.0.11 -GitPython==3.1.40 -htmlmin==0.1.12 -httplib2==0.22.0 -idna==3.4 -importlib-metadata==6.8.0 -Jinja2==3.1.2 -joblib==1.3.2 -jsmin==3.0.1 -livereload==2.6.3 -lunr==0.7.0.post1 -Markdown==3.5 -markdown-include==0.8.1 -MarkupSafe==2.1.3 -mergedeep==1.3.4 -mkdocs==1.5.3 -mkdocs-git-revision-date-localized-plugin==1.2.1 -mkdocs-material==9.4.7 -mkdocs-material-extensions==1.3 -mkdocs-minify-plugin==0.7.1 -mkdocs-redirects==1.2.1 -mkdocs-simple-hooks==0.1.5 -nltk==3.8.1 -packaging==23.2 -plantuml==0.3.0 -plantuml-markdown==3.9.2 -Pygments==2.16.1 -pymdown-extensions==10.3.1 -pyparsing==3.1.1 -python-dateutil==2.8.2 -pytz==2023.3.post1 -PyYAML==6.0.1 -pyyaml_env_tag==0.1 -regex==2023.10.3 -requests==2.31.0 -six==1.16.0 -smmap==5.0.1 -tornado==6.3.3 -tqdm==4.66.1 -urllib3==2.0.7 -watchdog==3.0.0 -zipp==3.17.0 +wheel==0.45.1 + +mkdocs==1.6.1 # documentation framework +mkdocs-git-revision-date-localized-plugin==1.4.5 # plugin "git-revision-date-localized" +mkdocs-material==9.6.11 # theme for mkdocs +mkdocs-material-extensions==1.3.1 # extensions +mkdocs-minify-plugin==0.8.0 # plugin "minify" +mkdocs-redirects==1.2.2 # plugin "redirects" +mkdocs-htmlproofer-plugin==1.3.0 # plugin "htmlproofer" + +PyYAML==6.0.2 # linter diff --git a/docs/mkdocs/scripts/check_structure.py b/docs/mkdocs/scripts/check_structure.py index 643482af2..c8d637d06 100755 --- a/docs/mkdocs/scripts/check_structure.py +++ b/docs/mkdocs/scripts/check_structure.py @@ -5,47 +5,49 @@ import os.path import re import sys +import yaml + warnings = 0 -def report(rule, location, description): +def report(rule, location, description) -> None: global warnings warnings += 1 print(f'{warnings:3}. {location}: {description} [{rule}]') -def check_structure(): +def check_structure() -> None: expected_sections = [ - 'Template parameters', - 'Specializations', - 'Iterator invalidation', - 'Requirements', - 'Member types', - 'Member functions', - 'Member variables', - 'Static functions', - 'Non-member functions', - 'Literals', - 'Helper classes', - 'Parameters', - 'Return value', - 'Exception safety', - 'Exceptions', - 'Complexity', - 'Possible implementation', - 'Default definition', - 'Notes', - 'Examples', - 'See also', - 'Version history' + "Template parameters", + "Specializations", + "Iterator invalidation", + "Requirements", + "Member types", + "Member functions", + "Member variables", + "Static functions", + "Non-member functions", + "Literals", + "Helper classes", + "Parameters", + "Return value", + "Exception safety", + "Exceptions", + "Complexity", + "Possible implementation", + "Default definition", + "Notes", + "Examples", + "See also", + "Version history", ] required_sections = [ - 'Examples', - 'Version history' + "Examples", + "Version history", ] - files = sorted(glob.glob('api/**/*.md', recursive=True)) + files = sorted(glob.glob("api/**/*.md", recursive=True)) for file in files: with open(file) as file_content: section_idx = -1 # the index of the current h2 section @@ -60,30 +62,30 @@ def check_structure(): for lineno, original_line in enumerate(file_content.readlines()): line = original_line.strip() - if line.startswith('# '): + if line.startswith("# "): h1sections += 1 # there should only be one top-level title if h1sections > 1: - report('structure/unexpected_section', f'{file}:{lineno+1}', f'unexpected top-level title "{line}"') + report("structure/unexpected_section", f"{file}:{lineno+1}", f'unexpected top-level title "{line}"') h1sections = 1 # Overview pages should have a better title - if line == '# Overview': - report('style/title', f'{file}:{lineno+1}', 'overview pages should have a better title than "Overview"') + if line == "# Overview": + report("style/title", f"{file}:{lineno+1}", 'overview pages should have a better title than "Overview"') # lines longer than 160 characters are bad (unless they are tables) - if len(line) > 160 and '|' not in line: - report('whitespace/line_length', f'{file}:{lineno+1} ({current_section})', f'line is too long ({len(line)} vs. 160 chars)') + if len(line) > 160 and "|" not in line: + report("whitespace/line_length", f"{file}:{lineno+1} ({current_section})", f"line is too long ({len(line)} vs. 160 chars)") # sections in `` comments are treated as present - if line.startswith('') + if line.startswith("") existing_sections.append(current_section) # check if sections are correct - if line.startswith('## '): + if line.startswith("## "): # before starting a new section, check if the previous one documented all overloads if current_section in documented_overloads and last_overload != 0: if len(documented_overloads[current_section]) > 0 and len(documented_overloads[current_section]) != last_overload: @@ -91,21 +93,20 @@ def check_structure(): undocumented = [x for x in expected if x not in documented_overloads[current_section]] unexpected = [x for x in documented_overloads[current_section] if x not in expected] if len(undocumented): - report('style/numbering', f'{file}:{lineno} ({current_section})', f'undocumented overloads: {", ".join([f"({x})" for x in undocumented])}') + report("style/numbering", f"{file}:{lineno} ({current_section})", f'undocumented overloads: {", ".join([f"({x})" for x in undocumented])}') if len(unexpected): - report('style/numbering', f'{file}:{lineno} ({current_section})', f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}') + report("style/numbering", f"{file}:{lineno} ({current_section})", f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}') - current_section = line.strip('## ') + current_section = line.strip("## ") existing_sections.append(current_section) if current_section in expected_sections: idx = expected_sections.index(current_section) if idx <= section_idx: - report('structure/section_order', f'{file}:{lineno+1}', f'section "{current_section}" is in an unexpected order (should be before "{expected_sections[section_idx]}")') + report("structure/section_order", f"{file}:{lineno+1}", f'section "{current_section}" is in an unexpected order (should be before "{expected_sections[section_idx]}")') section_idx = idx - else: - if 'index.md' not in file: # index.md files may have a different structure - report('structure/unknown_section', f'{file}:{lineno+1}', f'section "{current_section}" is not part of the expected sections') + elif "index.md" not in file: # index.md files may have a different structure + report("structure/unknown_section", f"{file}:{lineno+1}", f'section "{current_section}" is not part of the expected sections') # collect the numbered items of the current section to later check if they match the number of overloads if last_overload != 0 and not in_initial_code_example: @@ -116,64 +117,106 @@ def check_structure(): documented_overloads[current_section].append(number) # code example - if line == '```cpp' and section_idx == -1: + if line == "```cpp" and section_idx == -1: in_initial_code_example = True - if in_initial_code_example and line.startswith('//') and line not in ['// since C++20', '// until C++20']: + if in_initial_code_example and line.startswith("//") and line not in ["// since C++20", "// until C++20"]: # check numbering of overloads if any(map(str.isdigit, line)): - number = int(re.findall(r'\d+', line)[0]) + number = int(re.findall(r"\d+", line)[0]) if number != last_overload + 1: - report('style/numbering', f'{file}:{lineno+1}', f'expected number ({number}) to be ({last_overload +1 })') + report("style/numbering", f"{file}:{lineno+1}", f"expected number ({number}) to be ({last_overload +1 })") last_overload = number - if any(map(str.isdigit, line)) and '(' not in line: - report('style/numbering', f'{file}:{lineno+1}', f'number should be in parentheses: {line}') + if any(map(str.isdigit, line)) and "(" not in line: + report("style/numbering", f"{file}:{lineno+1}", f"number should be in parentheses: {line}") - if line == '```' and in_initial_code_example: + if line == "```" and in_initial_code_example: in_initial_code_example = False # consecutive blank lines are bad - if line == '' and previous_line == '': - report('whitespace/blank_lines', f'{file}:{lineno}-{lineno+1} ({current_section})', 'consecutive blank lines') + if line == "" and previous_line == "": + report("whitespace/blank_lines", f"{file}:{lineno}-{lineno+1} ({current_section})", "consecutive blank lines") # check that non-example admonitions have titles - untitled_admonition = re.match(r'^(\?\?\?|!!!) ([^ ]+)$', line) - if untitled_admonition and untitled_admonition.group(2) != 'example': - report('style/admonition_title', f'{file}:{lineno} ({current_section})', f'"{untitled_admonition.group(2)}" admonitions should have a title') + untitled_admonition = re.match(r"^(\?\?\?|!!!) ([^ ]+)$", line) + if untitled_admonition and untitled_admonition.group(2) != "example": + report("style/admonition_title", f"{file}:{lineno} ({current_section})", f'"{untitled_admonition.group(2)}" admonitions should have a title') previous_line = line - if 'index.md' not in file: # index.md files may have a different structure + if "index.md" not in file: # index.md files may have a different structure for required_section in required_sections: if required_section not in existing_sections: - report('structure/missing_section', f'{file}:{lineno+1}', f'required section "{required_section}" was not found') + report("structure/missing_section", f"{file}:{lineno+1}", f'required section "{required_section}" was not found') -def check_examples(): - example_files = sorted(glob.glob('../../examples/*.cpp')) - markdown_files = sorted(glob.glob('**/*.md', recursive=True)) +def check_examples() -> None: + example_files = sorted(glob.glob("../../examples/*.cpp")) + markdown_files = sorted(glob.glob("**/*.md", recursive=True)) # check if every example file is used in at least one markdown file for example_file in example_files: - example_file = os.path.join('examples', os.path.basename(example_file)) + example_file = os.path.join("examples", os.path.basename(example_file)) found = False for markdown_file in markdown_files: - content = ' '.join(open(markdown_file).readlines()) + content = " ".join(open(markdown_file).readlines()) if example_file in content: found = True break if not found: - report('examples/missing', f'{example_file}', 'example file is not used in any documentation file') + report("examples/missing", f"{example_file}", "example file is not used in any documentation file") -if __name__ == '__main__': - print(120 * '-') +def check_links() -> None: + """Check that every entry in the navigation (nav in mkdocs.yml) links to at most one file. If a file is linked more + than once, then the first entry is repeated. See https://github.com/nlohmann/json/issues/4564 for the issue in + this project and https://github.com/mkdocs/mkdocs/issues/3428 for the root cause. + + The issue can be fixed by merging the keys, so + + - 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md + - 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md + + would be replaced with + + - 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md + """ + file_with_path = {} + + def collect_links(node, path="") -> None: + if isinstance(node, list): + for x in node: + collect_links(x, path) + elif isinstance(node, dict): + for p, x in node.items(): + collect_links(x, path + "/" + p) + else: + if node not in file_with_path: + file_with_path[node] = [] + file_with_path[node].append(path) + + with open("../mkdocs.yml") as mkdocs_file: + # see https://github.com/yaml/pyyaml/issues/86#issuecomment-1042485535 + yaml.add_multi_constructor("tag:yaml.org,2002:python/name", lambda loader, suffix, node: None, Loader=yaml.SafeLoader) + yaml.add_multi_constructor("!ENV", lambda loader, suffix, node: None, Loader=yaml.SafeLoader) + y = yaml.safe_load(mkdocs_file) + + collect_links(y["nav"]) + for duplicate_file in [x for x in file_with_path if len(file_with_path[x]) > 1]: + file_list = [f'"{x}"' for x in file_with_path[duplicate_file]] + file_list_str = ", ".join(file_list) + report("nav/duplicate_files", "mkdocs.yml", f'file "{duplicate_file}" is linked with multiple keys in "nav": {file_list_str}; only one is rendered properly, see #4564') + + +if __name__ == "__main__": + print(120 * "-") check_structure() check_examples() - print(120 * '-') + check_links() + print(120 * "-") if warnings > 0: sys.exit(1) diff --git a/docs/usages/ios.png b/docs/usages/ios.png deleted file mode 100755 index 1d2c1b807..000000000 Binary files a/docs/usages/ios.png and /dev/null differ diff --git a/docs/usages/macos.png b/docs/usages/macos.png deleted file mode 100644 index 107b5f07f..000000000 Binary files a/docs/usages/macos.png and /dev/null differ diff --git a/include/nlohmann/adl_serializer.hpp b/include/nlohmann/adl_serializer.hpp index 56a606c0f..5df1af3de 100644 --- a/include/nlohmann/adl_serializer.hpp +++ b/include/nlohmann/adl_serializer.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index 91382cd68..d6398e626 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/abi_macros.hpp b/include/nlohmann/detail/abi_macros.hpp index f48b9eb1d..76cf336fc 100644 --- a/include/nlohmann/detail/abi_macros.hpp +++ b/include/nlohmann/detail/abi_macros.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -12,20 +12,24 @@ #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 #warning "Already included a different version of the library!" #endif #endif #endif #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) #ifndef JSON_DIAGNOSTICS #define JSON_DIAGNOSTICS 0 #endif +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif @@ -36,6 +40,12 @@ #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS #endif +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp #else @@ -47,14 +57,15 @@ #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index aa2f0cbf4..d647d7423 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -13,6 +13,9 @@ #include // forward_list #include // inserter, front_inserter, end #include // map +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -43,6 +46,24 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) n = nullptr; } +#ifdef JSON_HAS_CPP_17 +#ifndef JSON_USE_IMPLICIT_CONVERSIONS +template +void from_json(const BasicJsonType& j, std::optional& opt) +{ + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt.emplace(j.template get()); + } +} + +#endif // JSON_USE_IMPLICIT_CONVERSIONS +#endif // JSON_HAS_CPP_17 + // overloads for basic_json template parameters template < typename BasicJsonType, typename ArithmeticType, enable_if_t < std::is_arithmetic::value&& @@ -190,6 +211,54 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines } } +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + arr[i1][i2] = j.at(i1).at(i2).template get(); + } + } +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get(); + } + } + } +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + for (std::size_t i4 = 0; i4 < N4; ++i4) + { + arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get(); + } + } + } + } +} + template inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { @@ -275,7 +344,7 @@ void()) template < typename BasicJsonType, typename T, std::size_t... Idx > std::array from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag> /*unused*/, index_sequence /*unused*/) + identity_tag> /*unused*/, index_sequence /*unused*/) { return { { std::forward(j).at(Idx).template get()... } }; } @@ -379,6 +448,12 @@ std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence< return std::make_tuple(std::forward(j).at(Idx).template get()...); } +template +std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/) +{ + return {}; +} + template < typename BasicJsonType, class A1, class A2 > std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) { @@ -464,7 +539,12 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) { JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } - p = *j.template get_ptr(); + const auto& s = *j.template get_ptr(); +#ifdef JSON_HAS_CPP_20 + p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); +#else + p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 +#endif } #endif diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index e10741c92..743104174 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -1,10 +1,10 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2009 Florian Loitsch -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -239,10 +239,10 @@ boundaries compute_boundaries(FloatType value) // v- m- v m+ v+ const bool lower_boundary_is_closer = F == 0 && E > 1; - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_plus = diyfp((2 * v.f) + 1, v.e - 1); const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) + ? diyfp((4 * v.f) - 1, v.e - 2) // (B) + : diyfp((2 * v.f) - 1, v.e - 1); // (A) // Determine the normalized w+ = m+. const diyfp w_plus = diyfp::normalize(m_plus); @@ -472,7 +472,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) JSON_ASSERT(e >= -1500); JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + const int k = ((f * 78913) / (1 << 18)) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; JSON_ASSERT(index >= 0); @@ -950,15 +950,15 @@ inline char* append_exponent(char* buf, int e) } else if (k < 100) { - *buf++ = static_cast('0' + k / 10); + *buf++ = static_cast('0' + (k / 10)); k %= 10; *buf++ = static_cast('0' + k); } else { - *buf++ = static_cast('0' + k / 100); + *buf++ = static_cast('0' + (k / 100)); k %= 100; - *buf++ = static_cast('0' + k / 10); + *buf++ = static_cast('0' + (k / 10)); k %= 10; *buf++ = static_cast('0' + k); } diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index e39b7797d..ead45665f 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -1,13 +1,18 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once +#include // JSON_HAS_CPP_17 +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif + #include // copy #include // begin, end #include // string @@ -18,7 +23,6 @@ #include // vector #include -#include #include #include #include @@ -260,6 +264,22 @@ struct external_constructor // to_json // ///////////// +#ifdef JSON_HAS_CPP_17 +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::optional& opt) +{ + if (opt.has_value()) + { + j = *opt; + } + else + { + j = nullptr; + } +} +#endif + template::value, int> = 0> inline void to_json(BasicJsonType& j, T b) noexcept @@ -320,7 +340,8 @@ template::type; - external_constructor::construct(j, static_cast(e)); + static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; + external_constructor::construct(j, static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -405,6 +426,13 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence< j = { std::get(t)... }; } +template +inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/) +{ + using array_t = typename BasicJsonType::array_t; + j = array_t(); +} + template::value, int > = 0> inline void to_json(BasicJsonType& j, const T& t) { @@ -415,7 +443,12 @@ inline void to_json(BasicJsonType& j, const T& t) template inline void to_json(BasicJsonType& j, const std_fs::path& p) { - j = p.string(); +#ifdef JSON_HAS_CPP_20 + const std::u8string s = p.u8string(); + j = std::string(s.begin(), s.end()); +#else + j = p.u8string(); // returns std::string in C++17 +#endif } #endif diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp index 5974d7be2..5ebfb6578 100644 --- a/include/nlohmann/detail/exceptions.hpp +++ b/include/nlohmann/detail/exceptions.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -25,6 +25,18 @@ #include #include +// With -Wweak-vtables, Clang will complain about the exception classes as they +// have no out-of-line virtual method definitions and their vtable will be +// emitted in every translation unit. This issue cannot be fixed with a +// header-only library as there is no implementation file to move these +// functions to. As a result, we suppress this warning here to avoid client +// code to stumble over this. See https://github.com/nlohmann/json/issues/4087 +// for a discussion. +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wweak-vtables" +#endif + NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -119,16 +131,34 @@ class exception : public std::exception { return concat(a, '/', detail::escape(b)); }); - return concat('(', str, ") "); + + return concat('(', str, ") ", get_byte_positions(leaf_element)); #else - static_cast(leaf_element); - return ""; + return get_byte_positions(leaf_element); #endif } private: /// an exception object as storage for error messages std::runtime_error m; +#if JSON_DIAGNOSTIC_POSITIONS + template + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos)) + { + return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") "); + } + return ""; + } +#else + template + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + static_cast(leaf_element); + return ""; + } +#endif }; /// @brief exception indicating a parse error @@ -255,3 +285,7 @@ class other_error : public exception } // namespace detail NLOHMANN_JSON_NAMESPACE_END + +#if defined(__clang__) + #pragma clang diagnostic pop +#endif diff --git a/include/nlohmann/detail/hash.hpp b/include/nlohmann/detail/hash.hpp index 4464e8e67..973943ec2 100644 --- a/include/nlohmann/detail/hash.hpp +++ b/include/nlohmann/detail/hash.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index a6e100e76..2120cf9a4 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -20,6 +20,9 @@ #include // char_traits, string #include // make_pair, move #include // vector +#ifdef __cpp_lib_byteswap + #include //byteswap +#endif #include #include @@ -62,7 +65,7 @@ static inline bool little_endianness(int num = 1) noexcept /*! @brief deserialization of CBOR, MessagePack, and UBJSON values */ -template> +template> class binary_reader { using number_integer_t = typename BasicJsonType::number_integer_t; @@ -169,7 +172,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -325,6 +328,12 @@ class binary_reader return get_number(input_format_t::bson, value) && sax->number_integer(value); } + case 0x11: // uint64 + { + std::uint64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_unsigned(value); + } + default: // anything else not supported (yet) { std::array cr{{}}; @@ -391,7 +400,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -651,7 +660,7 @@ class binary_reader } case 0x9F: // array (indefinite length) - return get_cbor_array(static_cast(-1), tag_handler); + return get_cbor_array(detail::unknown_size(), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -705,7 +714,7 @@ class binary_reader } case 0xBF: // map (indefinite length) - return get_cbor_object(static_cast(-1), tag_handler); + return get_cbor_object(detail::unknown_size(), tag_handler); case 0xC6: // tagged item case 0xC7: @@ -1093,7 +1102,7 @@ class binary_reader } /*! - @param[in] len the length of the array or static_cast(-1) for an + @param[in] len the length of the array or detail::unknown_size() for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed @@ -1106,7 +1115,7 @@ class binary_reader return false; } - if (len != static_cast(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -1131,7 +1140,7 @@ class binary_reader } /*! - @param[in] len the length of the object or static_cast(-1) for an + @param[in] len the length of the object or detail::unknown_size() for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed @@ -1147,7 +1156,7 @@ class binary_reader if (len != 0) { string_t key; - if (len != static_cast(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -2310,6 +2319,16 @@ class binary_reader case 'Z': // null return sax->null(); + case 'B': // byte + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + case 'U': { std::uint8_t number{}; @@ -2510,7 +2529,7 @@ class binary_reader return false; } - if (size_and_type.second == 'C') + if (size_and_type.second == 'C' || size_and_type.second == 'B') { size_and_type.second = 'U'; } @@ -2532,6 +2551,13 @@ class binary_reader return (sax->end_array() && sax->end_object()); } + // If BJData type marker is 'B' decode as binary + if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') + { + binary_t result; + return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + } + if (size_and_type.first != npos) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) @@ -2565,7 +2591,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -2643,7 +2669,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -2754,6 +2780,29 @@ class binary_reader return current = ia.get_character(); } + /*! + @brief get_to read into a primitive type + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns false instead + + @return bool, whether the read was successful + */ + template + bool get_to(T& dest, const input_format_t format, const char* context) + { + auto new_chars_read = ia.get_elements(&dest); + chars_read += new_chars_read; + if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) + { + // in case of failure, advance position by 1 to report failing location + ++chars_read; + sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + return false; + } + return true; + } + /*! @return character read from the input after ignoring all 'N' entries */ @@ -2768,6 +2817,28 @@ class binary_reader return current; } + template + static void byte_swap(NumberType& number) + { + constexpr std::size_t sz = sizeof(number); +#ifdef __cpp_lib_byteswap + if constexpr (sz == 1) + { + return; + } + if constexpr(std::is_integral_v) + { + number = std::byteswap(number); + return; + } +#endif + auto* ptr = reinterpret_cast(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } + } + /* @brief read a number from the input @@ -2786,29 +2857,16 @@ class binary_reader template bool get_number(const input_format_t format, NumberType& result) { - // step 1: read input into array with system's byte order - std::array vec{}; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) + // read in the original format + + if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) - { - return false; - } - - // reverse byte order prior to conversion if necessary - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } + return false; + } + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + byte_swap(result); } - - // step 2: convert array into number of type T and return - std::memcpy(&result, vec.data(), sizeof(NumberType)); return true; } @@ -2947,7 +3005,7 @@ class binary_reader } private: - static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast(-1); + static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size(); /// input adapter InputAdapterType ia; @@ -2973,6 +3031,7 @@ class binary_reader #define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ make_array( \ + bjd_type{'B', "byte"}, \ bjd_type{'C', "char"}, \ bjd_type{'D', "double"}, \ bjd_type{'I', "int16"}, \ diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 33fca3e4b..1affd619e 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -23,6 +23,7 @@ #include // istream #endif // JSON_NO_IO +#include #include #include #include @@ -67,6 +68,13 @@ class file_input_adapter return std::fgetc(m_file); } + // returns the number of characters successfully read + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + return fread(dest, 1, sizeof(T) * count, m_file); + } + private: /// the file pointer to read from std::FILE* m_file; @@ -126,6 +134,17 @@ class input_stream_adapter return res; } + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto res = static_cast(sb->sgetn(reinterpret_cast(dest), static_cast(count * sizeof(T)))); + if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T))) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + private: /// the associated input stream std::istream* is = nullptr; @@ -157,6 +176,26 @@ class iterator_input_adapter return char_traits::eof(); } + // for general iterators, we cannot really do something better than falling back to processing the range one-by-one + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto* ptr = reinterpret_cast(dest); + for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index) + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + ptr[read_index] = static_cast(*current); + std::advance(current, 1); + } + else + { + return read_index; + } + } + return count * sizeof(T); + } + private: IteratorType current; IteratorType end; @@ -320,6 +359,13 @@ class wide_string_input_adapter return utf8_bytes[utf8_bytes_index++]; } + // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here + template + std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) + { + JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); + } + private: BaseInputAdapter base_adapter; @@ -416,10 +462,17 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory::create(container); } +// specialization for std::string +using string_input_adapter_type = decltype(input_adapter(std::declval())); + #ifndef JSON_NO_IO // Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { + if (file == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } return file_input_adapter(file); } @@ -446,9 +499,13 @@ template < typename CharT, int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { + if (b == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } auto length = std::strlen(reinterpret_cast(b)); const auto* ptr = reinterpret_cast(b); - return input_adapter(ptr, ptr + length); + return input_adapter(ptr, ptr + length); // cppcheck-suppress[nullPointerArithmeticRedundantCheck] } template diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index c772521cd..0ff877893 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -1,22 +1,23 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include #include // string +#include // enable_if_t #include // move #include // vector #include +#include #include #include - NLOHMANN_JSON_NAMESPACE_BEGIN /*! @@ -144,6 +145,11 @@ struct json_sax namespace detail { +constexpr std::size_t unknown_size() +{ + return (std::numeric_limits::max)(); +} + /*! @brief SAX implementation to create a JSON value from SAX events @@ -157,7 +163,7 @@ constructor contains the parsed value. @tparam BasicJsonType the JSON type */ -template +template class json_sax_dom_parser { public: @@ -166,14 +172,15 @@ class json_sax_dom_parser using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; + using lexer_t = lexer; /*! @param[in,out] r reference to a JSON value that is manipulated while parsing @param[in] allow_exceptions_ whether parse errors yield exceptions */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true, lexer_t* lexer_ = nullptr) + : root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) {} // make class move-only @@ -229,7 +236,18 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } @@ -252,6 +270,14 @@ class json_sax_dom_parser JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_object()); +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; @@ -261,7 +287,16 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } @@ -274,6 +309,14 @@ class json_sax_dom_parser JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_array()); +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; @@ -298,6 +341,75 @@ class json_sax_dom_parser } private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + // As we handle the start and end positions for values created during parsing, + // we do not expect the following value type to be called. Regardless, set the positions + // in case this is created manually or through a different constructor. Exclude from lcov + // since the exact condition of this switch is esoteric. + // LCOV_EXCL_START + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + // LCOV_EXCL_STOP + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + /*! @invariant If the ref stack is empty, then the passed value will be the new root. @@ -311,6 +423,11 @@ class json_sax_dom_parser if (ref_stack.empty()) { root = BasicJsonType(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(root); +#endif + return &root; } @@ -319,12 +436,22 @@ class json_sax_dom_parser if (ref_stack.back()->is_array()) { ref_stack.back()->m_data.m_value.array->emplace_back(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back()); +#endif + return &(ref_stack.back()->m_data.m_value.array->back()); } JSON_ASSERT(ref_stack.back()->is_object()); JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(*object_element); +#endif + return object_element; } @@ -338,9 +465,11 @@ class json_sax_dom_parser bool errored = false; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; }; -template +template class json_sax_dom_callback_parser { public: @@ -351,11 +480,13 @@ class json_sax_dom_callback_parser using binary_t = typename BasicJsonType::binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; + using lexer_t = lexer; json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) + parser_callback_t cb, + const bool allow_exceptions_ = true, + lexer_t* lexer_ = nullptr) + : root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) { keep_stack.push_back(true); } @@ -418,12 +549,26 @@ class json_sax_dom_callback_parser auto val = handle_value(BasicJsonType::value_t::object, true); ref_stack.push_back(val.second); - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back()) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check object limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + } return true; } @@ -452,9 +597,23 @@ class json_sax_dom_callback_parser { // discard object *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded object. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif } else { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); } } @@ -488,10 +647,25 @@ class json_sax_dom_callback_parser auto val = handle_value(BasicJsonType::value_t::array, true); ref_stack.push_back(val.second); - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back()) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the array, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check array limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } } return true; @@ -506,12 +680,26 @@ class json_sax_dom_callback_parser keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); if (keep) { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); } else { // discard array *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded array. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif } } @@ -548,6 +736,71 @@ class json_sax_dom_callback_parser } private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + /*! @param[in] v value to add to the JSON value we build during parsing @param[in] skip_callback whether we should skip calling the callback @@ -578,6 +831,10 @@ class json_sax_dom_callback_parser // create value auto value = BasicJsonType(std::forward(v)); +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(value); +#endif + // check callback const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); @@ -632,9 +889,9 @@ class json_sax_dom_callback_parser /// stack to model hierarchy of values std::vector ref_stack {}; /// stack to manage which values to keep - std::vector keep_stack {}; + std::vector keep_stack {}; // NOLINT(readability-redundant-member-init) /// stack to manage which object keys to keep - std::vector key_keep_stack {}; + std::vector key_keep_stack {}; // NOLINT(readability-redundant-member-init) /// helper to hold the reference for the next object element BasicJsonType* object_element = nullptr; /// whether a syntax error occurred @@ -645,6 +902,8 @@ class json_sax_dom_callback_parser const bool allow_exceptions = true; /// a discarded value for the callback BasicJsonType discarded = BasicJsonType::value_t::discarded; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; }; template @@ -692,7 +951,7 @@ class json_sax_acceptor return true; } - bool start_object(std::size_t /*unused*/ = static_cast(-1)) + bool start_object(std::size_t /*unused*/ = detail::unknown_size()) { return true; } @@ -707,7 +966,7 @@ class json_sax_acceptor return true; } - bool start_array(std::size_t /*unused*/ = static_cast(-1)) + bool start_array(std::size_t /*unused*/ = detail::unknown_size()) { return true; } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 4b3bf77d6..2b4e80a48 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -967,7 +967,7 @@ class lexer : public lexer_base locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() // lgtm [cpp/use-of-goto] + token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated. { // reset token_buffer to store the number's bytes reset(); @@ -1049,6 +1049,7 @@ scan_number_zero: case '.': { add(decimal_point_char); + decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } @@ -1085,6 +1086,7 @@ scan_number_any1: case '.': { add(decimal_point_char); + decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } @@ -1245,7 +1247,7 @@ scan_number_done: // we are done scanning a number) unget(); - char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg) errno = 0; // try to parse integers first and fall back to floats @@ -1256,7 +1258,7 @@ scan_number_done: // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - if (errno == 0) + if (errno != ERANGE) { value_unsigned = static_cast(x); if (value_unsigned == x) @@ -1272,7 +1274,7 @@ scan_number_done: // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - if (errno == 0) + if (errno != ERANGE) { value_integer = static_cast(x); if (value_integer == x) @@ -1322,6 +1324,7 @@ scan_number_done: { token_buffer.clear(); token_string.clear(); + decimal_point_position = std::string::npos; token_string.push_back(char_traits::to_char_type(current)); } @@ -1430,6 +1433,11 @@ scan_number_done: /// return current string value (implicitly resets the token; useful only once) string_t& get_string() { + // translate decimal points from locale back to '.' (#4084) + if (decimal_point_char != '.' && decimal_point_position != std::string::npos) + { + token_buffer[decimal_point_position] = '.'; + } return token_buffer; } @@ -1627,6 +1635,8 @@ scan_number_done: /// the decimal point const char_int_type decimal_point_char = '.'; + /// the position of the decimal point in the input + std::size_t decimal_point_position = std::string::npos; }; } // namespace detail diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index bdf85ba29..b5a5a525c 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -69,10 +69,10 @@ class parser public: /// a parser reading from an input adapter explicit parser(InputAdapterType&& adapter, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions_ = true, const bool skip_comments = false) - : callback(cb) + : callback(std::move(cb)) , m_lexer(std::move(adapter), skip_comments) , allow_exceptions(allow_exceptions_) { @@ -94,7 +94,7 @@ class parser { if (callback) { - json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions, &m_lexer); sax_parse_internal(&sdp); // in strict mode, input must be completely read @@ -122,7 +122,7 @@ class parser } else { - json_sax_dom_parser sdp(result, allow_exceptions); + json_sax_dom_parser sdp(result, allow_exceptions, &m_lexer); sax_parse_internal(&sdp); // in strict mode, input must be completely read @@ -194,7 +194,7 @@ class parser { case token_type::begin_object: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -239,7 +239,7 @@ class parser case token_type::begin_array: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } diff --git a/include/nlohmann/detail/input/position_t.hpp b/include/nlohmann/detail/input/position_t.hpp index 8ac7c78cf..c26c5f434 100644 --- a/include/nlohmann/detail/input/position_t.hpp +++ b/include/nlohmann/detail/input/position_t.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/iterators/internal_iterator.hpp b/include/nlohmann/detail/iterators/internal_iterator.hpp index 2991ee693..9f3c8e6b8 100644 --- a/include/nlohmann/detail/iterators/internal_iterator.hpp +++ b/include/nlohmann/detail/iterators/internal_iterator.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 444709134..45864e8c3 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -463,7 +463,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator==(const IterImpl& other) const @@ -474,7 +474,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + return true; + } switch (m_object->m_data.m_type) { @@ -499,7 +503,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator!=(const IterImpl& other) const @@ -509,7 +513,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<(const iter_impl& other) const { @@ -519,7 +523,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false + return false; + } switch (m_object->m_data.m_type) { @@ -544,7 +553,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<=(const iter_impl& other) const { @@ -553,7 +562,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator>(const iter_impl& other) const { @@ -562,7 +571,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized. */ bool operator>=(const iter_impl& other) const { diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index 76293de22..78e0d8b03 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -1,16 +1,15 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include // size_t -#include // input_iterator_tag -#include // string, to_string +#include // forward_iterator_tag #include // tuple_size, get, tuple_element #include // move @@ -20,19 +19,13 @@ #include #include +#include #include NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -template -void int_to_string( string_type& target, std::size_t value ) -{ - // For ADL - using std::to_string; - target = to_string(value); -} template class iteration_proxy_value { public: @@ -40,7 +33,7 @@ template class iteration_proxy_value using value_type = iteration_proxy_value; using pointer = value_type *; using reference = value_type &; - using iterator_category = std::input_iterator_tag; + using iterator_category = std::forward_iterator_tag; using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; private: @@ -220,7 +213,7 @@ namespace std #endif template class tuple_size<::nlohmann::detail::iteration_proxy_value> // NOLINT(cert-dcl58-cpp) - : public std::integral_constant {}; + : public std::integral_constant {}; template class tuple_element> // NOLINT(cert-dcl58-cpp) diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp index 84cc27a85..5ca92a5e8 100644 --- a/include/nlohmann/detail/iterators/iterator_traits.hpp +++ b/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -43,7 +43,7 @@ struct iterator_traits template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> - : iterator_types + : iterator_types { }; diff --git a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp index 006d5499a..f979d8533 100644 --- a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp +++ b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/iterators/primitive_iterator.hpp b/include/nlohmann/detail/iterators/primitive_iterator.hpp index 0b6e8499e..3a238349b 100644 --- a/include/nlohmann/detail/iterators/primitive_iterator.hpp +++ b/include/nlohmann/detail/iterators/primitive_iterator.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/json_custom_base_class.hpp b/include/nlohmann/detail/json_custom_base_class.hpp index d1e29162a..91e0c80bc 100644 --- a/include/nlohmann/detail/json_custom_base_class.hpp +++ b/include/nlohmann/detail/json_custom_base_class.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 4fdcd9ad2..1f764979e 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -228,7 +228,7 @@ class json_pointer } const char* p = s.c_str(); - char* p_end = nullptr; + char* p_end = nullptr; // NOLINT(misc-const-correctness) errno = 0; // strtoull doesn't reset errno const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) if (p == p_end // invalid input or empty string @@ -750,7 +750,7 @@ class json_pointer // iterate array and use index as reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { - flatten(detail::concat(reference_string, '/', std::to_string(i)), + flatten(detail::concat(reference_string, '/', std::to_string(i)), value.m_data.m_value.array->operator[](i), result); } } @@ -769,7 +769,7 @@ class json_pointer // iterate object and use keys as reference string for (const auto& element : *value.m_data.m_value.object) { - flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); + flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); } } break; diff --git a/include/nlohmann/detail/json_ref.hpp b/include/nlohmann/detail/json_ref.hpp index b8bb6a76b..a9a68d9b3 100644 --- a/include/nlohmann/detail/json_ref.hpp +++ b/include/nlohmann/detail/json_ref.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 97127a646..d1c6b1be3 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -32,15 +32,20 @@ // C++ language standard detection // if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) + #define JSON_HAS_CPP_23 #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) + #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #define JSON_HAS_CPP_14 #endif // the cpp 11 flag is always specified because it is the minimal required version @@ -216,7 +221,9 @@ template \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [e](const std::pair& ej_pair) -> bool \ @@ -228,7 +235,9 @@ template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [&j](const std::pair& ej_pair) -> bool \ @@ -391,42 +400,146 @@ #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); -#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1; /*! @brief macro @def NLOHMANN_DEFINE_TYPE_INTRUSIVE @since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ */ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } /*! @brief macro @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ */ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } // inspired from https://stackoverflow.com/a/26745591 -// allows to call any std function as if (e.g. with begin): +// allows calling any std function as if (e.g., with begin): // using std::begin; begin(x); // // it allows using the detected idiom to retrieve the return type diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index c6620d1e2..2edb1686d 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -34,6 +34,7 @@ #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 + #undef JSON_HAS_CPP_23 #undef JSON_HAS_FILESYSTEM #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON diff --git a/include/nlohmann/detail/meta/call_std/begin.hpp b/include/nlohmann/detail/meta/call_std/begin.hpp index 364cc89d8..6e697b58e 100644 --- a/include/nlohmann/detail/meta/call_std/begin.hpp +++ b/include/nlohmann/detail/meta/call_std/begin.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/meta/call_std/end.hpp b/include/nlohmann/detail/meta/call_std/end.hpp index 463f07061..4d279146d 100644 --- a/include/nlohmann/detail/meta/call_std/end.hpp +++ b/include/nlohmann/detail/meta/call_std/end.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index 412b5aa74..57811b985 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-FileCopyrightText: 2018 The Abseil Authors // SPDX-License-Identifier: MIT @@ -162,7 +162,7 @@ struct static_const #endif template -inline constexpr std::array make_array(Args&& ... args) +constexpr std::array make_array(Args&& ... args) { return std::array {{static_cast(std::forward(args))...}}; } diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp index 1db9bf9ca..c394733e1 100644 --- a/include/nlohmann/detail/meta/detected.hpp +++ b/include/nlohmann/detail/meta/detected.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/meta/identity_tag.hpp b/include/nlohmann/detail/meta/identity_tag.hpp index 269deffb2..c39dabbac 100644 --- a/include/nlohmann/detail/meta/identity_tag.hpp +++ b/include/nlohmann/detail/meta/identity_tag.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/meta/is_sax.hpp b/include/nlohmann/detail/meta/is_sax.hpp index 4e02bc148..2574f72b9 100644 --- a/include/nlohmann/detail/meta/is_sax.hpp +++ b/include/nlohmann/detail/meta/is_sax.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/meta/std_fs.hpp b/include/nlohmann/detail/meta/std_fs.hpp index fd1803964..2f33e32d2 100644 --- a/include/nlohmann/detail/meta/std_fs.hpp +++ b/include/nlohmann/detail/meta/std_fs.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -19,7 +19,7 @@ namespace std_fs = std::experimental::filesystem; } // namespace detail NLOHMANN_JSON_NAMESPACE_END #elif JSON_HAS_FILESYSTEM -#include +#include // NOLINT(build/c++17) NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index e1b000dcc..d834a0d56 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -1,18 +1,18 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include // numeric_limits +#include // char_traits +#include // tuple #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval -#include // tuple -#include // char_traits #include #include @@ -211,7 +211,7 @@ struct char_traits : std::char_traits static constexpr int_type eof() noexcept { - return static_cast(EOF); + return static_cast(std::char_traits::eof()); } }; @@ -235,7 +235,7 @@ struct char_traits : std::char_traits static constexpr int_type eof() noexcept { - return static_cast(EOF); + return static_cast(std::char_traits::eof()); } }; @@ -261,19 +261,19 @@ struct is_default_constructible : std::is_default_constructible {}; template struct is_default_constructible> - : conjunction, is_default_constructible> {}; + : conjunction, is_default_constructible> {}; template struct is_default_constructible> - : conjunction, is_default_constructible> {}; + : conjunction, is_default_constructible> {}; template struct is_default_constructible> - : conjunction...> {}; + : conjunction...> {}; template struct is_default_constructible> - : conjunction...> {}; + : conjunction...> {}; template struct is_constructible : std::is_constructible {}; @@ -471,8 +471,8 @@ is_detected::value&& // special case for types like std::filesystem::path whose iterator's value_type are themselves // c.f. https://github.com/nlohmann/json/pull/3073 !std::is_same>::value&& - is_complete_type < - detected_t>::value >> +is_complete_type < +detected_t>::value >> { using value_type = range_value_t; @@ -595,12 +595,12 @@ using is_usable_as_key_type = typename std::conditional < template> using is_usable_as_basic_json_key_type = typename std::conditional < - is_usable_as_key_type::value - && !is_json_iterator_of::value, - std::true_type, - std::false_type >::type; + is_usable_as_key_type::value + && !is_json_iterator_of::value, + std::true_type, + std::false_type >::type; template using detect_erase_with_key_type = decltype(std::declval().erase(std::declval())); @@ -734,7 +734,7 @@ struct value_in_range_of_impl1 }; template -inline constexpr bool value_in_range_of(T val) +constexpr bool value_in_range_of(T val) { return value_in_range_of_impl1::test(val); } @@ -750,7 +750,7 @@ namespace impl { template -inline constexpr bool is_c_string() +constexpr bool is_c_string() { using TUnExt = typename std::remove_extent::type; using TUnCVExt = typename std::remove_cv::type; @@ -778,7 +778,7 @@ namespace impl { template -inline constexpr bool is_transparent() +constexpr bool is_transparent() { return is_detected::value; } diff --git a/include/nlohmann/detail/meta/void_t.hpp b/include/nlohmann/detail/meta/void_t.hpp index 99615c7c5..258475c49 100644 --- a/include/nlohmann/detail/meta/void_t.hpp +++ b/include/nlohmann/detail/meta/void_t.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index f475d57be..f81fa54c7 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -28,6 +28,13 @@ NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { +/// how to encode BJData +enum class bjdata_version_t +{ + draft2, + draft3, +}; + /////////////////// // binary writer // /////////////////// @@ -612,7 +619,7 @@ class binary_writer case value_t::binary: { // step 0: determine if the binary type has a set subtype to - // determine whether or not to use the ext or fixext types + // determine whether to use the ext or fixext types const bool use_ext = j.m_data.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length @@ -735,11 +742,14 @@ class binary_writer @param[in] use_type whether to use '$' prefixes (optimized format) @param[in] add_prefix whether prefixes need to be used for this value @param[in] use_bjdata whether write in BJData format, default is false + @param[in] bjdata_version which BJData version to use, default is draft2 */ void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true, - const bool use_bjdata = false) + const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2) { + const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3; + switch (j.type()) { case value_t::null: @@ -829,7 +839,7 @@ class binary_writer for (const auto& el : *j.m_data.m_value.array) { - write_ubjson(el, use_count, use_type, prefix_required, use_bjdata); + write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version); } if (!use_count) @@ -847,11 +857,11 @@ class binary_writer oa->write_character(to_char_type('[')); } - if (use_type && !j.m_data.m_value.binary->empty()) + if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty())) { JSON_ASSERT(use_count); oa->write_character(to_char_type('$')); - oa->write_character('U'); + oa->write_character(bjdata_draft3 ? 'B' : 'U'); } if (use_count) @@ -870,7 +880,7 @@ class binary_writer { for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i) { - oa->write_character(to_char_type('U')); + oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U')); oa->write_character(j.m_data.m_value.binary->data()[i]); } } @@ -887,7 +897,7 @@ class binary_writer { if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) { - if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) + if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) { break; } @@ -931,7 +941,7 @@ class binary_writer oa->write_characters( reinterpret_cast(el.first.c_str()), el.first.size()); - write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata); + write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version); } if (!use_count) @@ -1087,7 +1097,8 @@ class binary_writer } else { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); + write_bson_entry_header(name, 0x11 /* uint64 */); + write_number(static_cast(j.m_data.m_value.number_unsigned), true); } } @@ -1615,10 +1626,11 @@ class binary_writer /*! @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid */ - bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type) + bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type, const bjdata_version_t bjdata_version) { std::map bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, - {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'} + {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, + {"char", 'C'}, {"byte", 'B'} }; string_t key = "_ArrayType_"; @@ -1648,10 +1660,10 @@ class binary_writer oa->write_character('#'); key = "_ArraySize_"; - write_ubjson(value.at(key), use_count, use_type, true, true); + write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version); key = "_ArrayData_"; - if (dtype == 'U' || dtype == 'C') + if (dtype == 'U' || dtype == 'C' || dtype == 'B') { for (const auto& el : value.at(key)) { diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp index 626f7c0c8..608069702 100644 --- a/include/nlohmann/detail/output/output_adapters.hpp +++ b/include/nlohmann/detail/output/output_adapters.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index ed20b0d9e..3137f3c36 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -1,10 +1,10 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -643,7 +643,7 @@ class serializer @param[in] x unsigned integer number to count its digits @return number of decimal digits */ - inline unsigned int count_digits(number_unsigned_t x) noexcept + unsigned int count_digits(number_unsigned_t x) noexcept { unsigned int n_digits = 1; for (;;) @@ -926,7 +926,7 @@ class serializer ? (byte & 0x3fu) | (codep << 6u) : (0xFFu >> type) & (byte); - const std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); + const std::size_t index = 256u + (static_cast(state) * 16u) + static_cast(type); JSON_ASSERT(index < utf8d.size()); state = utf8d[index]; return state; @@ -952,7 +952,7 @@ class serializer * absolute values of INT_MIN and INT_MAX are usually not the same. See * #1708 for details. */ - inline number_unsigned_t remove_sign(number_integer_t x) noexcept + number_unsigned_t remove_sign(number_integer_t x) noexcept { JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) return static_cast(-(x + 1)) + 1; diff --git a/include/nlohmann/detail/string_concat.hpp b/include/nlohmann/detail/string_concat.hpp index f49e8d215..78569a8ad 100644 --- a/include/nlohmann/detail/string_concat.hpp +++ b/include/nlohmann/detail/string_concat.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/string_escape.hpp b/include/nlohmann/detail/string_escape.hpp index 7f1b5c562..7f0231819 100644 --- a/include/nlohmann/detail/string_escape.hpp +++ b/include/nlohmann/detail/string_escape.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/detail/string_utils.hpp b/include/nlohmann/detail/string_utils.hpp new file mode 100644 index 000000000..d8ecc0cba --- /dev/null +++ b/include/nlohmann/detail/string_utils.hpp @@ -0,0 +1,37 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t +#include // string, to_string + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +void int_to_string(StringType& target, std::size_t value) +{ + // For ADL + using std::to_string; + target = to_string(value); +} + +template +StringType to_string(std::size_t value) +{ + StringType result; + int_to_string(result, value); + return result; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/include/nlohmann/detail/value_t.hpp b/include/nlohmann/detail/value_t.hpp index 07688fe8c..4bd87abd2 100644 --- a/include/nlohmann/detail/value_t.hpp +++ b/include/nlohmann/detail/value_t.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 95d6bf1dd..ed51cd544 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /****************************************************************************\ @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -114,9 +115,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec friend class ::nlohmann::detail::binary_writer; template friend class ::nlohmann::detail::binary_reader; - template + template friend class ::nlohmann::detail::json_sax_dom_parser; - template + template friend class ::nlohmann::detail::json_sax_dom_callback_parser; friend class ::nlohmann::detail::exception; @@ -137,7 +138,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ) { return ::nlohmann::detail::parser(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); + std::move(cb), allow_exceptions, ignore_comments); } private: @@ -170,6 +171,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec using error_handler_t = detail::error_handler_t; /// how to treat CBOR tags using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// how to encode BJData + using bjdata_version_t = detail::bjdata_version_t; /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; @@ -249,7 +252,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { basic_json result; - result["copyright"] = "(C) 2013-2023 Niels Lohmann"; + result["copyright"] = "(C) 2013-2025 Niels Lohmann"; result["name"] = "JSON for Modern C++"; result["url"] = "https://github.com/nlohmann/json"; result["version"]["string"] = @@ -514,7 +517,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE } break; } @@ -750,10 +753,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return it; } - reference set_parent(reference j, std::size_t old_capacity = static_cast(-1)) + reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size()) { #if JSON_DIAGNOSTICS - if (old_capacity != static_cast(-1)) + if (old_capacity != detail::unknown_size()) { // see https://github.com/nlohmann/json/issues/2838 JSON_ASSERT(type() == value_t::array); @@ -847,6 +850,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::enable_if_t < detail::is_basic_json::value&& !std::is_same::value, int > = 0 > basic_json(const BasicJsonType& val) +#if JSON_DIAGNOSTIC_POSITIONS + : start_position(val.start_pos()), + end_position(val.end_pos()) +#endif { using other_boolean_t = typename BasicJsonType::boolean_t; using other_number_float_t = typename BasicJsonType::number_float_t; @@ -893,6 +900,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } JSON_ASSERT(m_data.m_type == val.type()); + set_parents(); assert_invariant(); } @@ -1029,7 +1037,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class InputIT, typename std::enable_if < std::is_same::value || std::is_same::value, int >::type = 0 > - basic_json(InputIT first, InputIT last) + basic_json(InputIT first, InputIT last) // NOLINT(performance-unnecessary-value-param) { JSON_ASSERT(first.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr); @@ -1144,6 +1152,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ basic_json(const basic_json& other) : json_base_class_t(other) +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) + , end_position(other.end_position) +#endif { m_data.m_type = other.m_data.m_type; // check of passed value is valid @@ -1213,15 +1225,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ basic_json(basic_json&& other) noexcept : json_base_class_t(std::forward(other)), - m_data(std::move(other.m_data)) + m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check + , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check +#endif { // check that passed value is valid - other.assert_invariant(false); + other.assert_invariant(false); // cppcheck-suppress[accessForwarded] // invalidate payload other.m_data.m_type = value_t::null; other.m_data.m_value = {}; +#if JSON_DIAGNOSTIC_POSITIONS + other.start_position = std::string::npos; + other.end_position = std::string::npos; +#endif + set_parents(); assert_invariant(); } @@ -1242,6 +1263,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec using std::swap; swap(m_data.m_type, other.m_data.m_type); swap(m_data.m_value, other.m_data.m_value); + +#if JSON_DIAGNOSTIC_POSITIONS + swap(start_position, other.start_position); + swap(end_position, other.end_position); +#endif + json_base_class_t::operator=(std::move(other)); set_parents(); @@ -1463,13 +1490,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) @@ -1948,7 +1975,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // create better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } + } // cppcheck-suppress[missingReturn] } else { @@ -1971,7 +1998,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // create better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } + } // cppcheck-suppress[missingReturn] } else { @@ -2116,7 +2143,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](typename object_t::key_type key) + reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param) { // implicitly convert null value to an empty object if (is_null()) @@ -2426,7 +2453,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class IteratorType, detail::enable_if_t < std::is_same::value || std::is_same::value, int > = 0 > - IteratorType erase(IteratorType pos) + IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) @@ -2496,7 +2523,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class IteratorType, detail::enable_if_t < std::is_same::value || std::is_same::value, int > = 0 > - IteratorType erase(IteratorType first, IteratorType last) + IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) @@ -3263,7 +3290,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @note: This uses std::distance to support GCC 4.8, /// see https://github.com/nlohmann/json/pull/1257 template - iterator insert_iterator(const_iterator pos, Args&& ... args) + iterator insert_iterator(const_iterator pos, Args&& ... args) // NOLINT(performance-unnecessary-value-param) { iterator result(this); JSON_ASSERT(m_data.m_value.array != nullptr); @@ -3282,7 +3309,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const basic_json& val) + iterator insert(const_iterator pos, const basic_json& val) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) @@ -3302,14 +3329,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, basic_json&& val) + iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param) { return insert(pos, val); } /// @brief inserts copies of element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) @@ -3329,7 +3356,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts range of elements into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) + iterator insert(const_iterator pos, const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) @@ -3360,7 +3387,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts elements from initializer list into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, initializer_list_t ilist) + iterator insert(const_iterator pos, initializer_list_t ilist) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) @@ -3380,7 +3407,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts range of elements into object /// @sa https://json.nlohmann.me/api/basic_json/insert/ - void insert(const_iterator first, const_iterator last) + void insert(const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) { // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) @@ -3401,6 +3428,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + set_parents(); } /// @brief updates a JSON object from another object, overwriting existing keys @@ -3412,7 +3440,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief updates a JSON object from another object, overwriting existing keys /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_iterator first, const_iterator last, bool merge_objects = false) + void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param) { // implicitly convert null value to an empty object if (is_null()) @@ -4013,12 +4041,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(InputType&& i, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] return result; } @@ -4028,24 +4056,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] return result; } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) static basic_json parse(detail::span_input_adapter&& i, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -4224,6 +4252,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec basic_json* m_parent = nullptr; #endif +#if JSON_DIAGNOSTIC_POSITIONS + /// the start position of the value + std::size_t start_position = std::string::npos; + /// the end position of the value + std::size_t end_position = std::string::npos; + public: + constexpr std::size_t start_pos() const noexcept + { + return start_position; + } + + constexpr std::size_t end_pos() const noexcept + { + return end_position; + } +#endif + ////////////////////////////////////////// // binary serialization/deserialization // ////////////////////////////////////////// @@ -4309,27 +4354,30 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static std::vector to_bjdata(const basic_json& j, const bool use_size = false, - const bool use_type = false) + const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { std::vector result; - to_bjdata(j, result, use_size, use_type); + to_bjdata(j, result, use_size, use_type, version); return result; } /// @brief create a BJData serialization of a given JSON value /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { - binary_writer(o).write_ubjson(j, use_size, use_type, true, true); + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); } /// @brief create a BJData serialization of a given JSON value /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { - binary_writer(o).write_ubjson(j, use_size, use_type, true, true); + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); } /// @brief create a BSON serialization of a given JSON value @@ -4365,9 +4413,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4381,9 +4429,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4406,10 +4454,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4422,9 +4470,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4437,9 +4485,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4460,10 +4508,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4476,9 +4524,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4491,9 +4539,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4514,10 +4562,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4530,9 +4578,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4545,9 +4593,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4560,9 +4608,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4575,9 +4623,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -4598,10 +4646,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } /// @} @@ -4702,7 +4750,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // the valid JSON Patch operations enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - const auto get_op = [](const std::string & op) + const auto get_op = [](const string_t& op) { if (op == "add") { @@ -4733,7 +4781,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec }; // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) + const auto operation_add = [&result](json_pointer & ptr, const basic_json & val) { // adding to the root of the target document means replacing it if (ptr.empty()) @@ -4839,15 +4887,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (const auto& val : json_patch) { // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, + const auto get_value = [&val](const string_t& op, + const string_t& member, bool string_type) -> basic_json & { // find value auto it = val.m_data.m_value.object->find(member); // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); + const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) // check if desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) @@ -4874,8 +4922,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // collect mandatory members - const auto op = get_value("op", "op", true).template get(); - const auto path = get_value(op, "path", true).template get(); + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); json_pointer ptr(path); switch (get_op(op)) @@ -4901,7 +4949,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case patch_operations::move: { - const auto from_path = get_value("move", "from", true).template get(); + const auto from_path = get_value("move", "from", true).template get(); json_pointer from_ptr(from_path); // the "from" location must exist - use at() @@ -4918,7 +4966,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case patch_operations::copy: { - const auto from_path = get_value("copy", "from", true).template get(); + const auto from_path = get_value("copy", "from", true).template get(); const json_pointer from_ptr(from_path); // the "from" location must exist - use at() @@ -4978,7 +5026,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/diff/ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") + const string_t& path = "") { // the patch basic_json result(value_t::array); @@ -5008,7 +5056,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec while (i < source.size() && i < target.size()) { // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i))); + auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', detail::to_string(i))); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); ++i; } @@ -5025,7 +5073,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.insert(result.begin() + end_index, object( { {"op", "remove"}, - {"path", detail::concat(path, '/', std::to_string(i))} + {"path", detail::concat(path, '/', detail::to_string(i))} })); ++i; } @@ -5036,7 +5084,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.push_back( { {"op", "add"}, - {"path", detail::concat(path, "/-")}, + {"path", detail::concat(path, "/-")}, {"value", target[i]} }); ++i; @@ -5051,7 +5099,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = source.cbegin(); it != source.cend(); ++it) { // escape the key name to be used in a JSON patch - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); if (target.find(it.key()) != target.end()) { @@ -5075,7 +5123,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (source.find(it.key()) == source.end()) { // found a key that is not in this -> add it - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); result.push_back( { {"op", "add"}, {"path", path_key}, diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index 32bde590f..a595ae4ab 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 39e4a50a1..d830c6d7e 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -26,7 +26,7 @@ NLOHMANN_JSON_NAMESPACE_BEGIN /// for use within nlohmann::basic_json template , class Allocator = std::allocator>> - struct ordered_map : std::vector, Allocator> + struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; @@ -341,7 +341,7 @@ template , template using require_input_iter = typename std::enable_if::iterator_category, - std::input_iterator_tag>::value>::type; + std::input_iterator_tag>::value>::type; template> void insert(InputIt first, InputIt last) diff --git a/include/nlohmann/thirdparty/hedley/hedley.hpp b/include/nlohmann/thirdparty/hedley/hedley.hpp index a1dc64f60..fb0b073b0 100644 --- a/include/nlohmann/thirdparty/hedley/hedley.hpp +++ b/include/nlohmann/thirdparty/hedley/hedley.hpp @@ -2,11 +2,11 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann -// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson // SPDX-License-Identifier: MIT /* Hedley - https://nemequ.github.io/hedley diff --git a/include/nlohmann/thirdparty/hedley/hedley_undef.hpp b/include/nlohmann/thirdparty/hedley/hedley_undef.hpp index c0aee2bb3..ad86d11f2 100644 --- a/include/nlohmann/thirdparty/hedley/hedley_undef.hpp +++ b/include/nlohmann/thirdparty/hedley/hedley_undef.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/meson.build b/meson.build index 7a9c5ec85..a2d6e31a2 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('nlohmann_json', 'cpp', - version : '3.11.3', + version : '3.12.0', license : 'MIT', ) diff --git a/nlohmann_json.natvis b/nlohmann_json.natvis index a831ea04b..09a46d67d 100644 --- a/nlohmann_json.natvis +++ b/nlohmann_json.natvis @@ -7,21 +7,21 @@ - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) @@ -37,21 +37,21 @@ - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) @@ -65,30 +65,30 @@ - - - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) - + {second} second @@ -97,21 +97,21 @@ - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) @@ -125,30 +125,30 @@ - - - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) - + {second} second @@ -157,21 +157,21 @@ - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) @@ -185,30 +185,30 @@ - - - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) - + {second} second @@ -217,21 +217,21 @@ - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) @@ -245,30 +245,30 @@ - - - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) - + {second} second diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8b72ea653..82d69f7c5 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /****************************************************************************\ @@ -34,10 +34,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -47,10 +47,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -59,20 +59,24 @@ #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 #warning "Already included a different version of the library!" #endif #endif #endif #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) #ifndef JSON_DIAGNOSTICS #define JSON_DIAGNOSTICS 0 #endif +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif @@ -83,6 +87,12 @@ #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS #endif +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp #else @@ -94,14 +104,15 @@ #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ @@ -149,10 +160,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -162,6 +173,9 @@ #include // forward_list #include // inserter, front_inserter, end #include // map +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -172,10 +186,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -192,10 +206,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -208,10 +222,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -220,10 +234,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -233,10 +247,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -320,11 +334,11 @@ NLOHMANN_JSON_NAMESPACE_END // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann -// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson // SPDX-License-Identifier: MIT /* Hedley - https://nemequ.github.io/hedley @@ -2384,15 +2398,20 @@ JSON_HEDLEY_DIAGNOSTIC_POP // C++ language standard detection // if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) + #define JSON_HAS_CPP_23 #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) + #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #define JSON_HAS_CPP_14 #endif // the cpp 11 flag is always specified because it is the minimal required version @@ -2568,7 +2587,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP template \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [e](const std::pair& ej_pair) -> bool \ @@ -2580,7 +2601,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [&j](const std::pair& ej_pair) -> bool \ @@ -2743,42 +2766,146 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); -#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1; /*! @brief macro @def NLOHMANN_DEFINE_TYPE_INTRUSIVE @since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ */ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } /*! @brief macro @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ */ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } // inspired from https://stackoverflow.com/a/26745591 -// allows to call any std function as if (e.g. with begin): +// allows calling any std function as if (e.g., with begin): // using std::begin; begin(x); // // it allows using the detected idiom to retrieve the return type @@ -2939,10 +3066,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -3014,10 +3141,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -3056,10 +3183,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-FileCopyrightText: 2018 The Abseil Authors // SPDX-License-Identifier: MIT @@ -3219,7 +3346,7 @@ struct static_const #endif template -inline constexpr std::array make_array(Args&& ... args) +constexpr std::array make_array(Args&& ... args) { return std::array {{static_cast(std::forward(args))...}}; } @@ -3230,27 +3357,27 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include // numeric_limits +#include // char_traits +#include // tuple #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval -#include // tuple -#include // char_traits // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -3293,7 +3420,7 @@ struct iterator_traits template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> - : iterator_types + : iterator_types { }; @@ -3315,10 +3442,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -3335,10 +3462,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -3359,10 +3486,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -3624,7 +3751,7 @@ struct char_traits : std::char_traits static constexpr int_type eof() noexcept { - return static_cast(EOF); + return static_cast(std::char_traits::eof()); } }; @@ -3648,7 +3775,7 @@ struct char_traits : std::char_traits static constexpr int_type eof() noexcept { - return static_cast(EOF); + return static_cast(std::char_traits::eof()); } }; @@ -3674,19 +3801,19 @@ struct is_default_constructible : std::is_default_constructible {}; template struct is_default_constructible> - : conjunction, is_default_constructible> {}; + : conjunction, is_default_constructible> {}; template struct is_default_constructible> - : conjunction, is_default_constructible> {}; + : conjunction, is_default_constructible> {}; template struct is_default_constructible> - : conjunction...> {}; + : conjunction...> {}; template struct is_default_constructible> - : conjunction...> {}; + : conjunction...> {}; template struct is_constructible : std::is_constructible {}; @@ -3884,8 +4011,8 @@ is_detected::value&& // special case for types like std::filesystem::path whose iterator's value_type are themselves // c.f. https://github.com/nlohmann/json/pull/3073 !std::is_same>::value&& - is_complete_type < - detected_t>::value >> +is_complete_type < +detected_t>::value >> { using value_type = range_value_t; @@ -4008,12 +4135,12 @@ using is_usable_as_key_type = typename std::conditional < template> using is_usable_as_basic_json_key_type = typename std::conditional < - is_usable_as_key_type::value - && !is_json_iterator_of::value, - std::true_type, - std::false_type >::type; + is_usable_as_key_type::value + && !is_json_iterator_of::value, + std::true_type, + std::false_type >::type; template using detect_erase_with_key_type = decltype(std::declval().erase(std::declval())); @@ -4147,7 +4274,7 @@ struct value_in_range_of_impl1 }; template -inline constexpr bool value_in_range_of(T val) +constexpr bool value_in_range_of(T val) { return value_in_range_of_impl1::test(val); } @@ -4163,7 +4290,7 @@ namespace impl { template -inline constexpr bool is_c_string() +constexpr bool is_c_string() { using TUnExt = typename std::remove_extent::type; using TUnCVExt = typename std::remove_cv::type; @@ -4191,7 +4318,7 @@ namespace impl { template -inline constexpr bool is_transparent() +constexpr bool is_transparent() { return is_detected::value; } @@ -4210,10 +4337,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -4358,6 +4485,18 @@ inline OutStringType concat(Args && ... args) NLOHMANN_JSON_NAMESPACE_END +// With -Wweak-vtables, Clang will complain about the exception classes as they +// have no out-of-line virtual method definitions and their vtable will be +// emitted in every translation unit. This issue cannot be fixed with a +// header-only library as there is no implementation file to move these +// functions to. As a result, we suppress this warning here to avoid client +// code to stumble over this. See https://github.com/nlohmann/json/issues/4087 +// for a discussion. +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wweak-vtables" +#endif + NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -4452,16 +4591,34 @@ class exception : public std::exception { return concat(a, '/', detail::escape(b)); }); - return concat('(', str, ") "); + + return concat('(', str, ") ", get_byte_positions(leaf_element)); #else - static_cast(leaf_element); - return ""; + return get_byte_positions(leaf_element); #endif } private: /// an exception object as storage for error messages std::runtime_error m; +#if JSON_DIAGNOSTIC_POSITIONS + template + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos)) + { + return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") "); + } + return ""; + } +#else + template + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + static_cast(leaf_element); + return ""; + } +#endif }; /// @brief exception indicating a parse error @@ -4589,6 +4746,10 @@ class other_error : public exception } // namespace detail NLOHMANN_JSON_NAMESPACE_END +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + // #include // #include @@ -4596,10 +4757,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -4620,10 +4781,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -4640,7 +4801,7 @@ namespace std_fs = std::experimental::filesystem; } // namespace detail NLOHMANN_JSON_NAMESPACE_END #elif JSON_HAS_FILESYSTEM -#include +#include // NOLINT(build/c++17) NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -4670,6 +4831,24 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) n = nullptr; } +#ifdef JSON_HAS_CPP_17 +#ifndef JSON_USE_IMPLICIT_CONVERSIONS +template +void from_json(const BasicJsonType& j, std::optional& opt) +{ + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt.emplace(j.template get()); + } +} + +#endif // JSON_USE_IMPLICIT_CONVERSIONS +#endif // JSON_HAS_CPP_17 + // overloads for basic_json template parameters template < typename BasicJsonType, typename ArithmeticType, enable_if_t < std::is_arithmetic::value&& @@ -4817,6 +4996,54 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines } } +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + arr[i1][i2] = j.at(i1).at(i2).template get(); + } + } +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get(); + } + } + } +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + for (std::size_t i4 = 0; i4 < N4; ++i4) + { + arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get(); + } + } + } + } +} + template inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { @@ -4902,7 +5129,7 @@ void()) template < typename BasicJsonType, typename T, std::size_t... Idx > std::array from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag> /*unused*/, index_sequence /*unused*/) + identity_tag> /*unused*/, index_sequence /*unused*/) { return { { std::forward(j).at(Idx).template get()... } }; } @@ -5006,6 +5233,12 @@ std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence< return std::make_tuple(std::forward(j).at(Idx).template get()...); } +template +std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/) +{ + return {}; +} + template < typename BasicJsonType, class A1, class A2 > std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) { @@ -5091,7 +5324,12 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) { JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } - p = *j.template get_ptr(); + const auto& s = *j.template get_ptr(); +#ifdef JSON_HAS_CPP_20 + p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); +#else + p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 +#endif } #endif @@ -5126,14 +5364,20 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT +// #include +// JSON_HAS_CPP_17 +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif + #include // copy #include // begin, end #include // string @@ -5146,17 +5390,16 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include // size_t -#include // input_iterator_tag -#include // string, to_string +#include // forward_iterator_tag #include // tuple_size, get, tuple_element #include // move @@ -5168,6 +5411,46 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t +#include // string, to_string + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +void int_to_string(StringType& target, std::size_t value) +{ + // For ADL + using std::to_string; + target = to_string(value); +} + +template +StringType to_string(std::size_t value) +{ + StringType result; + int_to_string(result, value); + return result; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + // #include @@ -5175,13 +5458,6 @@ NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -template -void int_to_string( string_type& target, std::size_t value ) -{ - // For ADL - using std::to_string; - target = to_string(value); -} template class iteration_proxy_value { public: @@ -5189,7 +5465,7 @@ template class iteration_proxy_value using value_type = iteration_proxy_value; using pointer = value_type *; using reference = value_type &; - using iterator_category = std::input_iterator_tag; + using iterator_category = std::forward_iterator_tag; using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; private: @@ -5369,7 +5645,7 @@ namespace std #endif template class tuple_size<::nlohmann::detail::iteration_proxy_value> // NOLINT(cert-dcl58-cpp) - : public std::integral_constant {}; + : public std::integral_constant {}; template class tuple_element> // NOLINT(cert-dcl58-cpp) @@ -5390,8 +5666,6 @@ class tuple_element> inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy> = true; #endif -// #include - // #include // #include @@ -5637,6 +5911,22 @@ struct external_constructor // to_json // ///////////// +#ifdef JSON_HAS_CPP_17 +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::optional& opt) +{ + if (opt.has_value()) + { + j = *opt; + } + else + { + j = nullptr; + } +} +#endif + template::value, int> = 0> inline void to_json(BasicJsonType& j, T b) noexcept @@ -5697,7 +5987,8 @@ template::type; - external_constructor::construct(j, static_cast(e)); + static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; + external_constructor::construct(j, static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -5782,6 +6073,13 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence< j = { std::get(t)... }; } +template +inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/) +{ + using array_t = typename BasicJsonType::array_t; + j = array_t(); +} + template::value, int > = 0> inline void to_json(BasicJsonType& j, const T& t) { @@ -5792,7 +6090,12 @@ inline void to_json(BasicJsonType& j, const T& t) template inline void to_json(BasicJsonType& j, const std_fs::path& p) { - j = p.string(); +#ifdef JSON_HAS_CPP_20 + const std::u8string s = p.u8string(); + j = std::string(s.begin(), s.end()); +#else + j = p.u8string(); // returns std::string in C++17 +#endif } #endif @@ -5867,10 +6170,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -5979,10 +6282,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -6112,10 +6415,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -6132,16 +6435,19 @@ NLOHMANN_JSON_NAMESPACE_END #include // char_traits, string #include // make_pair, move #include // vector +#ifdef __cpp_lib_byteswap + #include //byteswap +#endif // #include // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -6161,6 +6467,8 @@ NLOHMANN_JSON_NAMESPACE_END #include // istream #endif // JSON_NO_IO +// #include + // #include // #include @@ -6208,6 +6516,13 @@ class file_input_adapter return std::fgetc(m_file); } + // returns the number of characters successfully read + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + return fread(dest, 1, sizeof(T) * count, m_file); + } + private: /// the file pointer to read from std::FILE* m_file; @@ -6267,6 +6582,17 @@ class input_stream_adapter return res; } + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto res = static_cast(sb->sgetn(reinterpret_cast(dest), static_cast(count * sizeof(T)))); + if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T))) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + private: /// the associated input stream std::istream* is = nullptr; @@ -6298,6 +6624,26 @@ class iterator_input_adapter return char_traits::eof(); } + // for general iterators, we cannot really do something better than falling back to processing the range one-by-one + template + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto* ptr = reinterpret_cast(dest); + for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index) + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + ptr[read_index] = static_cast(*current); + std::advance(current, 1); + } + else + { + return read_index; + } + } + return count * sizeof(T); + } + private: IteratorType current; IteratorType end; @@ -6461,6 +6807,13 @@ class wide_string_input_adapter return utf8_bytes[utf8_bytes_index++]; } + // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here + template + std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) + { + JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); + } + private: BaseInputAdapter base_adapter; @@ -6557,10 +6910,17 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory::create(container); } +// specialization for std::string +using string_input_adapter_type = decltype(input_adapter(std::declval())); + #ifndef JSON_NO_IO // Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { + if (file == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } return file_input_adapter(file); } @@ -6587,9 +6947,13 @@ template < typename CharT, int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { + if (b == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } auto length = std::strlen(reinterpret_cast(b)); const auto* ptr = reinterpret_cast(b); - return input_adapter(ptr, ptr + length); + return input_adapter(ptr, ptr + length); // cppcheck-suppress[nullPointerArithmeticRedundantCheck] } template @@ -6635,742 +6999,29 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include #include // string +#include // enable_if_t #include // move #include // vector // #include -// #include - -// #include - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/*! -@brief SAX interface - -This class describes the SAX interface used by @ref nlohmann::json::sax_parse. -Each function is called in different situations while the input is parsed. The -boolean return value informs the parser whether to continue processing the -input. -*/ -template -struct json_sax -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @brief a null value was read - @return whether parsing should proceed - */ - virtual bool null() = 0; - - /*! - @brief a boolean value was read - @param[in] val boolean value - @return whether parsing should proceed - */ - virtual bool boolean(bool val) = 0; - - /*! - @brief an integer number was read - @param[in] val integer value - @return whether parsing should proceed - */ - virtual bool number_integer(number_integer_t val) = 0; - - /*! - @brief an unsigned integer number was read - @param[in] val unsigned integer value - @return whether parsing should proceed - */ - virtual bool number_unsigned(number_unsigned_t val) = 0; - - /*! - @brief a floating-point number was read - @param[in] val floating-point value - @param[in] s raw token value - @return whether parsing should proceed - */ - virtual bool number_float(number_float_t val, const string_t& s) = 0; - - /*! - @brief a string value was read - @param[in] val string value - @return whether parsing should proceed - @note It is safe to move the passed string value. - */ - virtual bool string(string_t& val) = 0; - - /*! - @brief a binary value was read - @param[in] val binary value - @return whether parsing should proceed - @note It is safe to move the passed binary value. - */ - virtual bool binary(binary_t& val) = 0; - - /*! - @brief the beginning of an object was read - @param[in] elements number of object elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_object(std::size_t elements) = 0; - - /*! - @brief an object key was read - @param[in] val object key - @return whether parsing should proceed - @note It is safe to move the passed string. - */ - virtual bool key(string_t& val) = 0; - - /*! - @brief the end of an object was read - @return whether parsing should proceed - */ - virtual bool end_object() = 0; - - /*! - @brief the beginning of an array was read - @param[in] elements number of array elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_array(std::size_t elements) = 0; - - /*! - @brief the end of an array was read - @return whether parsing should proceed - */ - virtual bool end_array() = 0; - - /*! - @brief a parse error occurred - @param[in] position the position in the input where the error occurs - @param[in] last_token the last read token - @param[in] ex an exception object describing the error - @return whether parsing should proceed (must return false) - */ - virtual bool parse_error(std::size_t position, - const std::string& last_token, - const detail::exception& ex) = 0; - - json_sax() = default; - json_sax(const json_sax&) = default; - json_sax(json_sax&&) noexcept = default; - json_sax& operator=(const json_sax&) = default; - json_sax& operator=(json_sax&&) noexcept = default; - virtual ~json_sax() = default; -}; - -namespace detail -{ -/*! -@brief SAX implementation to create a JSON value from SAX events - -This class implements the @ref json_sax interface and processes the SAX events -to create a JSON value which makes it basically a DOM parser. The structure or -hierarchy of the JSON value is managed by the stack `ref_stack` which contains -a pointer to the respective array or object for each recursion depth. - -After successful parsing, the value that is passed by reference to the -constructor contains the parsed value. - -@tparam BasicJsonType the JSON type -*/ -template -class json_sax_dom_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @param[in,out] r reference to a JSON value that is manipulated while - parsing - @param[in] allow_exceptions_ whether parse errors yield exceptions - */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) - {} - - // make class move-only - json_sax_dom_parser(const json_sax_dom_parser&) = delete; - json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; - json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_object()); - - // add null at given key and store the reference for later - object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); - return true; - } - - bool end_object() - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_object()); - - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - bool start_array(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool end_array() - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_array()); - - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_value(Value&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType(std::forward(v)); - return &root; - } - - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->emplace_back(std::forward(v)); - return &(ref_stack.back()->m_data.m_value.array->back()); - } - - JSON_ASSERT(ref_stack.back()->is_object()); - JSON_ASSERT(object_element); - *object_element = BasicJsonType(std::forward(v)); - return object_element; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -template -class json_sax_dom_callback_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using parser_callback_t = typename BasicJsonType::parser_callback_t; - using parse_event_t = typename BasicJsonType::parse_event_t; - - json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) - { - keep_stack.push_back(true); - } - - // make class move-only - json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_callback_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - // check callback for object start - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::object, true); - ref_stack.push_back(val.second); - - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - BasicJsonType k = BasicJsonType(val); - - // check callback for key - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); - key_keep_stack.push_back(keep); - - // add discarded value at given key and store the reference for later - if (keep && ref_stack.back()) - { - object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); - } - - return true; - } - - bool end_object() - { - if (ref_stack.back()) - { - if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) - { - // discard object - *ref_stack.back() = discarded; - } - else - { - ref_stack.back()->set_parents(); - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) - { - // remove discarded value - for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) - { - if (it->is_discarded()) - { - ref_stack.back()->erase(it); - break; - } - } - } - - return true; - } - - bool start_array(std::size_t len) - { - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::array, true); - ref_stack.push_back(val.second); - - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool end_array() - { - bool keep = true; - - if (ref_stack.back()) - { - keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (keep) - { - ref_stack.back()->set_parents(); - } - else - { - // discard array - *ref_stack.back() = discarded; - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - // remove discarded value - if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->pop_back(); - } - - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @param[in] v value to add to the JSON value we build during parsing - @param[in] skip_callback whether we should skip calling the callback - function; this is required after start_array() and - start_object() SAX events, because otherwise we would call the - callback function with an empty array or object, respectively. - - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - - @return pair of boolean (whether value should be kept) and pointer (to the - passed value in the ref_stack hierarchy; nullptr if not kept) - */ - template - std::pair handle_value(Value&& v, const bool skip_callback = false) - { - JSON_ASSERT(!keep_stack.empty()); - - // do not handle this value if we know it would be added to a discarded - // container - if (!keep_stack.back()) - { - return {false, nullptr}; - } - - // create value - auto value = BasicJsonType(std::forward(v)); - - // check callback - const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); - - // do not handle this value if we just learnt it shall be discarded - if (!keep) - { - return {false, nullptr}; - } - - if (ref_stack.empty()) - { - root = std::move(value); - return {true, & root}; - } - - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (!ref_stack.back()) - { - return {false, nullptr}; - } - - // we now only expect arrays and objects - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - // array - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); - return {true, & (ref_stack.back()->m_data.m_value.array->back())}; - } - - // object - JSON_ASSERT(ref_stack.back()->is_object()); - // check if we should store an element for the current key - JSON_ASSERT(!key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (!store_element) - { - return {false, nullptr}; - } - - JSON_ASSERT(object_element); - *object_element = std::move(value); - return {true, object_element}; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// stack to manage which values to keep - std::vector keep_stack {}; - /// stack to manage which object keys to keep - std::vector key_keep_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// callback function - const parser_callback_t callback = nullptr; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; - /// a discarded value for the callback - BasicJsonType discarded = BasicJsonType::value_t::discarded; -}; - -template -class json_sax_acceptor -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - bool null() - { - return true; - } - - bool boolean(bool /*unused*/) - { - return true; - } - - bool number_integer(number_integer_t /*unused*/) - { - return true; - } - - bool number_unsigned(number_unsigned_t /*unused*/) - { - return true; - } - - bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) - { - return true; - } - - bool string(string_t& /*unused*/) - { - return true; - } - - bool binary(binary_t& /*unused*/) - { - return true; - } - - bool start_object(std::size_t /*unused*/ = static_cast(-1)) - { - return true; - } - - bool key(string_t& /*unused*/) - { - return true; - } - - bool end_object() - { - return true; - } - - bool start_array(std::size_t /*unused*/ = static_cast(-1)) - { - return true; - } - - bool end_array() - { - return true; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) - { - return false; - } -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -8338,7 +7989,7 @@ class lexer : public lexer_base locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() // lgtm [cpp/use-of-goto] + token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated. { // reset token_buffer to store the number's bytes reset(); @@ -8420,6 +8071,7 @@ scan_number_zero: case '.': { add(decimal_point_char); + decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } @@ -8456,6 +8108,7 @@ scan_number_any1: case '.': { add(decimal_point_char); + decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } @@ -8616,7 +8269,7 @@ scan_number_done: // we are done scanning a number) unget(); - char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg) errno = 0; // try to parse integers first and fall back to floats @@ -8627,7 +8280,7 @@ scan_number_done: // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - if (errno == 0) + if (errno != ERANGE) { value_unsigned = static_cast(x); if (value_unsigned == x) @@ -8643,7 +8296,7 @@ scan_number_done: // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - if (errno == 0) + if (errno != ERANGE) { value_integer = static_cast(x); if (value_integer == x) @@ -8693,6 +8346,7 @@ scan_number_done: { token_buffer.clear(); token_string.clear(); + decimal_point_position = std::string::npos; token_string.push_back(char_traits::to_char_type(current)); } @@ -8801,6 +8455,11 @@ scan_number_done: /// return current string value (implicitly resets the token; useful only once) string_t& get_string() { + // translate decimal points from locale back to '.' (#4084) + if (decimal_point_char != '.' && decimal_point_position != std::string::npos) + { + token_buffer[decimal_point_position] = '.'; + } return token_buffer; } @@ -8998,6 +8657,8 @@ scan_number_done: /// the decimal point const char_int_type decimal_point_char = '.'; + /// the position of the decimal point in the input + std::size_t decimal_point_position = std::string::npos; }; } // namespace detail @@ -9005,13 +8666,986 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief a floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string value was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string value. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary value was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary value. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + json_sax() = default; + json_sax(const json_sax&) = default; + json_sax(json_sax&&) noexcept = default; + json_sax& operator=(const json_sax&) = default; + json_sax& operator=(json_sax&&) noexcept = default; + virtual ~json_sax() = default; +}; + +namespace detail +{ +constexpr std::size_t unknown_size() +{ + return (std::numeric_limits::max)(); +} + +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using lexer_t = lexer; + + /*! + @param[in,out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true, lexer_t* lexer_ = nullptr) + : root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool end_array() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_array()); + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + // As we handle the start and end positions for values created during parsing, + // we do not expect the following value type to be called. Regardless, set the positions + // in case this is created manually or through a different constructor. Exclude from lcov + // since the exact condition of this switch is esoteric. + // LCOV_EXCL_START + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + // LCOV_EXCL_STOP + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(root); +#endif + + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back()); +#endif + + return &(ref_stack.back()->m_data.m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(*object_element); +#endif + + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + using lexer_t = lexer; + + json_sax_dom_callback_parser(BasicJsonType& r, + parser_callback_t cb, + const bool allow_exceptions_ = true, + lexer_t* lexer_ = nullptr) + : root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + if (ref_stack.back()) + { + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check object limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + } + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back()) + { + if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded object. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif + } + else + { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + + ref_stack.back()->set_parents(); + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + if (ref_stack.back()) + { + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the array, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check array limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (keep) + { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + + ref_stack.back()->set_parents(); + } + else + { + // discard array + *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded array. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(value); +#endif + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, & root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); + return {true, & (ref_stack.back()->m_data.m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; // NOLINT(readability-redundant-member-init) + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; // NOLINT(readability-redundant-member-init) + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = detail::unknown_size()) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = detail::unknown_size()) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -9207,7 +9841,7 @@ static inline bool little_endianness(int num = 1) noexcept /*! @brief deserialization of CBOR, MessagePack, and UBJSON values */ -template> +template> class binary_reader { using number_integer_t = typename BasicJsonType::number_integer_t; @@ -9314,7 +9948,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -9470,6 +10104,12 @@ class binary_reader return get_number(input_format_t::bson, value) && sax->number_integer(value); } + case 0x11: // uint64 + { + std::uint64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_unsigned(value); + } + default: // anything else not supported (yet) { std::array cr{{}}; @@ -9536,7 +10176,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -9796,7 +10436,7 @@ class binary_reader } case 0x9F: // array (indefinite length) - return get_cbor_array(static_cast(-1), tag_handler); + return get_cbor_array(detail::unknown_size(), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -9850,7 +10490,7 @@ class binary_reader } case 0xBF: // map (indefinite length) - return get_cbor_object(static_cast(-1), tag_handler); + return get_cbor_object(detail::unknown_size(), tag_handler); case 0xC6: // tagged item case 0xC7: @@ -10238,7 +10878,7 @@ class binary_reader } /*! - @param[in] len the length of the array or static_cast(-1) for an + @param[in] len the length of the array or detail::unknown_size() for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed @@ -10251,7 +10891,7 @@ class binary_reader return false; } - if (len != static_cast(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -10276,7 +10916,7 @@ class binary_reader } /*! - @param[in] len the length of the object or static_cast(-1) for an + @param[in] len the length of the object or detail::unknown_size() for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed @@ -10292,7 +10932,7 @@ class binary_reader if (len != 0) { string_t key; - if (len != static_cast(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -11455,6 +12095,16 @@ class binary_reader case 'Z': // null return sax->null(); + case 'B': // byte + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + case 'U': { std::uint8_t number{}; @@ -11655,7 +12305,7 @@ class binary_reader return false; } - if (size_and_type.second == 'C') + if (size_and_type.second == 'C' || size_and_type.second == 'B') { size_and_type.second = 'U'; } @@ -11677,6 +12327,13 @@ class binary_reader return (sax->end_array() && sax->end_object()); } + // If BJData type marker is 'B' decode as binary + if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') + { + binary_t result; + return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + } + if (size_and_type.first != npos) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) @@ -11710,7 +12367,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -11788,7 +12445,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -11899,6 +12556,29 @@ class binary_reader return current = ia.get_character(); } + /*! + @brief get_to read into a primitive type + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns false instead + + @return bool, whether the read was successful + */ + template + bool get_to(T& dest, const input_format_t format, const char* context) + { + auto new_chars_read = ia.get_elements(&dest); + chars_read += new_chars_read; + if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) + { + // in case of failure, advance position by 1 to report failing location + ++chars_read; + sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + return false; + } + return true; + } + /*! @return character read from the input after ignoring all 'N' entries */ @@ -11913,6 +12593,28 @@ class binary_reader return current; } + template + static void byte_swap(NumberType& number) + { + constexpr std::size_t sz = sizeof(number); +#ifdef __cpp_lib_byteswap + if constexpr (sz == 1) + { + return; + } + if constexpr(std::is_integral_v) + { + number = std::byteswap(number); + return; + } +#endif + auto* ptr = reinterpret_cast(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } + } + /* @brief read a number from the input @@ -11931,29 +12633,16 @@ class binary_reader template bool get_number(const input_format_t format, NumberType& result) { - // step 1: read input into array with system's byte order - std::array vec{}; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) + // read in the original format + + if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) - { - return false; - } - - // reverse byte order prior to conversion if necessary - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } + return false; + } + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + byte_swap(result); } - - // step 2: convert array into number of type T and return - std::memcpy(&result, vec.data(), sizeof(NumberType)); return true; } @@ -12092,7 +12781,7 @@ class binary_reader } private: - static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast(-1); + static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size(); /// input adapter InputAdapterType ia; @@ -12118,6 +12807,7 @@ class binary_reader #define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ make_array( \ + bjd_type{'B', "byte"}, \ bjd_type{'C', "char"}, \ bjd_type{'D', "double"}, \ bjd_type{'I', "int16"}, \ @@ -12160,10 +12850,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -12237,10 +12927,10 @@ class parser public: /// a parser reading from an input adapter explicit parser(InputAdapterType&& adapter, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions_ = true, const bool skip_comments = false) - : callback(cb) + : callback(std::move(cb)) , m_lexer(std::move(adapter), skip_comments) , allow_exceptions(allow_exceptions_) { @@ -12262,7 +12952,7 @@ class parser { if (callback) { - json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions, &m_lexer); sax_parse_internal(&sdp); // in strict mode, input must be completely read @@ -12290,7 +12980,7 @@ class parser } else { - json_sax_dom_parser sdp(result, allow_exceptions); + json_sax_dom_parser sdp(result, allow_exceptions, &m_lexer); sax_parse_internal(&sdp); // in strict mode, input must be completely read @@ -12362,7 +13052,7 @@ class parser { case token_type::begin_object: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -12407,7 +13097,7 @@ class parser case token_type::begin_array: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -12689,10 +13379,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -12702,10 +13392,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -12861,10 +13551,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -13331,7 +14021,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator==(const IterImpl& other) const @@ -13342,7 +14032,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + return true; + } switch (m_object->m_data.m_type) { @@ -13367,7 +14061,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator!=(const IterImpl& other) const @@ -13377,7 +14071,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<(const iter_impl& other) const { @@ -13387,7 +14081,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false + return false; + } switch (m_object->m_data.m_type) { @@ -13412,7 +14111,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<=(const iter_impl& other) const { @@ -13421,7 +14120,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator>(const iter_impl& other) const { @@ -13430,7 +14129,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized. */ bool operator>=(const iter_impl& other) const { @@ -13623,10 +14322,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -13758,10 +14457,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -13800,10 +14499,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -14033,7 +14732,7 @@ class json_pointer } const char* p = s.c_str(); - char* p_end = nullptr; + char* p_end = nullptr; // NOLINT(misc-const-correctness) errno = 0; // strtoull doesn't reset errno const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) if (p == p_end // invalid input or empty string @@ -14555,7 +15254,7 @@ class json_pointer // iterate array and use index as reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { - flatten(detail::concat(reference_string, '/', std::to_string(i)), + flatten(detail::concat(reference_string, '/', std::to_string(i)), value.m_data.m_value.array->operator[](i), result); } } @@ -14574,7 +15273,7 @@ class json_pointer // iterate object and use keys as reference string for (const auto& element : *value.m_data.m_value.object) { - flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); + flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); } } break; @@ -14795,10 +15494,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -14880,6 +15579,8 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include + // #include // #include @@ -14887,10 +15588,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -14913,10 +15614,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -15067,6 +15768,13 @@ NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { +/// how to encode BJData +enum class bjdata_version_t +{ + draft2, + draft3, +}; + /////////////////// // binary writer // /////////////////// @@ -15651,7 +16359,7 @@ class binary_writer case value_t::binary: { // step 0: determine if the binary type has a set subtype to - // determine whether or not to use the ext or fixext types + // determine whether to use the ext or fixext types const bool use_ext = j.m_data.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length @@ -15774,11 +16482,14 @@ class binary_writer @param[in] use_type whether to use '$' prefixes (optimized format) @param[in] add_prefix whether prefixes need to be used for this value @param[in] use_bjdata whether write in BJData format, default is false + @param[in] bjdata_version which BJData version to use, default is draft2 */ void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true, - const bool use_bjdata = false) + const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2) { + const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3; + switch (j.type()) { case value_t::null: @@ -15868,7 +16579,7 @@ class binary_writer for (const auto& el : *j.m_data.m_value.array) { - write_ubjson(el, use_count, use_type, prefix_required, use_bjdata); + write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version); } if (!use_count) @@ -15886,11 +16597,11 @@ class binary_writer oa->write_character(to_char_type('[')); } - if (use_type && !j.m_data.m_value.binary->empty()) + if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty())) { JSON_ASSERT(use_count); oa->write_character(to_char_type('$')); - oa->write_character('U'); + oa->write_character(bjdata_draft3 ? 'B' : 'U'); } if (use_count) @@ -15909,7 +16620,7 @@ class binary_writer { for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i) { - oa->write_character(to_char_type('U')); + oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U')); oa->write_character(j.m_data.m_value.binary->data()[i]); } } @@ -15926,7 +16637,7 @@ class binary_writer { if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) { - if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) + if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) { break; } @@ -15970,7 +16681,7 @@ class binary_writer oa->write_characters( reinterpret_cast(el.first.c_str()), el.first.size()); - write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata); + write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version); } if (!use_count) @@ -16126,7 +16837,8 @@ class binary_writer } else { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); + write_bson_entry_header(name, 0x11 /* uint64 */); + write_number(static_cast(j.m_data.m_value.number_unsigned), true); } } @@ -16654,10 +17366,11 @@ class binary_writer /*! @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid */ - bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type) + bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type, const bjdata_version_t bjdata_version) { std::map bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, - {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'} + {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, + {"char", 'C'}, {"byte", 'B'} }; string_t key = "_ArrayType_"; @@ -16687,10 +17400,10 @@ class binary_writer oa->write_character('#'); key = "_ArraySize_"; - write_ubjson(value.at(key), use_count, use_type, true, true); + write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version); key = "_ArrayData_"; - if (dtype == 'U' || dtype == 'C') + if (dtype == 'U' || dtype == 'C' || dtype == 'B') { for (const auto& el : value.at(key)) { @@ -16881,11 +17594,11 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -16906,11 +17619,11 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2009 Florian Loitsch -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -17146,10 +17859,10 @@ boundaries compute_boundaries(FloatType value) // v- m- v m+ v+ const bool lower_boundary_is_closer = F == 0 && E > 1; - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_plus = diyfp((2 * v.f) + 1, v.e - 1); const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) + ? diyfp((4 * v.f) - 1, v.e - 2) // (B) + : diyfp((2 * v.f) - 1, v.e - 1); // (A) // Determine the normalized w+ = m+. const diyfp w_plus = diyfp::normalize(m_plus); @@ -17379,7 +18092,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) JSON_ASSERT(e >= -1500); JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + const int k = ((f * 78913) / (1 << 18)) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; JSON_ASSERT(index >= 0); @@ -17857,15 +18570,15 @@ inline char* append_exponent(char* buf, int e) } else if (k < 100) { - *buf++ = static_cast('0' + k / 10); + *buf++ = static_cast('0' + (k / 10)); k %= 10; *buf++ = static_cast('0' + k); } else { - *buf++ = static_cast('0' + k / 100); + *buf++ = static_cast('0' + (k / 100)); k %= 100; - *buf++ = static_cast('0' + k / 10); + *buf++ = static_cast('0' + (k / 10)); k %= 10; *buf++ = static_cast('0' + k); } @@ -18651,7 +19364,7 @@ class serializer @param[in] x unsigned integer number to count its digits @return number of decimal digits */ - inline unsigned int count_digits(number_unsigned_t x) noexcept + unsigned int count_digits(number_unsigned_t x) noexcept { unsigned int n_digits = 1; for (;;) @@ -18934,7 +19647,7 @@ class serializer ? (byte & 0x3fu) | (codep << 6u) : (0xFFu >> type) & (byte); - const std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); + const std::size_t index = 256u + (static_cast(state) * 16u) + static_cast(type); JSON_ASSERT(index < utf8d.size()); state = utf8d[index]; return state; @@ -18960,7 +19673,7 @@ class serializer * absolute values of INT_MIN and INT_MAX are usually not the same. See * #1708 for details. */ - inline number_unsigned_t remove_sign(number_integer_t x) noexcept + number_unsigned_t remove_sign(number_integer_t x) noexcept { JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) return static_cast(-(x + 1)) + 1; @@ -19002,10 +19715,10 @@ NLOHMANN_JSON_NAMESPACE_END // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -19030,7 +19743,7 @@ NLOHMANN_JSON_NAMESPACE_BEGIN /// for use within nlohmann::basic_json template , class Allocator = std::allocator>> - struct ordered_map : std::vector, Allocator> + struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; @@ -19345,7 +20058,7 @@ template , template using require_input_iter = typename std::enable_if::iterator_category, - std::input_iterator_tag>::value>::type; + std::input_iterator_tag>::value>::type; template> void insert(InputIt first, InputIt last) @@ -19416,9 +20129,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec friend class ::nlohmann::detail::binary_writer; template friend class ::nlohmann::detail::binary_reader; - template + template friend class ::nlohmann::detail::json_sax_dom_parser; - template + template friend class ::nlohmann::detail::json_sax_dom_callback_parser; friend class ::nlohmann::detail::exception; @@ -19439,7 +20152,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ) { return ::nlohmann::detail::parser(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); + std::move(cb), allow_exceptions, ignore_comments); } private: @@ -19472,6 +20185,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec using error_handler_t = detail::error_handler_t; /// how to treat CBOR tags using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// how to encode BJData + using bjdata_version_t = detail::bjdata_version_t; /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; @@ -19551,7 +20266,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { basic_json result; - result["copyright"] = "(C) 2013-2023 Niels Lohmann"; + result["copyright"] = "(C) 2013-2025 Niels Lohmann"; result["name"] = "JSON for Modern C++"; result["url"] = "https://github.com/nlohmann/json"; result["version"]["string"] = @@ -19816,7 +20531,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE } break; } @@ -20052,10 +20767,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return it; } - reference set_parent(reference j, std::size_t old_capacity = static_cast(-1)) + reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size()) { #if JSON_DIAGNOSTICS - if (old_capacity != static_cast(-1)) + if (old_capacity != detail::unknown_size()) { // see https://github.com/nlohmann/json/issues/2838 JSON_ASSERT(type() == value_t::array); @@ -20135,8 +20850,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::enable_if_t < !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) - JSONSerializer::to_json(std::declval(), - std::forward(val)))) + JSONSerializer::to_json(std::declval(), + std::forward(val)))) { JSONSerializer::to_json(*this, std::forward(val)); set_parents(); @@ -20149,6 +20864,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::enable_if_t < detail::is_basic_json::value&& !std::is_same::value, int > = 0 > basic_json(const BasicJsonType& val) +#if JSON_DIAGNOSTIC_POSITIONS + : start_position(val.start_pos()), + end_position(val.end_pos()) +#endif { using other_boolean_t = typename BasicJsonType::boolean_t; using other_number_float_t = typename BasicJsonType::number_float_t; @@ -20195,6 +20914,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } JSON_ASSERT(m_data.m_type == val.type()); + set_parents(); assert_invariant(); } @@ -20331,7 +21051,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class InputIT, typename std::enable_if < std::is_same::value || std::is_same::value, int >::type = 0 > - basic_json(InputIT first, InputIT last) + basic_json(InputIT first, InputIT last) // NOLINT(performance-unnecessary-value-param) { JSON_ASSERT(first.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr); @@ -20446,6 +21166,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ basic_json(const basic_json& other) : json_base_class_t(other) +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) + , end_position(other.end_position) +#endif { m_data.m_type = other.m_data.m_type; // check of passed value is valid @@ -20515,15 +21239,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ basic_json(basic_json&& other) noexcept : json_base_class_t(std::forward(other)), - m_data(std::move(other.m_data)) + m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check + , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check +#endif { // check that passed value is valid - other.assert_invariant(false); + other.assert_invariant(false); // cppcheck-suppress[accessForwarded] // invalidate payload other.m_data.m_type = value_t::null; other.m_data.m_value = {}; +#if JSON_DIAGNOSTIC_POSITIONS + other.start_position = std::string::npos; + other.end_position = std::string::npos; +#endif + set_parents(); assert_invariant(); } @@ -20544,6 +21277,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec using std::swap; swap(m_data.m_type, other.m_data.m_type); swap(m_data.m_value, other.m_data.m_value); + +#if JSON_DIAGNOSTIC_POSITIONS + swap(start_position, other.start_position); + swap(end_position, other.end_position); +#endif + json_base_class_t::operator=(std::move(other)); set_parents(); @@ -20765,13 +21504,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) @@ -20906,7 +21645,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::has_from_json::value, int > = 0 > ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) + JSONSerializer::from_json(std::declval(), std::declval()))) { auto ret = ValueType(); JSONSerializer::from_json(*this, ret); @@ -20948,7 +21687,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::has_non_default_from_json::value, int > = 0 > ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) + JSONSerializer::from_json(std::declval()))) { return JSONSerializer::from_json(*this); } @@ -21098,7 +21837,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::has_from_json::value, int > = 0 > ValueType & get_to(ValueType& v) const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), v))) + JSONSerializer::from_json(std::declval(), v))) { JSONSerializer::from_json(*this, v); return v; @@ -21250,7 +21989,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // create better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } + } // cppcheck-suppress[missingReturn] } else { @@ -21273,7 +22012,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // create better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } + } // cppcheck-suppress[missingReturn] } else { @@ -21418,7 +22157,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](typename object_t::key_type key) + reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param) { // implicitly convert null value to an empty object if (is_null()) @@ -21728,7 +22467,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class IteratorType, detail::enable_if_t < std::is_same::value || std::is_same::value, int > = 0 > - IteratorType erase(IteratorType pos) + IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) @@ -21798,7 +22537,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class IteratorType, detail::enable_if_t < std::is_same::value || std::is_same::value, int > = 0 > - IteratorType erase(IteratorType first, IteratorType last) + IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) @@ -22565,7 +23304,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @note: This uses std::distance to support GCC 4.8, /// see https://github.com/nlohmann/json/pull/1257 template - iterator insert_iterator(const_iterator pos, Args&& ... args) + iterator insert_iterator(const_iterator pos, Args&& ... args) // NOLINT(performance-unnecessary-value-param) { iterator result(this); JSON_ASSERT(m_data.m_value.array != nullptr); @@ -22584,7 +23323,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const basic_json& val) + iterator insert(const_iterator pos, const basic_json& val) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) @@ -22604,14 +23343,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, basic_json&& val) + iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param) { return insert(pos, val); } /// @brief inserts copies of element into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) @@ -22631,7 +23370,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts range of elements into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) + iterator insert(const_iterator pos, const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) @@ -22662,7 +23401,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts elements from initializer list into array /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, initializer_list_t ilist) + iterator insert(const_iterator pos, initializer_list_t ilist) // NOLINT(performance-unnecessary-value-param) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) @@ -22682,7 +23421,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief inserts range of elements into object /// @sa https://json.nlohmann.me/api/basic_json/insert/ - void insert(const_iterator first, const_iterator last) + void insert(const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) { // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) @@ -22703,6 +23442,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + set_parents(); } /// @brief updates a JSON object from another object, overwriting existing keys @@ -22714,7 +23454,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief updates a JSON object from another object, overwriting existing keys /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_iterator first, const_iterator last, bool merge_objects = false) + void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param) { // implicitly convert null value to an empty object if (is_null()) @@ -23315,12 +24055,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(InputType&& i, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] return result; } @@ -23330,24 +24070,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] return result; } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) static basic_json parse(detail::span_input_adapter&& i, - const parser_callback_t cb = nullptr, + parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; - parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); + parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -23526,6 +24266,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec basic_json* m_parent = nullptr; #endif +#if JSON_DIAGNOSTIC_POSITIONS + /// the start position of the value + std::size_t start_position = std::string::npos; + /// the end position of the value + std::size_t end_position = std::string::npos; + public: + constexpr std::size_t start_pos() const noexcept + { + return start_position; + } + + constexpr std::size_t end_pos() const noexcept + { + return end_position; + } +#endif + ////////////////////////////////////////// // binary serialization/deserialization // ////////////////////////////////////////// @@ -23611,27 +24368,30 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static std::vector to_bjdata(const basic_json& j, const bool use_size = false, - const bool use_type = false) + const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { std::vector result; - to_bjdata(j, result, use_size, use_type); + to_bjdata(j, result, use_size, use_type, version); return result; } /// @brief create a BJData serialization of a given JSON value /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { - binary_writer(o).write_ubjson(j, use_size, use_type, true, true); + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); } /// @brief create a BJData serialization of a given JSON value /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ static void to_bjdata(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) { - binary_writer(o).write_ubjson(j, use_size, use_type, true, true); + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); } /// @brief create a BSON serialization of a given JSON value @@ -23667,9 +24427,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23683,9 +24443,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23708,10 +24468,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23724,9 +24484,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23739,9 +24499,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23762,10 +24522,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23778,9 +24538,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23793,9 +24553,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23816,10 +24576,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23832,9 +24592,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23847,9 +24607,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23862,9 +24622,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23877,9 +24637,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } @@ -23900,10 +24660,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true) { basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] return res ? result : basic_json(value_t::discarded); } /// @} @@ -24004,7 +24764,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // the valid JSON Patch operations enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - const auto get_op = [](const std::string & op) + const auto get_op = [](const string_t& op) { if (op == "add") { @@ -24035,7 +24795,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec }; // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) + const auto operation_add = [&result](json_pointer & ptr, const basic_json & val) { // adding to the root of the target document means replacing it if (ptr.empty()) @@ -24141,15 +24901,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (const auto& val : json_patch) { // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, + const auto get_value = [&val](const string_t& op, + const string_t& member, bool string_type) -> basic_json & { // find value auto it = val.m_data.m_value.object->find(member); // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); + const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) // check if desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) @@ -24176,8 +24936,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // collect mandatory members - const auto op = get_value("op", "op", true).template get(); - const auto path = get_value(op, "path", true).template get(); + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); json_pointer ptr(path); switch (get_op(op)) @@ -24203,7 +24963,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case patch_operations::move: { - const auto from_path = get_value("move", "from", true).template get(); + const auto from_path = get_value("move", "from", true).template get(); json_pointer from_ptr(from_path); // the "from" location must exist - use at() @@ -24220,7 +24980,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case patch_operations::copy: { - const auto from_path = get_value("copy", "from", true).template get(); + const auto from_path = get_value("copy", "from", true).template get(); const json_pointer from_ptr(from_path); // the "from" location must exist - use at() @@ -24280,7 +25040,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/diff/ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") + const string_t& path = "") { // the patch basic_json result(value_t::array); @@ -24310,7 +25070,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec while (i < source.size() && i < target.size()) { // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i))); + auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', detail::to_string(i))); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); ++i; } @@ -24327,7 +25087,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.insert(result.begin() + end_index, object( { {"op", "remove"}, - {"path", detail::concat(path, '/', std::to_string(i))} + {"path", detail::concat(path, '/', detail::to_string(i))} })); ++i; } @@ -24338,7 +25098,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.push_back( { {"op", "add"}, - {"path", detail::concat(path, "/-")}, + {"path", detail::concat(path, "/-")}, {"value", target[i]} }); ++i; @@ -24353,7 +25113,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = source.cbegin(); it != source.cend(); ++it) { // escape the key name to be used in a JSON patch - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); if (target.find(it.key()) != target.end()) { @@ -24377,7 +25137,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (source.find(it.key()) == source.end()) { // found a key that is not in this -> add it - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); result.push_back( { {"op", "add"}, {"path", path_key}, @@ -24558,10 +25318,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -24592,6 +25352,7 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 + #undef JSON_HAS_CPP_23 #undef JSON_HAS_FILESYSTEM #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON @@ -24603,10 +25364,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT diff --git a/single_include/nlohmann/json_fwd.hpp b/single_include/nlohmann/json_fwd.hpp index 29a6036d7..942917139 100644 --- a/single_include/nlohmann/json_fwd.hpp +++ b/single_include/nlohmann/json_fwd.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -18,10 +18,10 @@ // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT @@ -30,20 +30,24 @@ #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 #warning "Already included a different version of the library!" #endif #endif #endif #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) #ifndef JSON_DIAGNOSTICS #define JSON_DIAGNOSTICS 0 #endif +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif @@ -54,6 +58,12 @@ #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS #endif +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp #else @@ -65,14 +75,15 @@ #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a153a6924..b1dc5df10 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,12 +21,21 @@ include(test) # override standard support ############################################################################# +# Clang only supports C++14 starting from Clang 3.5 (lesser versions miss std::enable_if_t) +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) + unset(compiler_supports_cpp_14) +endif() + # Clang only supports C++17 starting from Clang 5.0 if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) unset(compiler_supports_cpp_17) endif() # MSVC 2015 (14.0) does not support C++17 -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1) +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) + unset(compiler_supports_cpp_17) +endif() +# GCC 5 and 6 do claim experimental support for C++17, but do not implement +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) unset(compiler_supports_cpp_17) endif() @@ -34,6 +43,10 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) unset(compiler_supports_cpp_20) endif() +# MSVC 2017 (15.x) does not support C++20 +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.20) + unset(compiler_supports_cpp_20) +endif() # GCC started supporting C++20 features in 8.0 but a test for #3070 segfaults prior to 9.0 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) unset(compiler_supports_cpp_20) diff --git a/tests/abi/config/config.hpp b/tests/abi/config/config.hpp index 8762b2a6b..47613e93e 100644 --- a/tests/abi/config/config.hpp +++ b/tests/abi/config/config.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/tests/abi/config/custom.cpp b/tests/abi/config/custom.cpp index 9e5bb8980..d6c320b3e 100644 --- a/tests/abi/config/custom.cpp +++ b/tests/abi/config/custom.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/abi/config/default.cpp b/tests/abi/config/default.cpp index d54ca6ff3..c19b2367a 100644 --- a/tests/abi/config/default.cpp +++ b/tests/abi/config/default.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -24,6 +24,10 @@ TEST_CASE("default namespace") expected += "_diag"; #endif +#if JSON_DIAGNOSTIC_POSITIONS + expected += "_dp"; +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON expected += "_ldvcmp"; #endif diff --git a/tests/abi/config/noversion.cpp b/tests/abi/config/noversion.cpp index 2a7c277d7..095bfca97 100644 --- a/tests/abi/config/noversion.cpp +++ b/tests/abi/config/noversion.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -25,6 +25,10 @@ TEST_CASE("default namespace without version component") expected += "_diag"; #endif +#if JSON_DIAGNOSTIC_POSITIONS + expected += "_dp"; +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON expected += "_ldvcmp"; #endif diff --git a/tests/abi/diag/diag.cpp b/tests/abi/diag/diag.cpp index 286f75dbe..3e5666351 100644 --- a/tests/abi/diag/diag.cpp +++ b/tests/abi/diag/diag.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/abi/diag/diag.hpp b/tests/abi/diag/diag.hpp index 1d4d49e9a..f071bb1f3 100644 --- a/tests/abi/diag/diag.hpp +++ b/tests/abi/diag/diag.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/tests/abi/diag/diag_off.cpp b/tests/abi/diag/diag_off.cpp index cd0d178f7..373b70803 100644 --- a/tests/abi/diag/diag_off.cpp +++ b/tests/abi/diag/diag_off.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #undef JSON_DIAGNOSTICS diff --git a/tests/abi/diag/diag_on.cpp b/tests/abi/diag/diag_on.cpp index 197a2c0c6..bfc9ec474 100644 --- a/tests/abi/diag/diag_on.cpp +++ b/tests/abi/diag/diag_on.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #undef JSON_DIAGNOSTICS diff --git a/tests/abi/inline_ns/use_current.cpp b/tests/abi/inline_ns/use_current.cpp index cb07dd33e..248bcce3b 100644 --- a/tests/abi/inline_ns/use_current.cpp +++ b/tests/abi/inline_ns/use_current.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/abi/inline_ns/use_v3_10_5.cpp b/tests/abi/inline_ns/use_v3_10_5.cpp index 7a4275390..d809ad3ec 100644 --- a/tests/abi/inline_ns/use_v3_10_5.cpp +++ b/tests/abi/inline_ns/use_v3_10_5.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/abi/main.cpp b/tests/abi/main.cpp index 0a4805e76..7eb86e315 100644 --- a/tests/abi/main.cpp +++ b/tests/abi/main.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN diff --git a/tests/benchmarks/src/benchmarks.cpp b/tests/benchmarks/src/benchmarks.cpp index 0210b9fea..bf222c26c 100644 --- a/tests/benchmarks/src/benchmarks.cpp +++ b/tests/benchmarks/src/benchmarks.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include @@ -140,6 +140,46 @@ BENCHMARK_CAPTURE(ToCbor, signed_ints, TEST_DATA_DIRECTORY "/regression/si BENCHMARK_CAPTURE(ToCbor, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); BENCHMARK_CAPTURE(ToCbor, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); +////////////////////////////////////////////////////////////////////////////// +// Parse Msgpack +////////////////////////////////////////////////////////////////////////////// + +static void FromMsgpack(benchmark::State& state, const char* filename) +{ + std::ifstream f(filename); + std::string str((std::istreambuf_iterator(f)), std::istreambuf_iterator()); + auto bytes = json::to_msgpack(json::parse(str)); + std::ofstream o("test.msgpack"); + o.write((char*)bytes.data(), bytes.size()); + o.flush(); + o.close(); + for (auto _ : state) + { + state.PauseTiming(); + auto* j = new json(); + auto file = fopen("test.msgpack", "rb"); + state.ResumeTiming(); + + *j = json::from_msgpack(file); + + state.PauseTiming(); + fclose(file); + delete j; + state.ResumeTiming(); + } + + state.SetBytesProcessed(state.iterations() * bytes.size()); +} + +BENCHMARK_CAPTURE(FromMsgpack, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"); +BENCHMARK_CAPTURE(FromMsgpack, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"); +BENCHMARK_CAPTURE(FromMsgpack, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"); +BENCHMARK_CAPTURE(FromMsgpack, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"); +BENCHMARK_CAPTURE(FromMsgpack, floats, TEST_DATA_DIRECTORY "/regression/floats.json"); +BENCHMARK_CAPTURE(FromMsgpack, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json"); +BENCHMARK_CAPTURE(FromMsgpack, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); +BENCHMARK_CAPTURE(FromMsgpack, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); + ////////////////////////////////////////////////////////////////////////////// // serialize binary CBOR ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/cmake_add_subdirectory/project/CMakeLists.txt b/tests/cmake_add_subdirectory/project/CMakeLists.txt index 0695305ff..775933e3f 100644 --- a/tests/cmake_add_subdirectory/project/CMakeLists.txt +++ b/tests/cmake_add_subdirectory/project/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.14) +cmake_minimum_required(VERSION 3.5...3.14) project(DummyImport CXX) diff --git a/tests/cmake_add_subdirectory/project/main.cpp b/tests/cmake_add_subdirectory/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_add_subdirectory/project/main.cpp +++ b/tests/cmake_add_subdirectory/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_fetch_content/project/main.cpp b/tests/cmake_fetch_content/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_fetch_content/project/main.cpp +++ b/tests/cmake_fetch_content/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_fetch_content2/project/main.cpp b/tests/cmake_fetch_content2/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_fetch_content2/project/main.cpp +++ b/tests/cmake_fetch_content2/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_import/project/CMakeLists.txt b/tests/cmake_import/project/CMakeLists.txt index 585f34cef..32bff796d 100644 --- a/tests/cmake_import/project/CMakeLists.txt +++ b/tests/cmake_import/project/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.14) +cmake_minimum_required(VERSION 3.5...3.14) project(DummyImport CXX) diff --git a/tests/cmake_import/project/main.cpp b/tests/cmake_import/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_import/project/main.cpp +++ b/tests/cmake_import/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_import_minver/project/CMakeLists.txt b/tests/cmake_import_minver/project/CMakeLists.txt index 25e40bfac..2e1af05db 100644 --- a/tests/cmake_import_minver/project/CMakeLists.txt +++ b/tests/cmake_import_minver/project/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.14) +cmake_minimum_required(VERSION 3.5...3.14) project(DummyImportMinVer CXX) diff --git a/tests/cmake_import_minver/project/main.cpp b/tests/cmake_import_minver/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_import_minver/project/main.cpp +++ b/tests/cmake_import_minver/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_target_include_directories/project/Bar.cpp b/tests/cmake_target_include_directories/project/Bar.cpp index 83a14bc85..1215a8d00 100644 --- a/tests/cmake_target_include_directories/project/Bar.cpp +++ b/tests/cmake_target_include_directories/project/Bar.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "Bar.hpp" diff --git a/tests/cmake_target_include_directories/project/Bar.hpp b/tests/cmake_target_include_directories/project/Bar.hpp index a56257c30..dffb81e31 100644 --- a/tests/cmake_target_include_directories/project/Bar.hpp +++ b/tests/cmake_target_include_directories/project/Bar.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cmake_target_include_directories/project/CMakeLists.txt b/tests/cmake_target_include_directories/project/CMakeLists.txt index 26b55cd89..c5317cf76 100644 --- a/tests/cmake_target_include_directories/project/CMakeLists.txt +++ b/tests/cmake_target_include_directories/project/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.14) +cmake_minimum_required(VERSION 3.5...3.14) project(DummyImport CXX) diff --git a/tests/cmake_target_include_directories/project/Foo.cpp b/tests/cmake_target_include_directories/project/Foo.cpp index 42e950e75..87b02892b 100644 --- a/tests/cmake_target_include_directories/project/Foo.cpp +++ b/tests/cmake_target_include_directories/project/Foo.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "Foo.hpp" diff --git a/tests/cmake_target_include_directories/project/Foo.hpp b/tests/cmake_target_include_directories/project/Foo.hpp index 18fe9763e..08aaf66b7 100644 --- a/tests/cmake_target_include_directories/project/Foo.hpp +++ b/tests/cmake_target_include_directories/project/Foo.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/tests/cmake_target_include_directories/project/main.cpp b/tests/cmake_target_include_directories/project/main.cpp index 6db944861..30bfbaf5a 100644 --- a/tests/cmake_target_include_directories/project/main.cpp +++ b/tests/cmake_target_include_directories/project/main.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/cuda_example/json_cuda.cu b/tests/cuda_example/json_cuda.cu index 657596662..fe875fca9 100644 --- a/tests/cuda_example/json_cuda.cu +++ b/tests/cuda_example/json_cuda.cu @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include diff --git a/tests/src/fuzzer-driver_afl.cpp b/tests/src/fuzzer-driver_afl.cpp index ae3aefe1e..aa577a3ee 100644 --- a/tests/src/fuzzer-driver_afl.cpp +++ b/tests/src/fuzzer-driver_afl.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_bjdata.cpp b/tests/src/fuzzer-parse_bjdata.cpp index 30f1ddd00..ae1b474b2 100644 --- a/tests/src/fuzzer-parse_bjdata.cpp +++ b/tests/src/fuzzer-parse_bjdata.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_bson.cpp b/tests/src/fuzzer-parse_bson.cpp index fa2a221db..a7ce308fc 100644 --- a/tests/src/fuzzer-parse_bson.cpp +++ b/tests/src/fuzzer-parse_bson.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_cbor.cpp b/tests/src/fuzzer-parse_cbor.cpp index db92aca8f..ed35c9193 100644 --- a/tests/src/fuzzer-parse_cbor.cpp +++ b/tests/src/fuzzer-parse_cbor.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_json.cpp b/tests/src/fuzzer-parse_json.cpp index be04e8030..8ceb96cb2 100644 --- a/tests/src/fuzzer-parse_json.cpp +++ b/tests/src/fuzzer-parse_json.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_msgpack.cpp b/tests/src/fuzzer-parse_msgpack.cpp index 0106b4053..fd9de56c3 100644 --- a/tests/src/fuzzer-parse_msgpack.cpp +++ b/tests/src/fuzzer-parse_msgpack.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/fuzzer-parse_ubjson.cpp b/tests/src/fuzzer-parse_ubjson.cpp index 2830bef75..2251f44a4 100644 --- a/tests/src/fuzzer-parse_ubjson.cpp +++ b/tests/src/fuzzer-parse_ubjson.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT /* diff --git a/tests/src/make_test_data_available.hpp b/tests/src/make_test_data_available.hpp index a2ffefa89..19d701b99 100644 --- a/tests/src/make_test_data_available.hpp +++ b/tests/src/make_test_data_available.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once @@ -18,7 +18,8 @@ namespace utils inline bool check_testsuite_downloaded() { - const std::unique_ptr file(std::fopen(TEST_DATA_DIRECTORY "/README.md", "r"), &std::fclose); + using FilePtr = std::unique_ptr; + const FilePtr file(std::fopen(TEST_DATA_DIRECTORY "/README.md", "r"), std::fclose); return file != nullptr; } diff --git a/tests/src/test_utils.hpp b/tests/src/test_utils.hpp index dbb0a9b14..a6003890b 100644 --- a/tests/src/test_utils.hpp +++ b/tests/src/test_utils.hpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once diff --git a/tests/src/unit-32bit.cpp b/tests/src/unit-32bit.cpp index 22a2ad283..ba284021c 100644 --- a/tests/src/unit-32bit.cpp +++ b/tests/src/unit-32bit.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -23,7 +23,7 @@ struct trait_test_arg static constexpr bool max_in_range = MaxInRange; }; -TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) +TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses) { using nlohmann::detail::value_in_range_of; diff --git a/tests/src/unit-algorithms.cpp b/tests/src/unit-algorithms.cpp index 3fb1640d4..fb3f03d1e 100644 --- a/tests/src/unit-algorithms.cpp +++ b/tests/src/unit-algorithms.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-allocator.cpp b/tests/src/unit-allocator.cpp index 399c8bfa8..d771fa32a 100644 --- a/tests/src/unit-allocator.cpp +++ b/tests/src/unit-allocator.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-alt-string.cpp b/tests/src/unit-alt-string.cpp index 7efe2e2e9..4f08290d7 100644 --- a/tests/src/unit-alt-string.cpp +++ b/tests/src/unit-alt-string.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-FileCopyrightText: 2018 Vitaliy Manushkin // SPDX-License-Identifier: MIT @@ -16,8 +16,8 @@ /* forward declarations */ class alt_string; -bool operator<(const char* op1, const alt_string& op2) noexcept; -void int_to_string(alt_string& target, std::size_t value); +bool operator<(const char* op1, const alt_string& op2) noexcept; // NOLINT(misc-use-internal-linkage) +void int_to_string(alt_string& target, std::size_t value); // NOLINT(misc-use-internal-linkage) /* * This is virtually a string class. @@ -28,17 +28,28 @@ class alt_string public: using value_type = std::string::value_type; - static constexpr auto npos = static_cast(-1); + static constexpr auto npos = (std::numeric_limits::max)(); alt_string(const char* str): str_impl(str) {} alt_string(const char* str, std::size_t count): str_impl(str, count) {} alt_string(size_t count, char chr): str_impl(count, chr) {} alt_string() = default; - template - alt_string& append(TParams&& ...params) + alt_string& append(char ch) { - str_impl.append(std::forward(params)...); + str_impl.push_back(ch); + return *this; + } + + alt_string& append(const alt_string& str) + { + str_impl.append(str.str_impl); + return *this; + } + + alt_string& append(const char* s, std::size_t length) + { + str_impl.append(s, length); return *this; } @@ -157,8 +168,13 @@ class alt_string return *this; } + void reserve( std::size_t new_cap = 0 ) + { + str_impl.reserve(new_cap); + } + private: - std::string str_impl {}; + std::string str_impl {}; // NOLINT(readability-redundant-member-init) friend bool operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept; }; @@ -319,4 +335,36 @@ TEST_CASE("alternative string type") CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]); CHECK(j.at(alt_json::json_pointer("/foo/1")) == j["foo"][1]); } + + SECTION("patch") + { + alt_json const patch1 = alt_json::parse(R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])"); + alt_json const doc1 = alt_json::parse(R"({ "a": { "foo": 1 } })"); + + CHECK_NOTHROW(doc1.patch(patch1)); + alt_json doc1_ans = alt_json::parse(R"( + { + "a": { + "foo": 1, + "b": [ "foo", "bar" ] + } + } + )"); + CHECK(doc1.patch(patch1) == doc1_ans); + } + + SECTION("diff") + { + alt_json const j1 = {"foo", "bar", "baz"}; + alt_json const j2 = {"foo", "bam"}; + CHECK(alt_json::diff(j1, j2).dump() == "[{\"op\":\"replace\",\"path\":\"/1\",\"value\":\"bam\"},{\"op\":\"remove\",\"path\":\"/2\"}]"); + } + + SECTION("flatten") + { + // a JSON value + const alt_json j = alt_json::parse(R"({"foo": ["bar", "baz"]})"); + const auto j2 = j.flatten(); + CHECK(j2.dump() == R"({"/foo/0":"bar","/foo/1":"baz"})"); + } } diff --git a/tests/src/unit-assert_macro.cpp b/tests/src/unit-assert_macro.cpp index 55eb3b9ec..41aca433d 100644 --- a/tests/src/unit-assert_macro.cpp +++ b/tests/src/unit-assert_macro.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-binary_formats.cpp b/tests/src/unit-binary_formats.cpp index b41a6fec1..cfbc2ef85 100644 --- a/tests/src/unit-binary_formats.cpp +++ b/tests/src/unit-binary_formats.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index 9f247fe6f..a7c305d91 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -109,7 +109,7 @@ struct trait_test_arg static constexpr bool max_in_range = MaxInRange; }; -TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) +TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses) { using nlohmann::detail::value_in_range_of; @@ -267,6 +267,34 @@ TEST_CASE("BJData") } } + SECTION("byte") + { + SECTION("0..255 (uint8)") + { + for (size_t i = 0; i <= 255; ++i) + { + CAPTURE(i) + + // create JSON value with integer number (no byte type in JSON) + json j = -1; + j.get_ref() = static_cast(i); + + // check type + CHECK(j.is_number_integer()); + + // create byte vector + std::vector const value + { + static_cast('B'), + static_cast(i), + }; + + // compare value + CHECK(json::from_bjdata(value) == j); + } + } + } + SECTION("number") { SECTION("signed") @@ -339,13 +367,13 @@ TEST_CASE("BJData") std::vector const numbers { -32769, - -100000, - -1000000, - -10000000, - -100000000, - -1000000000, - -2147483647 - 1, // https://stackoverflow.com/a/29356002/266378 - }; + -100000, + -1000000, + -10000000, + -100000000, + -1000000000, + -2147483647 - 1, // https://stackoverflow.com/a/29356002/266378 + }; for (const auto i : numbers) { CAPTURE(i) @@ -573,7 +601,7 @@ TEST_CASE("BJData") // check individual bytes CHECK(result[0] == 'I'); - auto const restored = static_cast(static_cast(result[2]) * 256 + static_cast(result[1])); + auto const restored = static_cast((static_cast(result[2]) * 256) + static_cast(result[1])); CHECK(restored == i); // roundtrip @@ -613,7 +641,7 @@ TEST_CASE("BJData") // check individual bytes CHECK(result[0] == 'u'); - auto const restored = static_cast(static_cast(result[2]) * 256 + static_cast(result[1])); + auto const restored = static_cast((static_cast(result[2]) * 256) + static_cast(result[1])); CHECK(restored == i); // roundtrip @@ -905,7 +933,7 @@ TEST_CASE("BJData") // check individual bytes CHECK(result[0] == 'I'); - auto const restored = static_cast(static_cast(result[2]) * 256 + static_cast(result[1])); + auto const restored = static_cast((static_cast(result[2]) * 256) + static_cast(result[1])); CHECK(restored == i); // roundtrip @@ -944,7 +972,7 @@ TEST_CASE("BJData") // check individual bytes CHECK(result[0] == 'u'); - auto const restored = static_cast(static_cast(result[2]) * 256 + static_cast(result[1])); + auto const restored = static_cast((static_cast(result[2]) * 256) + static_cast(result[1])); CHECK(restored == i); // roundtrip @@ -1501,262 +1529,316 @@ TEST_CASE("BJData") SECTION("binary") { - SECTION("N = 0..127") - { - for (std::size_t N = 0; N <= 127; ++N) - { - CAPTURE(N) - - // create JSON value with byte array containing of N * 'x' - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - // create expected byte vector - std::vector expected; - expected.push_back(static_cast('[')); - if (N != 0) + for (json::bjdata_version_t bjdata_version : { + json::bjdata_version_t::draft2, json::bjdata_version_t::draft3 + }) + { + CAPTURE(bjdata_version) + const bool draft3 = (bjdata_version == json::bjdata_version_t::draft3); + + SECTION("N = 0..127") + { + for (std::size_t N = 0; N <= 127; ++N) + { + CAPTURE(N) + + // create JSON value with byte array containing of N * 'x' + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + // create expected byte vector + std::vector expected; + expected.push_back(static_cast('[')); + if (draft3 || N != 0) + { + expected.push_back(static_cast('$')); + expected.push_back(static_cast(draft3 ? 'B' : 'U')); + } + expected.push_back(static_cast('#')); + expected.push_back(static_cast('i')); + expected.push_back(static_cast(N)); + for (size_t i = 0; i < N; ++i) + { + expected.push_back(0x78); + } + + // compare result + size + const auto result = json::to_bjdata(j, true, true, bjdata_version); + CHECK(result == expected); + if (!draft3 && N == 0) + { + CHECK(result.size() == N + 4); + } + else + { + CHECK(result.size() == N + 6); + } + + // check that no null byte is appended + if (N > 0) + { + CHECK(result.back() != '\x00'); + } + + if (draft3) + { + // roundtrip + CHECK(json::from_bjdata(result) == j); + CHECK(json::from_bjdata(result, true, false) == j); + } + else + { + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } + } + } + + SECTION("N = 128..255") + { + for (std::size_t N = 128; N <= 255; ++N) + { + CAPTURE(N) + + // create JSON value with byte array containing of N * 'x' + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + // create expected byte vector + std::vector expected; + expected.push_back(static_cast('[')); expected.push_back(static_cast('$')); + expected.push_back(static_cast(draft3 ? 'B' : 'U')); + expected.push_back(static_cast('#')); expected.push_back(static_cast('U')); - } - expected.push_back(static_cast('#')); - expected.push_back(static_cast('i')); - expected.push_back(static_cast(N)); - for (size_t i = 0; i < N; ++i) - { - expected.push_back(0x78); - } + expected.push_back(static_cast(N)); + for (size_t i = 0; i < N; ++i) + { + expected.push_back(0x78); + } - // compare result + size - const auto result = json::to_bjdata(j, true, true); - CHECK(result == expected); - if (N == 0) - { - CHECK(result.size() == N + 4); - } - else - { + // compare result + size + const auto result = json::to_bjdata(j, true, true, bjdata_version); + CHECK(result == expected); CHECK(result.size() == N + 6); - } - - // check that no null byte is appended - if (N > 0) - { + // check that no null byte is appended CHECK(result.back() != '\x00'); - } - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); - } - } - - SECTION("N = 128..255") - { - for (std::size_t N = 128; N <= 255; ++N) - { - CAPTURE(N) - - // create JSON value with byte array containing of N * 'x' - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - // create expected byte vector - std::vector expected; - expected.push_back(static_cast('[')); - expected.push_back(static_cast('$')); - expected.push_back(static_cast('U')); - expected.push_back(static_cast('#')); - expected.push_back(static_cast('U')); - expected.push_back(static_cast(N)); - for (size_t i = 0; i < N; ++i) - { - expected.push_back(0x78); - } - - // compare result + size - const auto result = json::to_bjdata(j, true, true); - CHECK(result == expected); - CHECK(result.size() == N + 6); - // check that no null byte is appended - CHECK(result.back() != '\x00'); - - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); - } - } - - SECTION("N = 256..32767") - { - for (const std::size_t N : + if (draft3) { - 256u, 999u, 1025u, 3333u, 2048u, 32767u - }) - { - CAPTURE(N) - - // create JSON value with byte array containing of N * 'x' - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - // create expected byte vector - std::vector expected(N + 7, 'x'); - expected[0] = '['; - expected[1] = '$'; - expected[2] = 'U'; - expected[3] = '#'; - expected[4] = 'I'; - expected[5] = static_cast(N & 0xFF); - expected[6] = static_cast((N >> 8) & 0xFF); - - // compare result + size - const auto result = json::to_bjdata(j, true, true); - CHECK(result == expected); - CHECK(result.size() == N + 7); - // check that no null byte is appended - CHECK(result.back() != '\x00'); - - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); - } - } - - SECTION("N = 32768..65535") - { - for (const std::size_t N : + // roundtrip + CHECK(json::from_bjdata(result) == j); + CHECK(json::from_bjdata(result, true, false) == j); + } + else { - 32768u, 55555u, 65535u - }) - { - CAPTURE(N) - - // create JSON value with byte array containing of N * 'x' - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - // create expected byte vector - std::vector expected(N + 7, 'x'); - expected[0] = '['; - expected[1] = '$'; - expected[2] = 'U'; - expected[3] = '#'; - expected[4] = 'u'; - expected[5] = static_cast(N & 0xFF); - expected[6] = static_cast((N >> 8) & 0xFF); - - // compare result + size - const auto result = json::to_bjdata(j, true, true); - CHECK(result == expected); - CHECK(result.size() == N + 7); - // check that no null byte is appended - CHECK(result.back() != '\x00'); - - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); - } - } - - SECTION("N = 65536..2147483647") - { - for (const std::size_t N : - { - 65536u, 77777u, 1048576u - }) - { - CAPTURE(N) - - // create JSON value with byte array containing of N * 'x' - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - // create expected byte vector - std::vector expected(N + 9, 'x'); - expected[0] = '['; - expected[1] = '$'; - expected[2] = 'U'; - expected[3] = '#'; - expected[4] = 'l'; - expected[5] = static_cast(N & 0xFF); - expected[6] = static_cast((N >> 8) & 0xFF); - expected[7] = static_cast((N >> 16) & 0xFF); - expected[8] = static_cast((N >> 24) & 0xFF); - - // compare result + size - const auto result = json::to_bjdata(j, true, true); - CHECK(result == expected); - CHECK(result.size() == N + 9); - // check that no null byte is appended - CHECK(result.back() != '\x00'); - - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); - } - } - - SECTION("Other Serializations") - { - const std::size_t N = 10; - const auto s = std::vector(N, 'x'); - json const j = json::binary(s); - - SECTION("No Count No Type") - { - std::vector expected; - expected.push_back(static_cast('[')); - for (std::size_t i = 0; i < N; ++i) - { - expected.push_back(static_cast('U')); - expected.push_back(static_cast(0x78)); + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } } - expected.push_back(static_cast(']')); - - // compare result + size - const auto result = json::to_bjdata(j, false, false); - CHECK(result == expected); - CHECK(result.size() == N + 12); - // check that no null byte is appended - CHECK(result.back() != '\x00'); - - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); } - SECTION("Yes Count No Type") + SECTION("N = 256..32767") { - std::vector expected; - expected.push_back(static_cast('[')); - expected.push_back(static_cast('#')); - expected.push_back(static_cast('i')); - expected.push_back(static_cast(N)); - - for (size_t i = 0; i < N; ++i) + for (const std::size_t N : + { + 256u, 999u, 1025u, 3333u, 2048u, 32767u + }) { - expected.push_back(static_cast('U')); - expected.push_back(static_cast(0x78)); + CAPTURE(N) + + // create JSON value with byte array containing of N * 'x' + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + // create expected byte vector + std::vector expected(N + 7, 'x'); + expected[0] = '['; + expected[1] = '$'; + expected[2] = draft3 ? 'B' : 'U'; + expected[3] = '#'; + expected[4] = 'I'; + expected[5] = static_cast(N & 0xFF); + expected[6] = static_cast((N >> 8) & 0xFF); + + // compare result + size + const auto result = json::to_bjdata(j, true, true, bjdata_version); + CHECK(result == expected); + CHECK(result.size() == N + 7); + // check that no null byte is appended + CHECK(result.back() != '\x00'); + + if (draft3) + { + // roundtrip + CHECK(json::from_bjdata(result) == j); + CHECK(json::from_bjdata(result, true, false) == j); + } + else + { + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } + } + } + + SECTION("N = 32768..65535") + { + for (const std::size_t N : + { + 32768u, 55555u, 65535u + }) + { + CAPTURE(N) + + // create JSON value with byte array containing of N * 'x' + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + // create expected byte vector + std::vector expected(N + 7, 'x'); + expected[0] = '['; + expected[1] = '$'; + expected[2] = draft3 ? 'B' : 'U'; + expected[3] = '#'; + expected[4] = 'u'; + expected[5] = static_cast(N & 0xFF); + expected[6] = static_cast((N >> 8) & 0xFF); + + // compare result + size + const auto result = json::to_bjdata(j, true, true, bjdata_version); + CHECK(result == expected); + CHECK(result.size() == N + 7); + // check that no null byte is appended + CHECK(result.back() != '\x00'); + + if (draft3) + { + // roundtrip + CHECK(json::from_bjdata(result) == j); + CHECK(json::from_bjdata(result, true, false) == j); + } + else + { + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } + } + } + + SECTION("N = 65536..2147483647") + { + for (const std::size_t N : + { + 65536u, 77777u, 1048576u + }) + { + CAPTURE(N) + + // create JSON value with byte array containing of N * 'x' + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + // create expected byte vector + std::vector expected(N + 9, 'x'); + expected[0] = '['; + expected[1] = '$'; + expected[2] = draft3 ? 'B' : 'U'; + expected[3] = '#'; + expected[4] = 'l'; + expected[5] = static_cast(N & 0xFF); + expected[6] = static_cast((N >> 8) & 0xFF); + expected[7] = static_cast((N >> 16) & 0xFF); + expected[8] = static_cast((N >> 24) & 0xFF); + + // compare result + size + const auto result = json::to_bjdata(j, true, true, bjdata_version); + CHECK(result == expected); + CHECK(result.size() == N + 9); + // check that no null byte is appended + CHECK(result.back() != '\x00'); + + if (draft3) + { + // roundtrip + CHECK(json::from_bjdata(result) == j); + CHECK(json::from_bjdata(result, true, false) == j); + } + else + { + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } + } + } + + SECTION("Other Serializations") + { + const std::size_t N = 10; + const auto s = std::vector(N, 'x'); + json const j = json::binary(s); + + SECTION("No Count No Type") + { + std::vector expected; + expected.push_back(static_cast('[')); + for (std::size_t i = 0; i < N; ++i) + { + expected.push_back(static_cast(draft3 ? 'B' : 'U')); + expected.push_back(static_cast(0x78)); + } + expected.push_back(static_cast(']')); + + // compare result + size + const auto result = json::to_bjdata(j, false, false, bjdata_version); + CHECK(result == expected); + CHECK(result.size() == N + 12); + // check that no null byte is appended + CHECK(result.back() != '\x00'); + + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); } - // compare result + size - const auto result = json::to_bjdata(j, true, false); - CHECK(result == expected); - CHECK(result.size() == N + 14); - // check that no null byte is appended - CHECK(result.back() != '\x00'); + SECTION("Yes Count No Type") + { + std::vector expected; + expected.push_back(static_cast('[')); + expected.push_back(static_cast('#')); + expected.push_back(static_cast('i')); + expected.push_back(static_cast(N)); - // roundtrip only works to an array of numbers - json j_out = s; - CHECK(json::from_bjdata(result) == j_out); - CHECK(json::from_bjdata(result, true, false) == j_out); + for (size_t i = 0; i < N; ++i) + { + expected.push_back(static_cast(draft3 ? 'B' : 'U')); + expected.push_back(static_cast(0x78)); + } + + // compare result + size + const auto result = json::to_bjdata(j, true, false, bjdata_version); + CHECK(result == expected); + CHECK(result.size() == N + 14); + // check that no null byte is appended + CHECK(result.back() != '\x00'); + + // roundtrip only works to an array of numbers + json j_out = s; + CHECK(json::from_bjdata(result) == j_out); + CHECK(json::from_bjdata(result, true, false) == j_out); + } } } } @@ -2334,6 +2416,7 @@ TEST_CASE("BJData") std::vector const v_D = {'[', '#', 'i', 2, 'D', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 'D', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40}; std::vector const v_S = {'[', '#', 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'}; std::vector const v_C = {'[', '#', 'i', 2, 'C', 'a', 'C', 'a'}; + std::vector const v_B = {'[', '#', 'i', 2, 'B', 0xFF, 'B', 0xFF}; // check if vector is parsed correctly CHECK(json::from_bjdata(v_TU) == json({true, true})); @@ -2351,6 +2434,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926})); CHECK(json::from_bjdata(v_S) == json({"a", "a"})); CHECK(json::from_bjdata(v_C) == json({"a", "a"})); + CHECK(json::from_bjdata(v_B) == json({255, 255})); // roundtrip: output should be optimized CHECK(json::to_bjdata(json::from_bjdata(v_T), true) == v_T); @@ -2367,6 +2451,7 @@ TEST_CASE("BJData") CHECK(json::to_bjdata(json::from_bjdata(v_D), true) == v_D); CHECK(json::to_bjdata(json::from_bjdata(v_S), true) == v_S); CHECK(json::to_bjdata(json::from_bjdata(v_C), true) == v_S); // char is serialized to string + CHECK(json::to_bjdata(json::from_bjdata(v_B), true) == v_U); // byte is serialized to uint8 } SECTION("optimized version (type and length)") @@ -2383,6 +2468,7 @@ TEST_CASE("BJData") std::vector const v_D = {'[', '$', 'D', '#', 'i', 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40}; std::vector const v_S = {'[', '#', 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'}; std::vector const v_C = {'[', '$', 'C', '#', 'i', 2, 'a', 'a'}; + std::vector const v_B = {'[', '$', 'B', '#', 'i', 2, 0xFF, 0xFF}; // check if vector is parsed correctly CHECK(json::from_bjdata(v_i) == json({127, 127})); @@ -2396,6 +2482,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926})); CHECK(json::from_bjdata(v_S) == json({"a", "a"})); CHECK(json::from_bjdata(v_C) == json({"a", "a"})); + CHECK(json::from_bjdata(v_B) == json::binary(std::vector({static_cast(255), static_cast(255)}))); // roundtrip: output should be optimized std::vector const v_empty = {'[', '#', 'i', 0}; @@ -2410,6 +2497,8 @@ TEST_CASE("BJData") CHECK(json::to_bjdata(json::from_bjdata(v_D), true, true) == v_D); CHECK(json::to_bjdata(json::from_bjdata(v_S), true, true) == v_S); CHECK(json::to_bjdata(json::from_bjdata(v_C), true, true) == v_S); // char is serialized to string + CHECK(json::to_bjdata(json::from_bjdata(v_B), true, true, json::bjdata_version_t::draft2) == v_U); + CHECK(json::to_bjdata(json::from_bjdata(v_B), true, true, json::bjdata_version_t::draft3) == v_B); } SECTION("optimized ndarray (type and vector-size as optimized 1D array)") @@ -2428,6 +2517,7 @@ TEST_CASE("BJData") std::vector const v_D = {'[', '$', 'D', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40}; std::vector const v_S = {'[', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'}; std::vector const v_C = {'[', '$', 'C', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 'a', 'a'}; + std::vector const v_B = {'[', '$', 'B', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xFF}; // check if vector is parsed correctly CHECK(json::from_bjdata(v_0) == json::array()); @@ -2443,6 +2533,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926})); CHECK(json::from_bjdata(v_S) == json({"a", "a"})); CHECK(json::from_bjdata(v_C) == json({"a", "a"})); + CHECK(json::from_bjdata(v_B) == json::binary(std::vector({static_cast(255), static_cast(255)}))); } SECTION("optimized ndarray (type and vector-size ndarray with JData annotations)") @@ -2460,6 +2551,7 @@ TEST_CASE("BJData") std::vector const v_d = {'[', '$', 'd', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0xA0, 0x40, 0x00, 0x00, 0xC0, 0x40}; std::vector const v_D = {'[', '$', 'D', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40}; std::vector const v_C = {'[', '$', 'C', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 'a', 'b', 'c', 'd', 'e', 'f'}; + std::vector const v_B = {'[', '$', 'B', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; // check if vector is parsed correctly CHECK(json::from_bjdata(v_e) == json({{"_ArrayData_", {254, 255}}, {"_ArraySize_", {2, 1}}, {"_ArrayType_", "uint8"}})); @@ -2475,6 +2567,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_d) == json({{"_ArrayData_", {1.f, 2.f, 3.f, 4.f, 5.f, 6.f}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "single"}})); CHECK(json::from_bjdata(v_D) == json({{"_ArrayData_", {1., 2., 3., 4., 5., 6.}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "double"}})); CHECK(json::from_bjdata(v_C) == json({{"_ArrayData_", {'a', 'b', 'c', 'd', 'e', 'f'}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "char"}})); + CHECK(json::from_bjdata(v_B) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "byte"}})); // roundtrip: output should be optimized CHECK(json::to_bjdata(json::from_bjdata(v_e), true, true) == v_e); @@ -2489,6 +2582,7 @@ TEST_CASE("BJData") CHECK(json::to_bjdata(json::from_bjdata(v_d), true, true) == v_d); CHECK(json::to_bjdata(json::from_bjdata(v_D), true, true) == v_D); CHECK(json::to_bjdata(json::from_bjdata(v_C), true, true) == v_C); + CHECK(json::to_bjdata(json::from_bjdata(v_B), true, true) == v_B); } SECTION("optimized ndarray (type and vector-size as 1D array)") @@ -2507,6 +2601,7 @@ TEST_CASE("BJData") std::vector const v_D = {'[', '$', 'D', '#', '[', 'i', 1, 'i', 2, ']', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40}; std::vector const v_S = {'[', '#', '[', 'i', 1, 'i', 2, ']', 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'}; std::vector const v_C = {'[', '$', 'C', '#', '[', 'i', 1, 'i', 2, ']', 'a', 'a'}; + std::vector const v_B = {'[', '$', 'B', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xFF}; std::vector const v_R = {'[', '#', '[', 'i', 2, ']', 'i', 6, 'U', 7}; // check if vector is parsed correctly @@ -2523,6 +2618,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926})); CHECK(json::from_bjdata(v_S) == json({"a", "a"})); CHECK(json::from_bjdata(v_C) == json({"a", "a"})); + CHECK(json::from_bjdata(v_B) == json::binary(std::vector({static_cast(255), static_cast(255)}))); CHECK(json::from_bjdata(v_R) == json({6, 7})); } @@ -2540,6 +2636,7 @@ TEST_CASE("BJData") std::vector const v_D = {'[', '$', 'D', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40}; std::vector const v_S = {'[', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'}; std::vector const v_C = {'[', '$', 'C', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 'a', 'a'}; + std::vector const v_B = {'[', '$', 'B', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xFF}; // check if vector is parsed correctly CHECK(json::from_bjdata(v_i) == json({127, 127})); @@ -2553,6 +2650,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926})); CHECK(json::from_bjdata(v_S) == json({"a", "a"})); CHECK(json::from_bjdata(v_C) == json({"a", "a"})); + CHECK(json::from_bjdata(v_B) == json::binary(std::vector({static_cast(255), static_cast(255)}))); } SECTION("invalid ndarray annotations remains as object") @@ -2594,6 +2692,17 @@ TEST_CASE("BJData") } } + SECTION("byte") + { + SECTION("parse bjdata markers in ubjson") + { + std::vector const v = {'B', 1}; + + json _; + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v), "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing UBJSON value: invalid byte: 0x42", json::parse_error&); + } + } + SECTION("strings") { SECTION("eof after S byte") @@ -2803,6 +2912,10 @@ TEST_CASE("BJData") std::vector const v0 = {'[', '#', 'T', ']'}; CHECK_THROWS_WITH(_ = json::from_bjdata(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x54"); CHECK(json::from_bjdata(v0, true, false).is_discarded()); + + std::vector const vB = {'[', '#', 'B', ']'}; + CHECK_THROWS_WITH(_ = json::from_bjdata(vB), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x42"); + CHECK(json::from_bjdata(v0, true, false).is_discarded()); } SECTION("parse bjdata markers as array size in ubjson") @@ -2904,6 +3017,10 @@ TEST_CASE("BJData") CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 18: syntax error while parsing BJData number: unexpected end of input", json::parse_error&); CHECK(json::from_bjdata(vU, true, false).is_discarded()); + std::vector const vB = {'[', '$', 'B', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 1, 2, 3, 4, 5}; + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 18: syntax error while parsing BJData number: unexpected end of input", json::parse_error&); + CHECK(json::from_bjdata(vU, true, false).is_discarded()); + std::vector const vT1 = {'[', '$', 'T', '#', '[', '$', 'i', '#', 'i', 2, 2, 3}; CHECK(json::from_bjdata(vT1, true, false).is_discarded()); @@ -3197,6 +3314,21 @@ TEST_CASE("Universal Binary JSON Specification Examples 1") CHECK(json::from_bjdata(v) == j); } + SECTION("Byte Type") + { + const auto s = std::vector( + { + static_cast(222), + static_cast(173), + static_cast(190), + static_cast(239) + }); + json const j = {{"binary", json::binary(s)}, {"val", 123}}; + std::vector const v = {'{', 'i', 6, 'b', 'i', 'n', 'a', 'r', 'y', '[', '$', 'B', '#', 'i', 4, 222, 173, 190, 239, 'i', 3, 'v', 'a', 'l', 'i', 123, '}'}; + //CHECK(json::to_bjdata(j) == v); // 123 value gets encoded as uint8 + CHECK(json::from_bjdata(v) == j); + } + SECTION("String Type") { SECTION("English") @@ -3448,7 +3580,7 @@ TEST_CASE("all BJData first bytes") // these bytes will fail immediately with exception parse_error.112 std::set supported = { - 'T', 'F', 'Z', 'U', 'i', 'I', 'l', 'L', 'd', 'D', 'C', 'S', '[', '{', 'N', 'H', 'u', 'm', 'M', 'h' + 'T', 'F', 'Z', 'B', 'U', 'i', 'I', 'l', 'L', 'd', 'D', 'C', 'S', '[', '{', 'N', 'H', 'u', 'm', 'M', 'h' }; for (auto i = 0; i < 256; ++i) diff --git a/tests/src/unit-bson.cpp b/tests/src/unit-bson.cpp index 13216f2f5..6f7153408 100644 --- a/tests/src/unit-bson.cpp +++ b/tests/src/unit-bson.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -331,7 +331,6 @@ TEST_CASE("BSON") SECTION("non-empty object with unsigned integer (64-bit) member") { - // directly encoding uint64 is not supported in bson (only for timestamp values) json const j = { { "entry", std::uint64_t{0x1234567804030201} } @@ -531,7 +530,6 @@ TEST_CASE("BSON") SECTION("Some more complex document") { - // directly encoding uint64 is not supported in bson (only for timestamp values) json const j = { {"double", 42.5}, @@ -621,7 +619,7 @@ TEST_CASE("BSON input/output_adapters") { SECTION("std::ostringstream") { - std::basic_ostringstream ss; + std::basic_ostringstream ss; json::to_bson(json_representation, ss); json j3 = json::from_bson(ss.str()); CHECK(json_representation == j3); @@ -1164,10 +1162,7 @@ TEST_CASE("BSON numerical data") std::vector const numbers { static_cast((std::numeric_limits::max)()) + 1ULL, - 10000000000000000000ULL, - 18000000000000000000ULL, - (std::numeric_limits::max)() - 1ULL, - (std::numeric_limits::max)(), + 0xffffffffffffffff, }; for (const auto i : numbers) @@ -1184,7 +1179,7 @@ TEST_CASE("BSON numerical data") std::vector const expected_bson = { 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) - 0x12u, /// entry: int64 + 0x11u, /// entry: uint64 'e', 'n', 't', 'r', 'y', '\x00', static_cast((iu >> (8u * 0u)) & 0xffu), static_cast((iu >> (8u * 1u)) & 0xffu), @@ -1197,12 +1192,15 @@ TEST_CASE("BSON numerical data") 0x00u // end marker }; - CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&); -#if JSON_DIAGNOSTICS - CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] (/entry) integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64"); -#else - CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64"); -#endif + const auto bson = json::to_bson(j); + CHECK(bson == expected_bson); + + auto j_roundtrip = json::from_bson(bson); + + CHECK(j.at("entry").is_number_unsigned()); + CHECK(j_roundtrip.at("entry").is_number_unsigned()); + CHECK(j_roundtrip == j); + CHECK(json::from_bson(bson, true, false) == j); } } diff --git a/tests/src/unit-byte_container_with_subtype.cpp b/tests/src/unit-byte_container_with_subtype.cpp index 4116076b0..3bdc241d4 100644 --- a/tests/src/unit-byte_container_with_subtype.cpp +++ b/tests/src/unit-byte_container_with_subtype.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-capacity.cpp b/tests/src/unit-capacity.cpp index 61203cc23..f85ea6f57 100644 --- a/tests/src/unit-capacity.cpp +++ b/tests/src/unit-capacity.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-cbor.cpp b/tests/src/unit-cbor.cpp index be94d2f6e..0404ca16b 100644 --- a/tests/src/unit-cbor.cpp +++ b/tests/src/unit-cbor.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -14,7 +14,6 @@ using nlohmann::json; #include #include #include -#include #include #include #include "make_test_data_available.hpp" @@ -241,13 +240,13 @@ TEST_CASE("CBOR") const std::vector numbers { -65537, - -100000, - -1000000, - -10000000, - -100000000, - -1000000000, - -4294967296, - }; + -100000, + -1000000, + -10000000, + -100000000, + -1000000000, + -4294967296, + }; for (const auto i : numbers) { CAPTURE(i) @@ -317,7 +316,7 @@ TEST_CASE("CBOR") // check individual bytes CHECK(result[0] == 0x39); - const auto restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + const auto restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == positive); CHECK(-1 - restored == i); @@ -505,7 +504,7 @@ TEST_CASE("CBOR") // check individual bytes CHECK(result[0] == 0x19); - const auto restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + const auto restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -744,7 +743,7 @@ TEST_CASE("CBOR") // check individual bytes CHECK(result[0] == 0x19); - const auto restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + const auto restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -990,7 +989,7 @@ TEST_CASE("CBOR") { 0xfa, 0xff, 0x7f, 0xff, 0xff }; - // the same with lowest float + // the same with the lowest float const auto result = json::to_cbor(j); CHECK(result == expected); // roundtrip @@ -1632,7 +1631,7 @@ TEST_CASE("CBOR") }; json j; - auto cbp = nlohmann::detail::json_sax_dom_callback_parser(j, callback, true); + auto cbp = nlohmann::detail::json_sax_dom_callback_parser(j, callback, true); CHECK(json::sax_parse(input, &cbp, json::input_format_t::cbor)); CHECK(j.at("foo").is_binary()); CHECK(binary_seen); @@ -1881,7 +1880,7 @@ TEST_CASE("single CBOR roundtrip") { SECTION("std::ostringstream") { - std::basic_ostringstream ss; + std::basic_ostringstream ss; json::to_cbor(j1, ss); json j3 = json::from_cbor(ss.str()); CHECK(j1 == j3); diff --git a/tests/src/unit-class_const_iterator.cpp b/tests/src/unit-class_const_iterator.cpp index 003ce8892..0171c4944 100644 --- a/tests/src/unit-class_const_iterator.cpp +++ b/tests/src/unit-class_const_iterator.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-class_iterator.cpp b/tests/src/unit-class_iterator.cpp index 296ffa3ff..4bf11f66a 100644 --- a/tests/src/unit-class_iterator.cpp +++ b/tests/src/unit-class_iterator.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-class_lexer.cpp b/tests/src/unit-class_lexer.cpp index ac0292531..a2f09d2f1 100644 --- a/tests/src/unit-class_lexer.cpp +++ b/tests/src/unit-class_lexer.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -23,7 +23,7 @@ json::lexer::token_type scan_string(const char* s, const bool ignore_comments) } } // namespace -std::string get_error_message(const char* s, bool ignore_comments = false); +std::string get_error_message(const char* s, bool ignore_comments = false); // NOLINT(misc-use-internal-linkage) std::string get_error_message(const char* s, const bool ignore_comments) { auto ia = nlohmann::detail::input_adapter(s); diff --git a/tests/src/unit-class_parser.cpp b/tests/src/unit-class_parser.cpp index f766842aa..549cd4f2b 100644 --- a/tests/src/unit-class_parser.cpp +++ b/tests/src/unit-class_parser.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -75,7 +75,7 @@ class SaxEventLogger bool start_object(std::size_t elements) { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_object()"); } @@ -100,7 +100,7 @@ class SaxEventLogger bool start_array(std::size_t elements) { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_array()"); } @@ -124,7 +124,7 @@ class SaxEventLogger return false; } - std::vector events {}; + std::vector events {}; // NOLINT(readability-redundant-member-init) bool errored = false; }; @@ -219,7 +219,7 @@ json parser_helper(const std::string& s) CHECK(j_nothrow == j); json j_sax; - nlohmann::detail::json_sax_dom_parser sdp(j_sax); + nlohmann::detail::json_sax_dom_parser sdp(j_sax); json::sax_parse(s, &sdp); CHECK(j_sax == j); @@ -828,7 +828,7 @@ TEST_CASE("parser class") // for ranges in range of IEEE 754-2008 binary64 (double precision) // this does not accommodate 64 bit integers without loss of accuracy. // As 64 bit integers are now widely used in software, it is desirable - // to expand support to to the full 64 bit (signed and unsigned) range + // to expand support to the full 64 bit (signed and unsigned) range // i.e. -(2**63) -> (2**64)-1. // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) diff --git a/tests/src/unit-class_parser_diagnostic_positions.cpp b/tests/src/unit-class_parser_diagnostic_positions.cpp new file mode 100644 index 000000000..976c4f9db --- /dev/null +++ b/tests/src/unit-class_parser_diagnostic_positions.cpp @@ -0,0 +1,1957 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" +#define JSON_TESTS_PRIVATE +#ifdef JSON_DIAGNOSTIC_POSITIONS + #undef JSON_DIAGNOSTIC_POSITIONS +#endif + +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include +using nlohmann::json; + +#ifdef JSON_TEST_NO_GLOBAL_UDLS + using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) +#endif + +#include + +namespace +{ +class SaxEventLogger +{ + public: + bool null() + { + events.emplace_back("null()"); + return true; + } + + bool boolean(bool val) + { + events.emplace_back(val ? "boolean(true)" : "boolean(false)"); + return true; + } + + bool number_integer(json::number_integer_t val) + { + events.push_back("number_integer(" + std::to_string(val) + ")"); + return true; + } + + bool number_unsigned(json::number_unsigned_t val) + { + events.push_back("number_unsigned(" + std::to_string(val) + ")"); + return true; + } + + bool number_float(json::number_float_t /*unused*/, const std::string& s) + { + events.push_back("number_float(" + s + ")"); + return true; + } + + bool string(std::string& val) + { + events.push_back("string(" + val + ")"); + return true; + } + + bool binary(json::binary_t& val) + { + std::string binary_contents = "binary("; + std::string comma_space; + for (auto b : val) + { + binary_contents.append(comma_space); + binary_contents.append(std::to_string(static_cast(b))); + comma_space = ", "; + } + binary_contents.append(")"); + events.push_back(binary_contents); + return true; + } + + bool start_object(std::size_t elements) + { + if (elements == (std::numeric_limits::max)()) + { + events.emplace_back("start_object()"); + } + else + { + events.push_back("start_object(" + std::to_string(elements) + ")"); + } + return true; + } + + bool key(std::string& val) + { + events.push_back("key(" + val + ")"); + return true; + } + + bool end_object() + { + events.emplace_back("end_object()"); + return true; + } + + bool start_array(std::size_t elements) + { + if (elements == (std::numeric_limits::max)()) + { + events.emplace_back("start_array()"); + } + else + { + events.push_back("start_array(" + std::to_string(elements) + ")"); + } + return true; + } + + bool end_array() + { + events.emplace_back("end_array()"); + return true; + } + + bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/) + { + errored = true; + events.push_back("parse_error(" + std::to_string(position) + ")"); + return false; + } + + std::vector events {}; // NOLINT(readability-redundant-member-init) + bool errored = false; +}; + +class SaxCountdown : public nlohmann::json::json_sax_t +{ + public: + explicit SaxCountdown(const int count) : events_left(count) + {} + + bool null() override + { + return events_left-- > 0; + } + + bool boolean(bool /*val*/) override + { + return events_left-- > 0; + } + + bool number_integer(json::number_integer_t /*val*/) override + { + return events_left-- > 0; + } + + bool number_unsigned(json::number_unsigned_t /*val*/) override + { + return events_left-- > 0; + } + + bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override + { + return events_left-- > 0; + } + + bool string(std::string& /*val*/) override + { + return events_left-- > 0; + } + + bool binary(json::binary_t& /*val*/) override + { + return events_left-- > 0; + } + + bool start_object(std::size_t /*elements*/) override + { + return events_left-- > 0; + } + + bool key(std::string& /*val*/) override + { + return events_left-- > 0; + } + + bool end_object() override + { + return events_left-- > 0; + } + + bool start_array(std::size_t /*elements*/) override + { + return events_left-- > 0; + } + + bool end_array() override + { + return events_left-- > 0; + } + + bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override + { + return false; + } + + private: + int events_left = 0; +}; + +json parser_helper(const std::string& s); +bool accept_helper(const std::string& s); +void comments_helper(const std::string& s); + +json parser_helper(const std::string& s) +{ + json j; + json::parser(nlohmann::detail::input_adapter(s)).parse(true, j); + + // if this line was reached, no exception occurred + // -> check if result is the same without exceptions + json j_nothrow; + CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j_nothrow)); + CHECK(j_nothrow == j); + + json j_sax; + nlohmann::detail::json_sax_dom_parser sdp(j_sax); + json::sax_parse(s, &sdp); + CHECK(j_sax == j); + + comments_helper(s); + + return j; +} + +bool accept_helper(const std::string& s) +{ + CAPTURE(s) + + // 1. parse s without exceptions + json j; + CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j)); + const bool ok_noexcept = !j.is_discarded(); + + // 2. accept s + const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true); + + // 3. check if both approaches come to the same result + CHECK(ok_noexcept == ok_accept); + + // 4. parse with SAX (compare with relaxed accept result) + SaxEventLogger el; + CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false)); + CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored); + + // 5. parse with simple callback + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept + { + return true; + }; + json const j_cb = json::parse(s, cb, false); + const bool ok_noexcept_cb = !j_cb.is_discarded(); + + // 6. check if this approach came to the same result + CHECK(ok_noexcept == ok_noexcept_cb); + + // 7. check if comments are properly ignored + if (ok_accept) + { + comments_helper(s); + } + + // 8. return result + return ok_accept; +} + +void comments_helper(const std::string& s) +{ + json _; + + // parse/accept with default parser + CHECK_NOTHROW(_ = json::parse(s)); + CHECK(json::accept(s)); + + // parse/accept while skipping comments + CHECK_NOTHROW(_ = json::parse(s, nullptr, false, true)); + CHECK(json::accept(s, true)); + + std::vector json_with_comments; + + // start with a comment + json_with_comments.push_back(std::string("// this is a comment\n") + s); + json_with_comments.push_back(std::string("/* this is a comment */") + s); + // end with a comment + json_with_comments.push_back(s + "// this is a comment"); + json_with_comments.push_back(s + "/* this is a comment */"); + + // check all strings + for (const auto& json_with_comment : json_with_comments) + { + CAPTURE(json_with_comment) + CHECK_THROWS_AS(_ = json::parse(json_with_comment), json::parse_error); + CHECK(!json::accept(json_with_comment)); + + CHECK_NOTHROW(_ = json::parse(json_with_comment, nullptr, true, true)); + CHECK(json::accept(json_with_comment, true)); + } +} + +/** + * Validates that the generated JSON object is the same as expected + * Validates that the start position and end position match the start and end of the string + * + * This check assumes that there is no whitespace around the json object in the original string. + */ +void validate_generated_json_and_start_end_pos_helper(const std::string& original_string, const json& j, const json& check) +{ + CHECK(j == check); + CHECK(j.start_pos() == 0); + CHECK(j.end_pos() == original_string.size()); +} + +/** + * Parses the root object from the given root string and validates that the start and end positions for the nested object are correct. + * + * This checks that whitespace around the nested object is included in the start and end positions of the root object. + */ +void validate_start_end_pos_for_nested_obj_helper(const std::string& nested_type_json_str, const std::string& root_type_json_str, const json& expected_json, const json::parser_callback_t& cb = nullptr) +{ + json j; + + // 1. If callback is provided, use callback version of parse() + if (cb) + { + j = json::parse(root_type_json_str, cb); + } + else + { + j = json::parse(root_type_json_str); + } + + // 2. Check if the generated JSON is as expected + // Assumptions: The root_type_json_str does not have any whitespace around the json object + validate_generated_json_and_start_end_pos_helper(root_type_json_str, j, expected_json); + + // 3. Get the nested object + const auto& nested = j["nested"]; + // 4. Check if the start and end positions are generated correctly for nested objects and arrays + CHECK(nested_type_json_str == root_type_json_str.substr(nested.start_pos(), nested.end_pos() - nested.start_pos())); +} + +} // namespace + +TEST_CASE("parser class") +{ + SECTION("parse") + { + SECTION("null") + { + CHECK(parser_helper("null") == json(nullptr)); + } + + SECTION("true") + { + CHECK(parser_helper("true") == json(true)); + } + + SECTION("false") + { + CHECK(parser_helper("false") == json(false)); + } + + SECTION("array") + { + SECTION("empty array") + { + CHECK(parser_helper("[]") == json(json::value_t::array)); + CHECK(parser_helper("[ ]") == json(json::value_t::array)); + } + + SECTION("nonempty array") + { + CHECK(parser_helper("[true, false, null]") == json({true, false, nullptr})); + } + } + + SECTION("object") + { + SECTION("empty object") + { + CHECK(parser_helper("{}") == json(json::value_t::object)); + CHECK(parser_helper("{ }") == json(json::value_t::object)); + } + + SECTION("nonempty object") + { + CHECK(parser_helper("{\"\": true, \"one\": 1, \"two\": null}") == json({{"", true}, {"one", 1}, {"two", nullptr}})); + } + } + + SECTION("string") + { + // empty string + CHECK(parser_helper("\"\"") == json(json::value_t::string)); + + SECTION("errors") + { + // error: tab in string + CHECK_THROWS_WITH_AS(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"'", json::parse_error&); + // error: newline in string + CHECK_THROWS_WITH_AS(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"'", json::parse_error&); + // error: backspace in string + CHECK_THROWS_WITH_AS(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"'", json::parse_error&); + // improve code coverage + CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); + // unescaped control characters + CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul) + CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0004 (EOT) must be escaped to \\u0004; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0005 (ENQ) must be escaped to \\u0005; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0006 (ACK) must be escaped to \\u0006; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0007 (BEL) must be escaped to \\u0007; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000B (VT) must be escaped to \\u000B; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000E (SO) must be escaped to \\u000E; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000F (SI) must be escaped to \\u000F; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0010 (DLE) must be escaped to \\u0010; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0011 (DC1) must be escaped to \\u0011; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0012 (DC2) must be escaped to \\u0012; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0013 (DC3) must be escaped to \\u0013; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0014 (DC4) must be escaped to \\u0014; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0015 (NAK) must be escaped to \\u0015; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0016 (SYN) must be escaped to \\u0016; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0017 (ETB) must be escaped to \\u0017; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0018 (CAN) must be escaped to \\u0018; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0019 (EM) must be escaped to \\u0019; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001A (SUB) must be escaped to \\u001A; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001B (ESC) must be escaped to \\u001B; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001C (FS) must be escaped to \\u001C; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001D (GS) must be escaped to \\u001D; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001E (RS) must be escaped to \\u001E; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001F (US) must be escaped to \\u001F; last read: '\"'", json::parse_error&); + + SECTION("additional test for null byte") + { + // The test above for the null byte is wrong, because passing + // a string to the parser only reads int until it encounters + // a null byte. This test inserts the null byte later on and + // uses an iterator range. + std::string s = "\"1\""; + s[1] = '\0'; + json _; + CHECK_THROWS_WITH_AS(_ = json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0000 (NUL) must be escaped to \\u0000; last read: '\"'", json::parse_error&); + } + } + + SECTION("escaped") + { + // quotation mark "\"" + auto r1 = R"("\"")"_json; + CHECK(parser_helper("\"\\\"\"") == r1); + // reverse solidus "\\" + auto r2 = R"("\\")"_json; + CHECK(parser_helper("\"\\\\\"") == r2); + // solidus + CHECK(parser_helper("\"\\/\"") == R"("/")"_json); + // backspace + CHECK(parser_helper("\"\\b\"") == json("\b")); + // formfeed + CHECK(parser_helper("\"\\f\"") == json("\f")); + // newline + CHECK(parser_helper("\"\\n\"") == json("\n")); + // carriage return + CHECK(parser_helper("\"\\r\"") == json("\r")); + // horizontal tab + CHECK(parser_helper("\"\\t\"") == json("\t")); + + CHECK(parser_helper("\"\\u0001\"").get() == "\x01"); + CHECK(parser_helper("\"\\u000a\"").get() == "\n"); + CHECK(parser_helper("\"\\u00b0\"").get() == "°"); + CHECK(parser_helper("\"\\u0c00\"").get() == "ఀ"); + CHECK(parser_helper("\"\\ud000\"").get() == "퀀"); + CHECK(parser_helper("\"\\u000E\"").get() == "\x0E"); + CHECK(parser_helper("\"\\u00F0\"").get() == "ð"); + CHECK(parser_helper("\"\\u0100\"").get() == "Ā"); + CHECK(parser_helper("\"\\u2000\"").get() == " "); + CHECK(parser_helper("\"\\uFFFF\"").get() == "￿"); + CHECK(parser_helper("\"\\u20AC\"").get() == "€"); + CHECK(parser_helper("\"€\"").get() == "€"); + CHECK(parser_helper("\"🎈\"").get() == "🎈"); + + CHECK(parser_helper("\"\\ud80c\\udc60\"").get() == "\xf0\x93\x81\xa0"); + CHECK(parser_helper("\"\\ud83c\\udf1e\"").get() == "🌞"); + } + } + + SECTION("number") + { + SECTION("integers") + { + SECTION("without exponent") + { + CHECK(parser_helper("-128") == json(-128)); + CHECK(parser_helper("-0") == json(-0)); + CHECK(parser_helper("0") == json(0)); + CHECK(parser_helper("128") == json(128)); + } + + SECTION("with exponent") + { + CHECK(parser_helper("0e1") == json(0e1)); + CHECK(parser_helper("0E1") == json(0e1)); + + CHECK(parser_helper("10000E-4") == json(10000e-4)); + CHECK(parser_helper("10000E-3") == json(10000e-3)); + CHECK(parser_helper("10000E-2") == json(10000e-2)); + CHECK(parser_helper("10000E-1") == json(10000e-1)); + CHECK(parser_helper("10000E0") == json(10000e0)); + CHECK(parser_helper("10000E1") == json(10000e1)); + CHECK(parser_helper("10000E2") == json(10000e2)); + CHECK(parser_helper("10000E3") == json(10000e3)); + CHECK(parser_helper("10000E4") == json(10000e4)); + + CHECK(parser_helper("10000e-4") == json(10000e-4)); + CHECK(parser_helper("10000e-3") == json(10000e-3)); + CHECK(parser_helper("10000e-2") == json(10000e-2)); + CHECK(parser_helper("10000e-1") == json(10000e-1)); + CHECK(parser_helper("10000e0") == json(10000e0)); + CHECK(parser_helper("10000e1") == json(10000e1)); + CHECK(parser_helper("10000e2") == json(10000e2)); + CHECK(parser_helper("10000e3") == json(10000e3)); + CHECK(parser_helper("10000e4") == json(10000e4)); + + CHECK(parser_helper("-0e1") == json(-0e1)); + CHECK(parser_helper("-0E1") == json(-0e1)); + CHECK(parser_helper("-0E123") == json(-0e123)); + + // numbers after exponent + CHECK(parser_helper("10E0") == json(10e0)); + CHECK(parser_helper("10E1") == json(10e1)); + CHECK(parser_helper("10E2") == json(10e2)); + CHECK(parser_helper("10E3") == json(10e3)); + CHECK(parser_helper("10E4") == json(10e4)); + CHECK(parser_helper("10E5") == json(10e5)); + CHECK(parser_helper("10E6") == json(10e6)); + CHECK(parser_helper("10E7") == json(10e7)); + CHECK(parser_helper("10E8") == json(10e8)); + CHECK(parser_helper("10E9") == json(10e9)); + CHECK(parser_helper("10E+0") == json(10e0)); + CHECK(parser_helper("10E+1") == json(10e1)); + CHECK(parser_helper("10E+2") == json(10e2)); + CHECK(parser_helper("10E+3") == json(10e3)); + CHECK(parser_helper("10E+4") == json(10e4)); + CHECK(parser_helper("10E+5") == json(10e5)); + CHECK(parser_helper("10E+6") == json(10e6)); + CHECK(parser_helper("10E+7") == json(10e7)); + CHECK(parser_helper("10E+8") == json(10e8)); + CHECK(parser_helper("10E+9") == json(10e9)); + CHECK(parser_helper("10E-1") == json(10e-1)); + CHECK(parser_helper("10E-2") == json(10e-2)); + CHECK(parser_helper("10E-3") == json(10e-3)); + CHECK(parser_helper("10E-4") == json(10e-4)); + CHECK(parser_helper("10E-5") == json(10e-5)); + CHECK(parser_helper("10E-6") == json(10e-6)); + CHECK(parser_helper("10E-7") == json(10e-7)); + CHECK(parser_helper("10E-8") == json(10e-8)); + CHECK(parser_helper("10E-9") == json(10e-9)); + } + + SECTION("edge cases") + { + // From RFC8259, Section 6: + // Note that when such software is used, numbers that are + // integers and are in the range [-(2**53)+1, (2**53)-1] + // are interoperable in the sense that implementations will + // agree exactly on their numeric values. + + // -(2**53)+1 + CHECK(parser_helper("-9007199254740991").get() == -9007199254740991); + // (2**53)-1 + CHECK(parser_helper("9007199254740991").get() == 9007199254740991); + } + + SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64-bit integers) + { + // While RFC8259, Section 6 specifies a preference for support + // for ranges in range of IEEE 754-2008 binary64 (double precision) + // this does not accommodate 64-bit integers without loss of accuracy. + // As 64-bit integers are now widely used in software, it is desirable + // to expand support to the full 64 bit (signed and unsigned) range + // i.e. -(2**63) -> (2**64)-1. + + // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) + CHECK(parser_helper("-9223372036854775808").get() == -9223372036854775807 - 1); + // (2**63)-1 + CHECK(parser_helper("9223372036854775807").get() == 9223372036854775807); + // (2**64)-1 + CHECK(parser_helper("18446744073709551615").get() == 18446744073709551615u); + } + } + + SECTION("floating-point") + { + SECTION("without exponent") + { + CHECK(parser_helper("-128.5") == json(-128.5)); + CHECK(parser_helper("0.999") == json(0.999)); + CHECK(parser_helper("128.5") == json(128.5)); + CHECK(parser_helper("-0.0") == json(-0.0)); + } + + SECTION("with exponent") + { + CHECK(parser_helper("-128.5E3") == json(-128.5E3)); + CHECK(parser_helper("-128.5E-3") == json(-128.5E-3)); + CHECK(parser_helper("-0.0e1") == json(-0.0e1)); + CHECK(parser_helper("-0.0E1") == json(-0.0e1)); + } + } + + SECTION("overflow") + { + // overflows during parsing yield an exception + CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); + } + + SECTION("invalid numbers") + { + // numbers must not begin with "+" + CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); + + CHECK_THROWS_WITH_AS(parser_helper("01"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-01"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("--1"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1."), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1E"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1E-"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1.E1"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-1E"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0E#"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0E-#"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0#"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0.0:"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0E123:"), + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"), + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0e-:"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0f"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input", json::parse_error&); + } + } + } + + SECTION("accept") + { + SECTION("null") + { + CHECK(accept_helper("null")); + } + + SECTION("true") + { + CHECK(accept_helper("true")); + } + + SECTION("false") + { + CHECK(accept_helper("false")); + } + + SECTION("array") + { + SECTION("empty array") + { + CHECK(accept_helper("[]")); + CHECK(accept_helper("[ ]")); + } + + SECTION("nonempty array") + { + CHECK(accept_helper("[true, false, null]")); + } + } + + SECTION("object") + { + SECTION("empty object") + { + CHECK(accept_helper("{}")); + CHECK(accept_helper("{ }")); + } + + SECTION("nonempty object") + { + CHECK(accept_helper("{\"\": true, \"one\": 1, \"two\": null}")); + } + } + + SECTION("string") + { + // empty string + CHECK(accept_helper("\"\"")); + + SECTION("errors") + { + // error: tab in string + CHECK(accept_helper("\"\t\"") == false); + // error: newline in string + CHECK(accept_helper("\"\n\"") == false); + CHECK(accept_helper("\"\r\"") == false); + // error: backspace in string + CHECK(accept_helper("\"\b\"") == false); + // improve code coverage + CHECK(accept_helper("\uFF01") == false); + CHECK(accept_helper("[-4:1,]") == false); + // unescaped control characters + CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul) + CHECK(accept_helper("\"\x01\"") == false); + CHECK(accept_helper("\"\x02\"") == false); + CHECK(accept_helper("\"\x03\"") == false); + CHECK(accept_helper("\"\x04\"") == false); + CHECK(accept_helper("\"\x05\"") == false); + CHECK(accept_helper("\"\x06\"") == false); + CHECK(accept_helper("\"\x07\"") == false); + CHECK(accept_helper("\"\x08\"") == false); + CHECK(accept_helper("\"\x09\"") == false); + CHECK(accept_helper("\"\x0a\"") == false); + CHECK(accept_helper("\"\x0b\"") == false); + CHECK(accept_helper("\"\x0c\"") == false); + CHECK(accept_helper("\"\x0d\"") == false); + CHECK(accept_helper("\"\x0e\"") == false); + CHECK(accept_helper("\"\x0f\"") == false); + CHECK(accept_helper("\"\x10\"") == false); + CHECK(accept_helper("\"\x11\"") == false); + CHECK(accept_helper("\"\x12\"") == false); + CHECK(accept_helper("\"\x13\"") == false); + CHECK(accept_helper("\"\x14\"") == false); + CHECK(accept_helper("\"\x15\"") == false); + CHECK(accept_helper("\"\x16\"") == false); + CHECK(accept_helper("\"\x17\"") == false); + CHECK(accept_helper("\"\x18\"") == false); + CHECK(accept_helper("\"\x19\"") == false); + CHECK(accept_helper("\"\x1a\"") == false); + CHECK(accept_helper("\"\x1b\"") == false); + CHECK(accept_helper("\"\x1c\"") == false); + CHECK(accept_helper("\"\x1d\"") == false); + CHECK(accept_helper("\"\x1e\"") == false); + CHECK(accept_helper("\"\x1f\"") == false); + } + + SECTION("escaped") + { + // quotation mark "\"" + auto r1 = R"("\"")"_json; + CHECK(accept_helper("\"\\\"\"")); + // reverse solidus "\\" + auto r2 = R"("\\")"_json; + CHECK(accept_helper("\"\\\\\"")); + // solidus + CHECK(accept_helper("\"\\/\"")); + // backspace + CHECK(accept_helper("\"\\b\"")); + // formfeed + CHECK(accept_helper("\"\\f\"")); + // newline + CHECK(accept_helper("\"\\n\"")); + // carriage return + CHECK(accept_helper("\"\\r\"")); + // horizontal tab + CHECK(accept_helper("\"\\t\"")); + + CHECK(accept_helper("\"\\u0001\"")); + CHECK(accept_helper("\"\\u000a\"")); + CHECK(accept_helper("\"\\u00b0\"")); + CHECK(accept_helper("\"\\u0c00\"")); + CHECK(accept_helper("\"\\ud000\"")); + CHECK(accept_helper("\"\\u000E\"")); + CHECK(accept_helper("\"\\u00F0\"")); + CHECK(accept_helper("\"\\u0100\"")); + CHECK(accept_helper("\"\\u2000\"")); + CHECK(accept_helper("\"\\uFFFF\"")); + CHECK(accept_helper("\"\\u20AC\"")); + CHECK(accept_helper("\"€\"")); + CHECK(accept_helper("\"🎈\"")); + + CHECK(accept_helper("\"\\ud80c\\udc60\"")); + CHECK(accept_helper("\"\\ud83c\\udf1e\"")); + } + } + + SECTION("number") + { + SECTION("integers") + { + SECTION("without exponent") + { + CHECK(accept_helper("-128")); + CHECK(accept_helper("-0")); + CHECK(accept_helper("0")); + CHECK(accept_helper("128")); + } + + SECTION("with exponent") + { + CHECK(accept_helper("0e1")); + CHECK(accept_helper("0E1")); + + CHECK(accept_helper("10000E-4")); + CHECK(accept_helper("10000E-3")); + CHECK(accept_helper("10000E-2")); + CHECK(accept_helper("10000E-1")); + CHECK(accept_helper("10000E0")); + CHECK(accept_helper("10000E1")); + CHECK(accept_helper("10000E2")); + CHECK(accept_helper("10000E3")); + CHECK(accept_helper("10000E4")); + + CHECK(accept_helper("10000e-4")); + CHECK(accept_helper("10000e-3")); + CHECK(accept_helper("10000e-2")); + CHECK(accept_helper("10000e-1")); + CHECK(accept_helper("10000e0")); + CHECK(accept_helper("10000e1")); + CHECK(accept_helper("10000e2")); + CHECK(accept_helper("10000e3")); + CHECK(accept_helper("10000e4")); + + CHECK(accept_helper("-0e1")); + CHECK(accept_helper("-0E1")); + CHECK(accept_helper("-0E123")); + } + + SECTION("edge cases") + { + // From RFC8259, Section 6: + // Note that when such software is used, numbers that are + // integers and are in the range [-(2**53)+1, (2**53)-1] + // are interoperable in the sense that implementations will + // agree exactly on their numeric values. + + // -(2**53)+1 + CHECK(accept_helper("-9007199254740991")); + // (2**53)-1 + CHECK(accept_helper("9007199254740991")); + } + + SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64-bit integers) + { + // While RFC8259, Section 6 specifies a preference for support + // for ranges in range of IEEE 754-2008 binary64 (double precision) + // this does not accommodate 64 bit integers without loss of accuracy. + // As 64 bit integers are now widely used in software, it is desirable + // to expand support to the full 64 bit (signed and unsigned) range + // i.e. -(2**63) -> (2**64)-1. + + // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) + CHECK(accept_helper("-9223372036854775808")); + // (2**63)-1 + CHECK(accept_helper("9223372036854775807")); + // (2**64)-1 + CHECK(accept_helper("18446744073709551615")); + } + } + + SECTION("floating-point") + { + SECTION("without exponent") + { + CHECK(accept_helper("-128.5")); + CHECK(accept_helper("0.999")); + CHECK(accept_helper("128.5")); + CHECK(accept_helper("-0.0")); + } + + SECTION("with exponent") + { + CHECK(accept_helper("-128.5E3")); + CHECK(accept_helper("-128.5E-3")); + CHECK(accept_helper("-0.0e1")); + CHECK(accept_helper("-0.0E1")); + } + } + + SECTION("overflow") + { + // overflows during parsing + CHECK(!accept_helper("1.18973e+4932")); + } + + SECTION("invalid numbers") + { + CHECK(accept_helper("01") == false); + CHECK(accept_helper("--1") == false); + CHECK(accept_helper("1.") == false); + CHECK(accept_helper("1E") == false); + CHECK(accept_helper("1E-") == false); + CHECK(accept_helper("1.E1") == false); + CHECK(accept_helper("-1E") == false); + CHECK(accept_helper("-0E#") == false); + CHECK(accept_helper("-0E-#") == false); + CHECK(accept_helper("-0#") == false); + CHECK(accept_helper("-0.0:") == false); + CHECK(accept_helper("-0.0Z") == false); + CHECK(accept_helper("-0E123:") == false); + CHECK(accept_helper("-0e0-:") == false); + CHECK(accept_helper("-0e-:") == false); + CHECK(accept_helper("-0f") == false); + + // numbers must not begin with "+" + CHECK(accept_helper("+1") == false); + CHECK(accept_helper("+0") == false); + } + } + } + + SECTION("parse errors") + { + // unexpected end of number + CHECK_THROWS_WITH_AS(parser_helper("0."), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("--"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-0."), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-."), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("-:"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("0.:"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("e."), + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1e."), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1e/"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1e:"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1E."), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1E/"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("1E:"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'", json::parse_error&); + + // unexpected end of null + CHECK_THROWS_WITH_AS(parser_helper("n"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("nu"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("nul"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("nulk"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("nulm"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'", json::parse_error&); + + // unexpected end of true + CHECK_THROWS_WITH_AS(parser_helper("t"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("tr"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("tru"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("trud"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("truf"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'", json::parse_error&); + + // unexpected end of false + CHECK_THROWS_WITH_AS(parser_helper("f"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("fa"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("fal"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("fals"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("falsd"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("falsf"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'", json::parse_error&); + + // missing/unexpected end of array + CHECK_THROWS_WITH_AS(parser_helper("["), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("[1"), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("[1,"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("[1,]"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("]"), + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); + + // missing/unexpected end of object + CHECK_THROWS_WITH_AS(parser_helper("{"), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""), + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"), + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"), + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"), + "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("}"), + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); + + // missing/unexpected end of string + CHECK_THROWS_WITH_AS(parser_helper("\""), + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\\""), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""), + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""), + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u"), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"), + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'", json::parse_error&); + CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"), + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'", json::parse_error&); + + // invalid escapes + for (int c = 1; c < 128; ++c) + { + auto s = std::string("\"\\") + std::string(1, static_cast(c)) + "\""; + + switch (c) + { + // valid escapes + case ('"'): + case ('\\'): + case ('/'): + case ('b'): + case ('f'): + case ('n'): + case ('r'): + case ('t'): + { + CHECK_NOTHROW(parser_helper(s)); + break; + } + + // \u must be followed with four numbers, so we skip it here + case ('u'): + { + break; + } + + // any other combination of backslash and character is invalid + default: + { + CHECK_THROWS_AS(parser_helper(s), json::parse_error&); + // only check error message if c is not a control character + if (c > 0x1f) + { + CHECK_THROWS_WITH_STD_STR(parser_helper(s), + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast(c)) + "'"); + } + break; + } + } + } + + // invalid \uxxxx escapes + { + // check whether character is a valid hex character + const auto valid = [](int c) + { + switch (c) + { + case ('0'): + case ('1'): + case ('2'): + case ('3'): + case ('4'): + case ('5'): + case ('6'): + case ('7'): + case ('8'): + case ('9'): + case ('a'): + case ('b'): + case ('c'): + case ('d'): + case ('e'): + case ('f'): + case ('A'): + case ('B'): + case ('C'): + case ('D'): + case ('E'): + case ('F'): + { + return true; + } + + default: + { + return false; + } + } + }; + + for (int c = 1; c < 128; ++c) + { + std::string const s = "\"\\u"; + + // create a string with the iterated character at each position + auto s1 = s + "000" + std::string(1, static_cast(c)) + "\""; + auto s2 = s + "00" + std::string(1, static_cast(c)) + "0\""; + auto s3 = s + "0" + std::string(1, static_cast(c)) + "00\""; + auto s4 = s + std::string(1, static_cast(c)) + "000\""; + + if (valid(c)) + { + CAPTURE(s1) + CHECK_NOTHROW(parser_helper(s1)); + CAPTURE(s2) + CHECK_NOTHROW(parser_helper(s2)); + CAPTURE(s3) + CHECK_NOTHROW(parser_helper(s3)); + CAPTURE(s4) + CHECK_NOTHROW(parser_helper(s4)); + } + else + { + CAPTURE(s1) + CHECK_THROWS_AS(parser_helper(s1), json::parse_error&); + // only check error message if c is not a control character + if (c > 0x1f) + { + CHECK_THROWS_WITH_STD_STR(parser_helper(s1), + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'"); + } + + CAPTURE(s2) + CHECK_THROWS_AS(parser_helper(s2), json::parse_error&); + // only check error message if c is not a control character + if (c > 0x1f) + { + CHECK_THROWS_WITH_STD_STR(parser_helper(s2), + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'"); + } + + CAPTURE(s3) + CHECK_THROWS_AS(parser_helper(s3), json::parse_error&); + // only check error message if c is not a control character + if (c > 0x1f) + { + CHECK_THROWS_WITH_STD_STR(parser_helper(s3), + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'"); + } + + CAPTURE(s4) + CHECK_THROWS_AS(parser_helper(s4), json::parse_error&); + // only check error message if c is not a control character + if (c > 0x1f) + { + CHECK_THROWS_WITH_STD_STR(parser_helper(s4), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'"); + } + } + } + } + + json _; + + // missing part of a surrogate pair + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&); + // invalid surrogate pair + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""), + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""), + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""), + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'", json::parse_error&); + } + + SECTION("parse errors (accept)") + { + // unexpected end of number + CHECK(accept_helper("0.") == false); + CHECK(accept_helper("-") == false); + CHECK(accept_helper("--") == false); + CHECK(accept_helper("-0.") == false); + CHECK(accept_helper("-.") == false); + CHECK(accept_helper("-:") == false); + CHECK(accept_helper("0.:") == false); + CHECK(accept_helper("e.") == false); + CHECK(accept_helper("1e.") == false); + CHECK(accept_helper("1e/") == false); + CHECK(accept_helper("1e:") == false); + CHECK(accept_helper("1E.") == false); + CHECK(accept_helper("1E/") == false); + CHECK(accept_helper("1E:") == false); + + // unexpected end of null + CHECK(accept_helper("n") == false); + CHECK(accept_helper("nu") == false); + CHECK(accept_helper("nul") == false); + + // unexpected end of true + CHECK(accept_helper("t") == false); + CHECK(accept_helper("tr") == false); + CHECK(accept_helper("tru") == false); + + // unexpected end of false + CHECK(accept_helper("f") == false); + CHECK(accept_helper("fa") == false); + CHECK(accept_helper("fal") == false); + CHECK(accept_helper("fals") == false); + + // missing/unexpected end of array + CHECK(accept_helper("[") == false); + CHECK(accept_helper("[1") == false); + CHECK(accept_helper("[1,") == false); + CHECK(accept_helper("[1,]") == false); + CHECK(accept_helper("]") == false); + + // missing/unexpected end of object + CHECK(accept_helper("{") == false); + CHECK(accept_helper("{\"foo\"") == false); + CHECK(accept_helper("{\"foo\":") == false); + CHECK(accept_helper("{\"foo\":}") == false); + CHECK(accept_helper("{\"foo\":1,}") == false); + CHECK(accept_helper("}") == false); + + // missing/unexpected end of string + CHECK(accept_helper("\"") == false); + CHECK(accept_helper("\"\\\"") == false); + CHECK(accept_helper("\"\\u\"") == false); + CHECK(accept_helper("\"\\u0\"") == false); + CHECK(accept_helper("\"\\u01\"") == false); + CHECK(accept_helper("\"\\u012\"") == false); + CHECK(accept_helper("\"\\u") == false); + CHECK(accept_helper("\"\\u0") == false); + CHECK(accept_helper("\"\\u01") == false); + CHECK(accept_helper("\"\\u012") == false); + + // unget of newline + CHECK(parser_helper("\n123\n") == 123); + + // invalid escapes + for (int c = 1; c < 128; ++c) + { + auto s = std::string("\"\\") + std::string(1, static_cast(c)) + "\""; + + switch (c) + { + // valid escapes + case ('"'): + case ('\\'): + case ('/'): + case ('b'): + case ('f'): + case ('n'): + case ('r'): + case ('t'): + { + CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept()); + break; + } + + // \u must be followed with four numbers, so we skip it here + case ('u'): + { + break; + } + + // any other combination of backslash and character is invalid + default: + { + CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept() == false); + break; + } + } + } + + // invalid \uxxxx escapes + { + // check whether character is a valid hex character + const auto valid = [](int c) + { + switch (c) + { + case ('0'): + case ('1'): + case ('2'): + case ('3'): + case ('4'): + case ('5'): + case ('6'): + case ('7'): + case ('8'): + case ('9'): + case ('a'): + case ('b'): + case ('c'): + case ('d'): + case ('e'): + case ('f'): + case ('A'): + case ('B'): + case ('C'): + case ('D'): + case ('E'): + case ('F'): + { + return true; + } + + default: + { + return false; + } + } + }; + + for (int c = 1; c < 128; ++c) + { + std::string const s = "\"\\u"; + + // create a string with the iterated character at each position + const auto s1 = s + "000" + std::string(1, static_cast(c)) + "\""; + const auto s2 = s + "00" + std::string(1, static_cast(c)) + "0\""; + const auto s3 = s + "0" + std::string(1, static_cast(c)) + "00\""; + const auto s4 = s + std::string(1, static_cast(c)) + "000\""; + + if (valid(c)) + { + CAPTURE(s1) + CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept()); + CAPTURE(s2) + CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept()); + CAPTURE(s3) + CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept()); + CAPTURE(s4) + CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept()); + } + else + { + CAPTURE(s1) + CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept() == false); + + CAPTURE(s2) + CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept() == false); + + CAPTURE(s3) + CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept() == false); + + CAPTURE(s4) + CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept() == false); + } + } + } + + // missing part of a surrogate pair + CHECK(accept_helper("\"\\uD80C\"") == false); + // invalid surrogate pair + CHECK(accept_helper("\"\\uD80C\\uD80C\"") == false); + CHECK(accept_helper("\"\\uD80C\\u0000\"") == false); + CHECK(accept_helper("\"\\uD80C\\uFFFF\"") == false); + } + + SECTION("tests found by mutate++") + { + // test case to make sure no comma precedes the first key + CHECK_THROWS_WITH_AS(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected ','; expected string literal", json::parse_error&); + // test case to make sure an object is properly closed + CHECK_THROWS_WITH_AS(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object - unexpected true literal; expected '}'", json::parse_error&); + + // test case to make sure the callback is properly evaluated after reading a key + { + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept + { + return event != json::parse_event_t::key; + }; + + json x = json::parse("{\"key\": false}", cb); + CHECK(x == json::object()); + } + } + + SECTION("callback function") + { + const auto* s_object = R"( + { + "foo": 2, + "bar": { + "baz": 1 + } + } + )"; + + const auto* s_array = R"( + [1,2,[3,4,5],4,5] + )"; + + const auto* structured_array = R"( + [ + 1, + { + "foo": "bar" + }, + { + "qux": "baz" + } + ] + )"; + + SECTION("filter nothing") + { + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + { + return true; + }); + + CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}})); + + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + { + return true; + }); + + CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5})); + } + + SECTION("filter everything") + { + json const j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + { + return false; + }); + + // the top-level object will be discarded, leaving a null + CHECK (j_object.is_null()); + + json const j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + { + return false; + }); + + // the top-level array will be discarded, leaving a null + CHECK (j_array.is_null()); + } + + SECTION("filter specific element") + { + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept + { + // filter all number(2) elements + return event != json::parse_event_t::value || j != json(2); + }); + + CHECK (j_object == json({{"bar", {{"baz", 1}}}})); + + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept + { + return event != json::parse_event_t::value || j != json(2); + }); + + CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); + } + + SECTION("filter object in array") + { + json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json & parsed) + { + return !(e == json::parse_event_t::object_end && parsed.contains("foo")); + }); + + // the specified object will be discarded, and removed. + CHECK (j_filtered1.size() == 2); + CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); + + json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept + { + return e != json::parse_event_t::object_end; + }); + + // removed all objects in array. + CHECK (j_filtered2.size() == 1); + CHECK (j_filtered2 == json({1})); + } + + SECTION("filter specific events") + { + SECTION("first closing event") + { + { + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept + { + static bool first = true; + if (e == json::parse_event_t::object_end && first) + { + first = false; + return false; + } + + return true; + }); + + // the first completed object will be discarded + CHECK (j_object == json({{"foo", 2}})); + } + + { + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept + { + static bool first = true; + if (e == json::parse_event_t::array_end && first) + { + first = false; + return false; + } + + return true; + }); + + // the first completed array will be discarded + CHECK (j_array == json({1, 2, 4, 5})); + } + } + } + + SECTION("special cases") + { + // the following test cases cover the situation in which an empty + // object and array is discarded only after the closing character + // has been read + + json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept + { + return e != json::parse_event_t::object_end; + }); + CHECK(j_empty_object == json()); + + json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept + { + return e != json::parse_event_t::array_end; + }); + CHECK(j_empty_array == json()); + } + } + + SECTION("constructing from contiguous containers") + { + SECTION("from std::vector") + { + std::vector v = {'t', 'r', 'u', 'e'}; + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + + SECTION("from std::array") + { + std::array v { {'t', 'r', 'u', 'e'} }; + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + + SECTION("from array") + { + uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + + SECTION("from char literal") + { + CHECK(parser_helper("true") == json(true)); + } + + SECTION("from std::string") + { + std::string v = {'t', 'r', 'u', 'e'}; + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + + SECTION("from std::initializer_list") + { + std::initializer_list const v = {'t', 'r', 'u', 'e'}; + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + + SECTION("from std::valarray") + { + std::valarray v = {'t', 'r', 'u', 'e'}; + json j; + json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); + CHECK(j == json(true)); + } + } + + SECTION("improve test coverage") + { + SECTION("parser with callback") + { + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept + { + return true; + }; + + CHECK(json::parse("{\"foo\": true:", cb, false).is_discarded()); + + json _; + CHECK_THROWS_WITH_AS(_ = json::parse("{\"foo\": true:", cb), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing object - unexpected ':'; expected '}'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("1.18973e+4932", cb), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); + } + + SECTION("SAX parser") + { + SECTION("} without value") + { + SaxCountdown s(1); + CHECK(json::sax_parse("{}", &s) == false); + } + + SECTION("} with value") + { + SaxCountdown s(3); + CHECK(json::sax_parse("{\"k1\": true}", &s) == false); + } + + SECTION("second key") + { + SaxCountdown s(3); + CHECK(json::sax_parse("{\"k1\": true, \"k2\": false}", &s) == false); + } + + SECTION("] without value") + { + SaxCountdown s(1); + CHECK(json::sax_parse("[]", &s) == false); + } + + SECTION("] with value") + { + SaxCountdown s(2); + CHECK(json::sax_parse("[1]", &s) == false); + } + + SECTION("float") + { + SaxCountdown s(0); + CHECK(json::sax_parse("3.14", &s) == false); + } + + SECTION("false") + { + SaxCountdown s(0); + CHECK(json::sax_parse("false", &s) == false); + } + + SECTION("null") + { + SaxCountdown s(0); + CHECK(json::sax_parse("null", &s) == false); + } + + SECTION("true") + { + SaxCountdown s(0); + CHECK(json::sax_parse("true", &s) == false); + } + + SECTION("unsigned") + { + SaxCountdown s(0); + CHECK(json::sax_parse("12", &s) == false); + } + + SECTION("integer") + { + SaxCountdown s(0); + CHECK(json::sax_parse("-12", &s) == false); + } + + SECTION("string") + { + SaxCountdown s(0); + CHECK(json::sax_parse("\"foo\"", &s) == false); + } + } + } + + SECTION("error messages for comments") + { + json _; + CHECK_THROWS_WITH_AS(_ = json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*'", json::parse_error); + } + + // Macro for all test cases for start_pos and end_pos +#define SETUP_TESTCASES() \ + SECTION("with callback") \ + { \ + SECTION("filter nothing") \ + { \ + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept \ + { \ + return true; \ + }; \ + validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, expected, cb); \ + } \ + SECTION("filter element") \ + { \ + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t event, json& j) noexcept \ + { \ + return (event != json::parse_event_t::key && event != json::parse_event_t::value) || j != json("a"); \ + }; \ + validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, filteredExpected, cb); \ + } \ + } \ + SECTION("without callback") \ + { \ + validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, expected); \ + } + + SECTION("retrieve start position and end position") + { + SECTION("for object") + { + // Create an object with spaces to test the start and end positions. Spaces will not be included in the + // JSON object, however, the start and end positions should include the spaces from the input JSON string. + const std::string nested_type_json_str = R"({ "a": 1,"b" : "test1"})"; + const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test2"})"; + auto expected = json({{"nested", {{"a", 1}, {"b", "test1"}}}, {"anotherValue", "test2"}}); + auto filteredExpected = expected; + filteredExpected["nested"].erase("a"); + + SETUP_TESTCASES() + } + + SECTION("for array") + { + const std::string nested_type_json_str = R"(["a", "test", 45])"; + const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", {"a", "test", 45}}, {"anotherValue", "test"}}); + auto filteredExpected = expected; + filteredExpected["nested"] = json({"test", 45}); + SETUP_TESTCASES() + } + + SECTION("for array with objects") + { + const std::string nested_type_json_str = R"([{"a": 1, "b": "test"}, {"c": 2, "d": "test2"}])"; + const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", {{{"a", 1}, {"b", "test"}}, {{"c", 2}, {"d", "test2"}}}}, {"anotherValue", "test"}}); + auto filteredExpected = expected; + filteredExpected["nested"][0].erase("a"); + SETUP_TESTCASES() + + auto j = json::parse(root_type_json_str); + auto nested_array = j["nested"]; + const auto& nested_obj = nested_array[0]; + CHECK(nested_type_json_str.substr(1, 21) == root_type_json_str.substr(nested_obj.start_pos(), nested_obj.end_pos() - nested_obj.start_pos())); + CHECK(nested_type_json_str.substr(24, 22) == root_type_json_str.substr(nested_array[1].start_pos(), nested_array[1].end_pos() - nested_array[1].start_pos())); + } + + SECTION("for two levels of nesting objects") + { + const std::string nested_type_json_str = R"({"nested2": {"b": "test"}})"; + const std::string root_type_json_str = R"({ "a": 2, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"a", 2}, {"nested", {{"nested2", {{"b", "test"}}}}}, {"anotherValue", "test"}}); + auto filteredExpected = expected; + filteredExpected.erase("a"); + SETUP_TESTCASES() + + auto j = json::parse(root_type_json_str); + auto nested_obj = j["nested"]["nested2"]; + CHECK(nested_type_json_str.substr(12, 13) == root_type_json_str.substr(nested_obj.start_pos(), nested_obj.end_pos() - nested_obj.start_pos())); + } + + SECTION("for simple types") + { + SECTION("no nested") + { + SECTION("with callback") + { + json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept + { + return true; + }; + + // 1. string type + std::string json_str = R"("test")"; + auto j = json::parse(json_str, cb); + validate_generated_json_and_start_end_pos_helper(json_str, j, "test"); + + // 2. number type + json_str = R"(1)"; + j = json::parse(json_str, cb); + validate_generated_json_and_start_end_pos_helper(json_str, j, 1); + + // 3. boolean type + json_str = R"(true)"; + j = json::parse(json_str, cb); + validate_generated_json_and_start_end_pos_helper(json_str, j, true); + + // 4. null type + json_str = R"(null)"; + j = json::parse(json_str, cb); + validate_generated_json_and_start_end_pos_helper(json_str, j, nullptr); + } + + SECTION("without callback") + { + // 1. string type + std::string json_str = R"("test")"; + auto j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, "test"); + + // 2. number type + json_str = R"(1)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, 1); + + json_str = R"(1.001239923)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, 1.001239923); + + json_str = R"(1.123812389000000)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, 1.123812389); + + // 3. boolean type + json_str = R"(true)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, true); + + json_str = R"(false)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, false); + + // 4. null type + json_str = R"(null)"; + j = json::parse(json_str); + validate_generated_json_and_start_end_pos_helper(json_str, j, nullptr); + } + } + + SECTION("string type") + { + const std::string nested_type_json_str = R"("test")"; + const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", "test"}, {"anotherValue", "test"}, {"a", 1}}); + auto filteredExpected = expected; + filteredExpected.erase("a"); + SETUP_TESTCASES() + } + + SECTION("number type") + { + const std::string nested_type_json_str = R"(2)"; + const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", 2}, {"anotherValue", "test"}, {"a", 1}}); + auto filteredExpected = expected; + filteredExpected.erase("a"); + SETUP_TESTCASES() + } + + SECTION("boolean type") + { + const std::string nested_type_json_str = R"(true)"; + const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", true}, {"anotherValue", "test"}, {"a", 1}}); + auto filteredExpected = expected; + filteredExpected.erase("a"); + SETUP_TESTCASES() + } + + SECTION("null type") + { + const std::string nested_type_json_str = R"(null)"; + const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })"; + auto expected = json({{"nested", nullptr}, {"anotherValue", "test"}, {"a", 1}}); + auto filteredExpected = expected; + filteredExpected.erase("a"); + SETUP_TESTCASES() + } + } + SECTION("with leading whitespace and newlines around root JSON") + { + const std::string initial_whitespace = R"( + + )"; + const std::string nested_type_json_str = R"({ + "a": 1, + "nested": { + "b": "test" + }, + "anotherValue": "test" + })"; + const std::string end_whitespace = R"( + + )"; + const std::string root_type_json_str = initial_whitespace + nested_type_json_str + end_whitespace; + + auto expected = json({{"a", 1}, {"nested", {{"b", "test"}}}, {"anotherValue", "test"}}); + + auto j = json::parse(root_type_json_str); + + // 2. Check if the generated JSON is as expected + CHECK(j == expected); + + // 3. Check if the start and end positions do not include the surrounding whitespace + CHECK(j.start_pos() == initial_whitespace.size()); + CHECK(j.end_pos() == root_type_json_str.size() - end_whitespace.size()); + } + } +} diff --git a/tests/src/unit-comparison.cpp b/tests/src/unit-comparison.cpp index 7df20486d..d87faaae5 100644 --- a/tests/src/unit-comparison.cpp +++ b/tests/src/unit-comparison.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT // cmake/test.cmake selects the C++ standard versions with which to build a diff --git a/tests/src/unit-concepts.cpp b/tests/src/unit-concepts.cpp index e04299184..31936bab3 100644 --- a/tests/src/unit-concepts.cpp +++ b/tests/src/unit-concepts.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -20,7 +20,6 @@ TEST_CASE("concepts") // a, b: values of type X: json // TABLE 96 - Container Requirements - // X::value_type must return T CHECK((std::is_same::value)); diff --git a/tests/src/unit-constructor1.cpp b/tests/src/unit-constructor1.cpp index bbd576057..02a08215b 100644 --- a/tests/src/unit-constructor1.cpp +++ b/tests/src/unit-constructor1.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -412,7 +412,7 @@ TEST_CASE("constructors") SECTION("char[]") { - char const s[] {"Hello world"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const char s[] {"Hello world"}; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) json const j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); diff --git a/tests/src/unit-constructor2.cpp b/tests/src/unit-constructor2.cpp index 85a91ff9b..153addcf0 100644 --- a/tests/src/unit-constructor2.cpp +++ b/tests/src/unit-constructor2.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-convenience.cpp b/tests/src/unit-convenience.cpp index 34bbb02cf..0d6d13593 100644 --- a/tests/src/unit-convenience.cpp +++ b/tests/src/unit-convenience.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -55,7 +55,7 @@ struct alt_string_iter return *this; } - std::string impl{}; + std::string impl{}; // NOLINT(readability-redundant-member-init) }; struct alt_string_data @@ -91,7 +91,7 @@ struct alt_string_data return *this; } - std::string impl{}; + std::string impl{}; // NOLINT(readability-redundant-member-init) }; void check_escaped(const char* original, const char* escaped = "", bool ensure_ascii = false); diff --git a/tests/src/unit-conversions.cpp b/tests/src/unit-conversions.cpp index d7df0bee5..98c4321dd 100644 --- a/tests/src/unit-conversions.cpp +++ b/tests/src/unit-conversions.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT // cmake/test.cmake selects the C++ standard versions with which to build a @@ -16,6 +15,11 @@ #include "doctest_compatibility.h" +// skip tests if JSON_DisableEnumSerialization=ON (#4384) +#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) + #define SKIP_TESTS_FOR_ENUM_SERIALIZATION +#endif + #define JSON_TESTS_PRIVATE #include using nlohmann::json; @@ -32,6 +36,25 @@ using nlohmann::json; DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +#ifdef JSON_HAS_CPP_17 + #if __has_include() + #include + #elif __has_include() + #include + #endif +#endif + +#if defined(JSON_HAS_CPP_17) + #include +#endif + TEST_CASE("value conversion") { SECTION("get an object (explicit)") @@ -153,6 +176,7 @@ TEST_CASE("value conversion") } #if JSON_USE_IMPLICIT_CONVERSIONS + SECTION("get an object (implicit)") { const json::object_t o_reference = {{"object", json::object()}, @@ -246,8 +270,8 @@ TEST_CASE("value conversion") SECTION("built-in arrays") { - const char str[] = "a string"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const char str[] = "a string"; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const int nbs[] = {0, 1, 2}; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const json j2 = nbs; const json j3 = str; @@ -336,7 +360,7 @@ TEST_CASE("value conversion") SECTION("built-in arrays") { - const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const int nbs[] = {0, 1, 2}; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) int nbs2[] = {0, 0, 0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const json j2 = nbs; @@ -344,6 +368,68 @@ TEST_CASE("value conversion") CHECK(std::equal(std::begin(nbs), std::end(nbs), std::begin(nbs2))); } + SECTION("built-in arrays: 2D") + { + const int nbs[][3] = {{0, 1, 2}, {3, 4, 5}}; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + int nbs2[][3] = {{0, 0, 0}, {0, 0, 0}}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + + const json j2 = nbs; + j2.get_to(nbs2); + CHECK(std::equal(std::begin(nbs[0]), std::end(nbs[1]), std::begin(nbs2[0]))); + } + + SECTION("built-in arrays: 3D") + { + // NOLINTBEGIN(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const int nbs[][2][3] = {\ + {{0, 1, 2}, {3, 4, 5}}, \ + {{10, 11, 12}, {13, 14, 15}}\ + }; + int nbs2[][2][3] = {\ + {{0, 0, 0}, {0, 0, 0}}, \ + {{0, 0, 0}, {0, 0, 0}}\ + }; + // NOLINTEND(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + + const json j2 = nbs; + j2.get_to(nbs2); + CHECK(std::equal(std::begin(nbs[0][0]), std::end(nbs[1][1]), std::begin(nbs2[0][0]))); + } + + SECTION("built-in arrays: 4D") + { + // NOLINTBEGIN(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const int nbs[][2][2][3] = {\ + { + \ + {{0, 1, 2}, {3, 4, 5}}, \ + {{10, 11, 12}, {13, 14, 15}}\ + }, \ + { + \ + {{20, 21, 22}, {23, 24, 25}}, \ + {{30, 31, 32}, {33, 34, 35}}\ + }\ + }; + int nbs2[][2][2][3] = {\ + { + \ + {{0, 0, 0}, {0, 0, 0}}, \ + {{0, 0, 0}, {0, 0, 0}}\ + }, \ + { + \ + {{0, 0, 0}, {0, 0, 0}}, \ + {{0, 0, 0}, {0, 0, 0}}\ + }\ + }; + // NOLINTEND(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + + const json j2 = nbs; + j2.get_to(nbs2); + CHECK(std::equal(std::begin(nbs[0][0][0]), std::end(nbs[1][1][1]), std::begin(nbs2[0][0][0]))); + } + SECTION("std::deque") { std::deque a{"previous", "value"}; @@ -1164,7 +1250,7 @@ TEST_CASE("value conversion") SECTION("non-const") { - const json j_const = j; + const json j_const = j; // NOLINT(performance-unnecessary-copy-initialization) const auto& b = j_const.get_binary(); CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary); } @@ -1263,6 +1349,7 @@ TEST_CASE("value conversion") } #endif +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION SECTION("get an enum") { enum c_enum { value_1, value_2 }; @@ -1271,6 +1358,7 @@ TEST_CASE("value conversion") CHECK(json(value_1).get() == value_1); CHECK(json(cpp_enum::value_1).get() == cpp_enum::value_1); } +#endif SECTION("more involved conversions") { @@ -1503,7 +1591,7 @@ TEST_CASE("value conversion") enum class cards {kreuz, pik, herz, karo}; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive +// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive NLOHMANN_JSON_SERIALIZE_ENUM(cards, { {cards::kreuz, "kreuz"}, @@ -1513,7 +1601,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(cards, {cards::karo, "karo"} }) -enum TaskState +enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value) { TS_STOPPED, TS_RUNNING, @@ -1521,7 +1609,7 @@ enum TaskState TS_INVALID = -1, }; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive +// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, { {TS_INVALID, nullptr}, @@ -1569,4 +1657,97 @@ TEST_CASE("JSON to enum mapping") } } +#ifdef JSON_HAS_CPP_17 +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +TEST_CASE("std::filesystem::path") +{ + SECTION("ascii") + { + json const j_string = "Path"; + auto p = j_string.template get(); + json const j_path = p; + + CHECK(j_path.template get() == + j_string.template get()); + } + + SECTION("utf-8") + { + json const j_string = "P\xc4\x9b\xc5\xa1ina"; + auto p = j_string.template get(); + json const j_path = p; + + CHECK(j_path.template get() == + j_string.template get()); + } +} +#endif + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS +TEST_CASE("std::optional") +{ + SECTION("null") + { + json j_null; + std::optional opt_null; + + CHECK(json(opt_null) == j_null); + CHECK(j_null.get>() == std::nullopt); + } + + SECTION("string") + { + json j_string = "string"; + std::optional opt_string = "string"; + + CHECK(json(opt_string) == j_string); + CHECK(std::optional(j_string) == opt_string); + } + + SECTION("bool") + { + json j_bool = true; + std::optional opt_bool = true; + + CHECK(json(opt_bool) == j_bool); + CHECK(std::optional(j_bool) == opt_bool); + } + + SECTION("number") + { + json j_number = 1; + std::optional opt_int = 1; + + CHECK(json(opt_int) == j_number); + CHECK(j_number.get>() == opt_int); + } + + SECTION("array") + { + json j_array = {1, 2, nullptr}; + std::vector> opt_array = {{1, 2, std::nullopt}}; + + CHECK(json(opt_array) == j_array); + CHECK(j_array.get>>() == opt_array); + } + + SECTION("object") + { + json j_object = {{"one", 1}, {"two", 2}, {"zero", nullptr}}; + std::map> opt_object {{"one", 1}, {"two", 2}, {"zero", std::nullopt}}; + + CHECK(json(opt_object) == j_object); + CHECK(std::map>(j_object) == opt_object); + } +} +#endif +#endif + +#ifdef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_17 +#endif + +#ifdef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_14 +#endif DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-custom-base-class.cpp b/tests/src/unit-custom-base-class.cpp index 7d3c2eefc..538153af8 100644 --- a/tests/src/unit-custom-base-class.cpp +++ b/tests/src/unit-custom-base-class.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2019 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include @@ -283,8 +282,8 @@ TEST_CASE("JSON Visit Node") }; json.visit( - [&](const json_with_visitor_t::json_pointer & p, - const json_with_visitor_t& j) + [&](const json_with_visitor_t::json_pointer & p, + const json_with_visitor_t& j) { std::stringstream str; str << p.to_string() << " - " ; @@ -331,6 +330,6 @@ TEST_CASE("JSON Visit Node") CHECK(expected.count(str.str()) == 1); expected.erase(str.str()); } - ); + ); CHECK(expected.empty()); } diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp index 3bc161f1d..84a970a18 100644 --- a/tests/src/unit-deserialization.cpp +++ b/tests/src/unit-deserialization.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -77,7 +76,7 @@ struct SaxEventLogger : public nlohmann::json_sax bool start_object(std::size_t elements) override { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_object()"); } @@ -102,7 +101,7 @@ struct SaxEventLogger : public nlohmann::json_sax bool start_array(std::size_t elements) override { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_array()"); } @@ -125,14 +124,14 @@ struct SaxEventLogger : public nlohmann::json_sax return false; } - std::vector events {}; + std::vector events {}; // NOLINT(readability-redundant-member-init) }; struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger { bool start_object(std::size_t elements) override { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_object()"); } @@ -157,7 +156,7 @@ struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger { bool start_array(std::size_t elements) override { - if (elements == static_cast(-1)) + if (elements == (std::numeric_limits::max)()) { events.emplace_back("start_array()"); } @@ -360,6 +359,10 @@ TEST_CASE("deserialization") "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "parse_error(29)" })); + + const char* string = nullptr; + CHECK_THROWS_WITH_AS(_ = json::parse(string), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::parse(nullptr), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&); } SECTION("operator<<") @@ -583,7 +586,7 @@ TEST_CASE("deserialization") auto first = str.begin(); auto last = str.end(); json j; - json_sax_dom_parser sax(j, true); + json_sax_dom_parser sax(j, true); CHECK(json::sax_parse(proxy(first), proxy(last), &sax, input_format_t::json, false)); @@ -1131,13 +1134,15 @@ TEST_CASE("deserialization") } } -TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T, - char, unsigned char, signed char, - wchar_t, - char16_t, char32_t, - std::uint8_t, std::int8_t, - std::int16_t, std::uint16_t, - std::int32_t, std::uint32_t) +// select the types to test - char8_t is only available in C++20 +#define TYPE_LIST(...) __VA_ARGS__ +#ifdef JSON_HAS_CPP_20 + #define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t, char8_t) +#else + #define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t) +#endif + +TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T, ASCII_TYPES) // NOLINT(readability-math-missing-parentheses) { std::vector const v = {'t', 'r', 'u', 'e'}; CHECK(json::parse(v) == json(true)); @@ -1149,8 +1154,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T, CHECK(l.events == std::vector({"boolean(true)"})); } -TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T, - char, unsigned char, std::uint8_t) +TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T, char, unsigned char, std::uint8_t) // NOLINT(readability-math-missing-parentheses) { // a star emoji std::vector const v = {'"', static_cast(0xe2u), static_cast(0xadu), static_cast(0x90u), static_cast(0xefu), static_cast(0xb8u), static_cast(0x8fu), '"'}; @@ -1162,8 +1166,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T, CHECK(l.events.size() == 1); } -TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T, - char16_t, std::uint16_t) +TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T, char16_t) // NOLINT(readability-math-missing-parentheses) { // a star emoji std::vector const v = {static_cast('"'), static_cast(0x2b50), static_cast(0xfe0f), static_cast('"')}; @@ -1175,8 +1178,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T, CHECK(l.events.size() == 1); } -TEST_CASE_TEMPLATE("deserialization of different character types (UTF-32)", T, - char32_t, std::uint32_t) +TEST_CASE_TEMPLATE("deserialization of different character types (UTF-32)", T, char32_t) // NOLINT(readability-math-missing-parentheses) { // a star emoji std::vector const v = {static_cast('"'), static_cast(0x2b50), static_cast(0xfe0f), static_cast('"')}; diff --git a/tests/src/unit-diagnostic-positions-only.cpp b/tests/src/unit-diagnostic-positions-only.cpp new file mode 100644 index 000000000..c7d217968 --- /dev/null +++ b/tests/src/unit-diagnostic-positions-only.cpp @@ -0,0 +1,44 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#ifdef JSON_DIAGNOSTICS + #undef JSON_DIAGNOSTICS +#endif + +#define JSON_DIAGNOSTICS 0 +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include + +using json = nlohmann::json; + +TEST_CASE("Better diagnostics with positions only") +{ + SECTION("invalid type") + { + const std::string json_invalid_string = R"( + { + "address": { + "street": "Fake Street", + "housenumber": "1" + } + } + )"; + json j = json::parse(json_invalid_string); + CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get(), + "[json.exception.type_error.302] (bytes 108-111) type must be number, but is string", json::type_error); + } + + SECTION("invalid type without positions") + { + const json j = "foo"; + CHECK_THROWS_WITH_AS(j.get(), + "[json.exception.type_error.302] type must be number, but is string", json::type_error); + } +} diff --git a/tests/src/unit-diagnostic-positions.cpp b/tests/src/unit-diagnostic-positions.cpp new file mode 100644 index 000000000..1e41505a9 --- /dev/null +++ b/tests/src/unit-diagnostic-positions.cpp @@ -0,0 +1,40 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#define JSON_DIAGNOSTICS 1 +#define JSON_DIAGNOSTIC_POSITIONS 1 +#include + +using json = nlohmann::json; + +TEST_CASE("Better diagnostics with positions") +{ + SECTION("invalid type") + { + const std::string json_invalid_string = R"( + { + "address": { + "street": "Fake Street", + "housenumber": "1" + } + } + )"; + json j = json::parse(json_invalid_string); + CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get(), + "[json.exception.type_error.302] (/address/housenumber) (bytes 108-111) type must be number, but is string", json::type_error); + } + + SECTION("invalid type without positions") + { + const json j = "foo"; + CHECK_THROWS_WITH_AS(j.get(), + "[json.exception.type_error.302] type must be number, but is string", json::type_error); + } +} diff --git a/tests/src/unit-diagnostics.cpp b/tests/src/unit-diagnostics.cpp index 0e172b915..859ee1ec0 100644 --- a/tests/src/unit-diagnostics.cpp +++ b/tests/src/unit-diagnostics.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -243,4 +242,24 @@ TEST_CASE("Regression tests for extended diagnostics") json const j_arr_copy = j_arr; } } + + SECTION("Regression test for issue #3915 - JSON_DIAGNOSTICS trigger assertion") + { + json j = json::object(); + j["root"] = "root_str"; + + json jj = json::object(); + jj["child"] = json::object(); + + // If do not push anything in object, then no assert will be produced + jj["child"]["prop1"] = "prop1_value"; + + // Push all properties of child in parent + j.insert(jj.at("child").begin(), jj.at("child").end()); + + // Here assert is generated when construct new json + const json k(j); + + CHECK(k.dump() == "{\"prop1\":\"prop1_value\",\"root\":\"root_str\"}"); + } } diff --git a/tests/src/unit-disabled_exceptions.cpp b/tests/src/unit-disabled_exceptions.cpp index 4ad155140..e4a9cb03e 100644 --- a/tests/src/unit-disabled_exceptions.cpp +++ b/tests/src/unit-disabled_exceptions.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -20,10 +19,10 @@ using json = nlohmann::json; // for #2824 ///////////////////////////////////////////////////////////////////// -class sax_no_exception : public nlohmann::detail::json_sax_dom_parser +class sax_no_exception : public nlohmann::detail::json_sax_dom_parser { public: - explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser(j, false) {} + explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser(j, false) {} static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) { diff --git a/tests/src/unit-element_access1.cpp b/tests/src/unit-element_access1.cpp index 55a07ede1..92de75b33 100644 --- a/tests/src/unit-element_access1.cpp +++ b/tests/src/unit-element_access1.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -55,7 +54,7 @@ TEST_CASE("element access 1") SECTION("null") { json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); @@ -64,7 +63,7 @@ TEST_CASE("element access 1") SECTION("boolean") { json j_nonarray(json::value_t::boolean); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); @@ -73,7 +72,7 @@ TEST_CASE("element access 1") SECTION("string") { json j_nonarray(json::value_t::string); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); @@ -82,7 +81,7 @@ TEST_CASE("element access 1") SECTION("object") { json j_nonarray(json::value_t::object); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object", json::type_error&); @@ -91,7 +90,7 @@ TEST_CASE("element access 1") SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); @@ -100,7 +99,7 @@ TEST_CASE("element access 1") SECTION("number (unsigned)") { json j_nonarray(json::value_t::number_unsigned); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); @@ -109,7 +108,7 @@ TEST_CASE("element access 1") SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); @@ -155,7 +154,7 @@ TEST_CASE("element access 1") SECTION("standard tests") { json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_NOTHROW(j_nonarray[0]); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with null", json::type_error&); } @@ -171,7 +170,7 @@ TEST_CASE("element access 1") SECTION("boolean") { json j_nonarray(json::value_t::boolean); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean", json::type_error&); } @@ -179,7 +178,7 @@ TEST_CASE("element access 1") SECTION("string") { json j_nonarray(json::value_t::string); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string", json::type_error&); } @@ -187,7 +186,7 @@ TEST_CASE("element access 1") SECTION("object") { json j_nonarray(json::value_t::object); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object", json::type_error&); } @@ -195,7 +194,7 @@ TEST_CASE("element access 1") SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); } @@ -203,7 +202,7 @@ TEST_CASE("element access 1") SECTION("number (unsigned)") { json j_nonarray(json::value_t::number_unsigned); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); } @@ -211,7 +210,7 @@ TEST_CASE("element access 1") SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); - const json j_nonarray_const(j_nonarray); + const json j_nonarray_const(j_nonarray); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&); } diff --git a/tests/src/unit-element_access2.cpp b/tests/src/unit-element_access2.cpp index 8497fb944..5104dcc77 100644 --- a/tests/src/unit-element_access2.cpp +++ b/tests/src/unit-element_access2.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -17,7 +16,7 @@ // build test with C++14 // JSON_HAS_CPP_14 -TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_json) +TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses) { SECTION("object") { @@ -83,7 +82,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("null") { Json j_nonobject(Json::value_t::null); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); @@ -96,7 +95,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("boolean") { Json j_nonobject(Json::value_t::boolean); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); @@ -109,7 +108,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("string") { Json j_nonobject(Json::value_t::string); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); @@ -122,7 +121,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("array") { Json j_nonobject(Json::value_t::array); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); @@ -135,7 +134,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("number (integer)") { Json j_nonobject(Json::value_t::number_integer); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); @@ -148,7 +147,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("number (unsigned)") { Json j_nonobject(Json::value_t::number_unsigned); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); @@ -161,7 +160,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j SECTION("number (floating-point)") { Json j_nonobject(Json::value_t::number_float); - const Json j_nonobject_const(j_nonobject); + const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization) CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); @@ -1456,7 +1455,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j } #if !defined(JSON_NOEXCEPTION) -TEST_CASE_TEMPLATE("element access 2 (throwing tests)", Json, nlohmann::json, nlohmann::ordered_json) +TEST_CASE_TEMPLATE("element access 2 (throwing tests)", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses) { SECTION("object") { @@ -1492,7 +1491,7 @@ TEST_CASE_TEMPLATE("element access 2 (throwing tests)", Json, nlohmann::json, nl #endif // TODO(falbrechtskirchinger) merge with the other test case; clean up -TEST_CASE_TEMPLATE("element access 2 (additional value() tests)", Json, nlohmann::json, nlohmann::ordered_json) +TEST_CASE_TEMPLATE("element access 2 (additional value() tests)", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses) { using string_t = typename Json::string_t; using number_integer_t = typename Json::number_integer_t; @@ -1566,9 +1565,9 @@ TEST_CASE_TEMPLATE("element access 2 (additional value() tests)", Json, nlohmann SECTION("const char(&)[] key") { - const char key[] = "foo"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) - const char key2[] = "baz"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) - const char key_notfound[] = "bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key[] = "foo"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key2[] = "baz"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key_notfound[] = "bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) CHECK(j.value(key, "default") == "bar"); CHECK(j.value(key, cpstr) == "bar"); @@ -1700,9 +1699,9 @@ TEST_CASE_TEMPLATE("element access 2 (additional value() tests)", Json, nlohmann SECTION("const char(&)[] key") { - const char key[] = "foo"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) - const char key2[] = "baz"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) - const char key_notfound[] = "bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key[] = "foo"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key2[] = "baz"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char key_notfound[] = "bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) CHECK(j.template value(key, "default") == "bar"); CHECK(j.template value(key, cpstr) == "bar"); diff --git a/tests/src/unit-hash.cpp b/tests/src/unit-hash.cpp index 7c98a27cb..285e490f5 100644 --- a/tests/src/unit-hash.cpp +++ b/tests/src/unit-hash.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-inspection.cpp b/tests/src/unit-inspection.cpp index 0574094c5..4d285fcdf 100644 --- a/tests/src/unit-inspection.cpp +++ b/tests/src/unit-inspection.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-items.cpp b/tests/src/unit-items.cpp index ef2dd74b1..d6149a72d 100644 --- a/tests/src/unit-items.cpp +++ b/tests/src/unit-items.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-iterators1.cpp b/tests/src/unit-iterators1.cpp index 24669a625..595a1b684 100644 --- a/tests/src/unit-iterators1.cpp +++ b/tests/src/unit-iterators1.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-iterators2.cpp b/tests/src/unit-iterators2.cpp index ce8c95ba4..abf28ebe3 100644 --- a/tests/src/unit-iterators2.cpp +++ b/tests/src/unit-iterators2.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT // cmake/test.cmake selects the C++ standard versions with which to build a diff --git a/tests/src/unit-iterators3.cpp b/tests/src/unit-iterators3.cpp new file mode 100644 index 000000000..b9b9c5097 --- /dev/null +++ b/tests/src/unit-iterators3.cpp @@ -0,0 +1,35 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include +#include +#include + +#include +using nlohmann::json; + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +#ifdef JSON_HAS_CPP_14 +TEST_CASE_TEMPLATE("checking forward-iterators", T, // NOLINT(readability-math-missing-parentheses) + std::vector, std::string, nlohmann::json) +{ + auto it1 = typename T::iterator{}; + auto it2 = typename T::iterator{}; + CHECK(it1 == it2); + CHECK(it1 <= it2); + CHECK(it1 >= it2); + CHECK_FALSE(it1 != it2); + CHECK_FALSE(it1 < it2); + CHECK_FALSE(it1 > it2); +} +#endif diff --git a/tests/src/unit-json_patch.cpp b/tests/src/unit-json_patch.cpp index 0999393e6..a5b3b2612 100644 --- a/tests/src/unit-json_patch.cpp +++ b/tests/src/unit-json_patch.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -60,7 +60,11 @@ TEST_CASE("JSON patch") json const doc2 = R"({ "q": { "bar": 2 } })"_json; // because "a" does not exist. +#if JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_AS(doc2.patch(patch1), "[json.exception.out_of_range.403] (bytes 0-21) key 'a' not found", json::out_of_range&); +#else CHECK_THROWS_WITH_AS(doc2.patch(patch1), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); +#endif json const doc3 = R"({ "a": {} })"_json; json const patch2 = R"([{ "op": "add", "path": "/a/b/c", "value": 1 }])"_json; @@ -68,6 +72,8 @@ TEST_CASE("JSON patch") // should cause an error because "b" does not exist in doc3 #if JSON_DIAGNOSTICS CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] (/a) key 'b' not found", json::out_of_range&); +#elif JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] (bytes 7-9) key 'b' not found", json::out_of_range&); #else CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] key 'b' not found", json::out_of_range&); #endif @@ -333,6 +339,8 @@ TEST_CASE("JSON patch") CHECK_THROWS_AS(doc.patch(patch), json::other_error&); #if JSON_DIAGNOSTICS CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump()); +#elif JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (bytes 47-95) unsuccessful: " + patch[0].dump()); #else CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); #endif @@ -417,8 +425,11 @@ TEST_CASE("JSON patch") // applied), because the "add" operation's target location that // references neither the root of the document, nor a member of // an existing object, nor a member of an existing array. - +#if JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.403] (bytes 21-37) key 'baz' not found", json::out_of_range&); +#else CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found", json::out_of_range&); +#endif } // A.13. Invalid JSON Patch Document @@ -476,6 +487,8 @@ TEST_CASE("JSON patch") CHECK_THROWS_AS(doc.patch(patch), json::other_error&); #if JSON_DIAGNOSTICS CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump()); +#elif JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (bytes 47-92) unsuccessful: " + patch[0].dump()); #else CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); #endif @@ -1205,6 +1218,8 @@ TEST_CASE("JSON patch") CHECK_THROWS_AS(doc.patch(patch), json::other_error&); #if JSON_DIAGNOSTICS CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (/0) unsuccessful: " + patch[0].dump()); +#elif JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] (bytes 47-117) unsuccessful: " + patch[0].dump()); #else CHECK_THROWS_WITH_STD_STR(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); #endif @@ -1305,7 +1320,7 @@ TEST_CASE("JSON patch") const auto& doc = test["doc"]; const auto& patch = test["patch"]; - if (test.count("error") == 0) + if (test.count("error") == 0) // NOLINT(readability-container-contains) { // if an expected value is given, use it; use doc otherwise const auto& expected = test.value("expected", doc); diff --git a/tests/src/unit-json_pointer.cpp b/tests/src/unit-json_pointer.cpp index 79c67f99d..149eff00a 100644 --- a/tests/src/unit-json_pointer.cpp +++ b/tests/src/unit-json_pointer.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -203,11 +203,15 @@ TEST_CASE("JSON pointers") // escaped access CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]); CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); - +#if JSON_DIAGNOSTIC_POSITIONS + // unescaped access + CHECK_THROWS_WITH_AS(j.at(json::json_pointer("/a/b")), + "[json.exception.out_of_range.403] (bytes 13-297) key 'a' not found", json::out_of_range&); +#else // unescaped access CHECK_THROWS_WITH_AS(j.at(json::json_pointer("/a/b")), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); - +#endif // unresolved access const json j_primitive = 1; CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer], @@ -652,7 +656,7 @@ TEST_CASE("JSON pointers") SECTION("equality comparison") { const char* ptr_cpstring = "/foo/bar"; - const char ptr_castring[] = "/foo/bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) std::string ptr_string{"/foo/bar"}; auto ptr1 = json::json_pointer(ptr_string); auto ptr2 = json::json_pointer(ptr_string); diff --git a/tests/src/unit-large_json.cpp b/tests/src/unit-large_json.cpp index 9703a5452..8b27d8384 100644 --- a/tests/src/unit-large_json.cpp +++ b/tests/src/unit-large_json.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-locale-cpp.cpp b/tests/src/unit-locale-cpp.cpp new file mode 100644 index 000000000..2d1328cbb --- /dev/null +++ b/tests/src/unit-locale-cpp.cpp @@ -0,0 +1,161 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#define JSON_TESTS_PRIVATE +#include +using nlohmann::json; + +#include + +struct ParserImpl final: public nlohmann::json_sax +{ + bool null() override + { + return true; + } + bool boolean(bool /*val*/) override + { + return true; + } + bool number_integer(json::number_integer_t /*val*/) override + { + return true; + } + bool number_unsigned(json::number_unsigned_t /*val*/) override + { + return true; + } + bool number_float(json::number_float_t /*val*/, const json::string_t& s) override + { + float_string_copy = s; + return true; + } + bool string(json::string_t& /*val*/) override + { + return true; + } + bool binary(json::binary_t& /*val*/) override + { + return true; + } + bool start_object(std::size_t /*val*/) override + { + return true; + } + bool key(json::string_t& /*val*/) override + { + return true; + } + bool end_object() override + { + return true; + } + bool start_array(std::size_t /*val*/) override + { + return true; + } + bool end_array() override + { + return true; + } + bool parse_error(std::size_t /*val*/, const std::string& /*val*/, const nlohmann::detail::exception& /*val*/) override + { + return false; + } + + ~ParserImpl() override; + + ParserImpl() + : float_string_copy("not set") + {} + + ParserImpl(const ParserImpl& other) + : float_string_copy(other.float_string_copy) + {} + + ParserImpl(ParserImpl&& other) noexcept + : float_string_copy(std::move(other.float_string_copy)) + {} + + ParserImpl& operator=(const ParserImpl& other) + { + if (this != &other) + { + float_string_copy = other.float_string_copy; + } + return *this; + } + + ParserImpl& operator=(ParserImpl&& other) noexcept + { + if (this != &other) + { + float_string_copy = std::move(other.float_string_copy); + } + return *this; + } + + json::string_t float_string_copy; +}; + +ParserImpl::~ParserImpl() = default; + +TEST_CASE("locale-dependent test (LC_NUMERIC=C)") +{ + WARN_MESSAGE(std::setlocale(LC_NUMERIC, "C") != nullptr, "could not set locale"); + + SECTION("check if locale is properly set") + { + std::array buffer = {}; + CHECK(std::snprintf(buffer.data(), buffer.size(), "%.2f", 12.34) == 5); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + CHECK(std::string(buffer.data()) == "12.34"); + } + + SECTION("parsing") + { + CHECK(json::parse("12.34").dump() == "12.34"); + } + + SECTION("SAX parsing") + { + ParserImpl sax {}; + json::sax_parse( "12.34", &sax ); + CHECK(sax.float_string_copy == "12.34"); + } +} + +TEST_CASE("locale-dependent test (LC_NUMERIC=de_DE)") +{ + if (std::setlocale(LC_NUMERIC, "de_DE") != nullptr) + { + SECTION("check if locale is properly set") + { + std::array buffer = {}; + CHECK(std::snprintf(buffer.data(), buffer.size(), "%.2f", 12.34) == 5); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + CHECK(std::string(buffer.data()) == "12,34"); + } + + SECTION("parsing") + { + CHECK(json::parse("12.34").dump() == "12.34"); + } + + SECTION("SAX parsing") + { + ParserImpl sax{}; + json::sax_parse("12.34", &sax); + CHECK(sax.float_string_copy == "12.34"); + } + } + else + { + MESSAGE("locale de_DE is not usable"); + } +} diff --git a/tests/src/unit-merge_patch.cpp b/tests/src/unit-merge_patch.cpp index 6a8bcfe2a..450876655 100644 --- a/tests/src/unit-merge_patch.cpp +++ b/tests/src/unit-merge_patch.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-meta.cpp b/tests/src/unit-meta.cpp index a522faabb..698245b75 100644 --- a/tests/src/unit-meta.cpp +++ b/tests/src/unit-meta.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -18,14 +18,14 @@ TEST_CASE("version information") json j = json::meta(); CHECK(j["name"] == "JSON for Modern C++"); - CHECK(j["copyright"] == "(C) 2013-2023 Niels Lohmann"); + CHECK(j["copyright"] == "(C) 2013-2025 Niels Lohmann"); CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "3.11.3"}, + {"string", "3.12.0"}, {"major", 3}, - {"minor", 11}, - {"patch", 3} + {"minor", 12}, + {"patch", 0} })); CHECK(j.find("platform") != j.end()); diff --git a/tests/src/unit-modifiers.cpp b/tests/src/unit-modifiers.cpp index fb686780e..109e8a949 100644 --- a/tests/src/unit-modifiers.cpp +++ b/tests/src/unit-modifiers.cpp @@ -1,10 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// Copyright (c) 2013-2022 Niels Lohmann . -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-msgpack.cpp b/tests/src/unit-msgpack.cpp index 61162afae..0d49ae6db 100644 --- a/tests/src/unit-msgpack.cpp +++ b/tests/src/unit-msgpack.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -281,7 +281,7 @@ TEST_CASE("MessagePack") // check individual bytes CHECK(result[0] == 0xcd); - auto const restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + auto const restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -479,11 +479,11 @@ TEST_CASE("MessagePack") std::vector const numbers { -32769, - -65536, - -77777, - -1048576, - -2147483648LL, - }; + -65536, + -77777, + -1048576, + -2147483648LL, + }; for (auto i : numbers) { CAPTURE(i) @@ -671,7 +671,7 @@ TEST_CASE("MessagePack") // check individual bytes CHECK(result[0] == 0xcd); - auto const restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + auto const restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -1508,6 +1508,22 @@ TEST_CASE("MessagePack") CHECK(json::from_msgpack(std::vector({0xc4}), true, false).is_discarded()); } + SECTION("unexpected end inside int with stream") + { + json _; + const std::string data = {static_cast(0xd2u), static_cast(0x12u), static_cast(0x34u), static_cast(0x56u)}; + CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::istringstream(data, std::ios::binary)), + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing MessagePack number: unexpected end of input", json::parse_error&); + } + SECTION("misuse wchar for binary") + { + json _; + // creates 0xd2 after UTF-8 decoding, triggers get_elements in wide_string_input_adapter for code coverage + const std::u32string data = {static_cast(0x0280)}; + CHECK_THROWS_WITH_AS(_ = json::from_msgpack(data), + "[json.exception.parse_error.112] parse error at byte 1: wide string type cannot be interpreted as binary data", json::parse_error&); + } + SECTION("unsupported bytes") { SECTION("concrete examples") @@ -1604,7 +1620,7 @@ TEST_CASE("single MessagePack roundtrip") { SECTION("std::ostringstream") { - std::basic_ostringstream ss; + std::basic_ostringstream ss; json::to_msgpack(j1, ss); json j3 = json::from_msgpack(ss.str()); CHECK(j1 == j3); diff --git a/tests/src/unit-no-mem-leak-on-adl-serialize.cpp b/tests/src/unit-no-mem-leak-on-adl-serialize.cpp index 37b10a916..6ce75ae11 100644 --- a/tests/src/unit-no-mem-leak-on-adl-serialize.cpp +++ b/tests/src/unit-no-mem-leak-on-adl-serialize.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-noexcept.cpp b/tests/src/unit-noexcept.cpp index bba230d01..a3c372349 100644 --- a/tests/src/unit-noexcept.cpp +++ b/tests/src/unit-noexcept.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -12,6 +12,11 @@ DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +// skip tests if JSON_DisableEnumSerialization=ON (#4384) +#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) + #define SKIP_TESTS_FOR_ENUM_SERIALIZATION +#endif + #include using nlohmann::json; @@ -36,12 +41,16 @@ static_assert(noexcept(json{}), ""); static_assert(noexcept(nlohmann::to_json(std::declval(), 2)), ""); static_assert(noexcept(nlohmann::to_json(std::declval(), 2.5)), ""); static_assert(noexcept(nlohmann::to_json(std::declval(), true)), ""); -static_assert(noexcept(nlohmann::to_json(std::declval(), test{})), ""); -static_assert(noexcept(nlohmann::to_json(std::declval(), pod{})), ""); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION +static_assert(noexcept(nlohmann::to_json(std::declval(), test {})), ""); +#endif +static_assert(noexcept(nlohmann::to_json(std::declval(), pod {})), ""); static_assert(!noexcept(nlohmann::to_json(std::declval(), pod_bis{})), ""); static_assert(noexcept(json(2)), ""); -static_assert(noexcept(json(test{})), ""); -static_assert(noexcept(json(pod{})), ""); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION +static_assert(noexcept(json(test {})), ""); +#endif +static_assert(noexcept(json(pod {})), ""); static_assert(noexcept(std::declval().get()), ""); static_assert(!noexcept(std::declval().get()), ""); static_assert(noexcept(json(pod{})), ""); diff --git a/tests/src/unit-ordered_json.cpp b/tests/src/unit-ordered_json.cpp index d77d904b0..d2504d5ec 100644 --- a/tests/src/unit-ordered_json.cpp +++ b/tests/src/unit-ordered_json.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-ordered_map.cpp b/tests/src/unit-ordered_map.cpp index ceafea1e9..b8aaf8c5b 100644 --- a/tests/src/unit-ordered_map.cpp +++ b/tests/src/unit-ordered_map.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-pointer_access.cpp b/tests/src/unit-pointer_access.cpp index 4503a3b73..2bb0f6037 100644 --- a/tests/src/unit-pointer_access.cpp +++ b/tests/src/unit-pointer_access.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -326,7 +326,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); @@ -355,7 +355,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); diff --git a/tests/src/unit-readme.cpp b/tests/src/unit-readme.cpp index f2a571aac..8b81e8fe8 100644 --- a/tests/src/unit-readme.cpp +++ b/tests/src/unit-readme.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -115,7 +115,7 @@ TEST_CASE("README" * doctest::skip()) auto j3 = json::parse(R"({"happy": true, "pi": 3.141})"); // explicit conversion to string - std::string const s = j.dump(); // {\"happy\":true,\"pi\":3.141} + std::string const s = j.dump(); // NOLINT(bugprone-unused-local-non-trivial-variable) // {\"happy\":true,\"pi\":3.141} // serialization with pretty printing // pass in the amount of spaces to indent @@ -152,7 +152,7 @@ TEST_CASE("README" * doctest::skip()) } // getter/setter - const auto tmp = j[0].get(); + const auto tmp = j[0].get(); // NOLINT(bugprone-unused-local-non-trivial-variable) j[1] = 42; bool foo{j.at(2)}; CHECK(foo == true); @@ -171,7 +171,7 @@ TEST_CASE("README" * doctest::skip()) // find an entry CHECK(o.find("foo") != o.end()); - if (o.find("foo") != o.end()) + if (o.find("foo") != o.end()) // NOLINT(readability-container-contains) { // there is an entry with key "foo" } @@ -237,7 +237,7 @@ TEST_CASE("README" * doctest::skip()) // strings std::string const s1 = "Hello, world!"; json const js = s1; - auto s2 = js.get(); + auto s2 = js.get(); // NOLINT(bugprone-unused-local-non-trivial-variable) // Booleans bool const b1 = true; @@ -253,7 +253,7 @@ TEST_CASE("README" * doctest::skip()) // etc. - std::string const vs = js.get(); + std::string const vs = js.get(); // NOLINT(bugprone-unused-local-non-trivial-variable) bool vb = jb.get(); CHECK(vb == true); int vi = jn.get(); diff --git a/tests/src/unit-reference_access.cpp b/tests/src/unit-reference_access.cpp index 3b46fe833..00e48a58b 100644 --- a/tests/src/unit-reference_access.cpp +++ b/tests/src/unit-reference_access.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -215,8 +215,8 @@ TEST_CASE("reference access") "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); CHECK_THROWS_WITH_AS(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); - //CHECK_THROWS_WITH_AS(value.get_ref(), - // "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); + CHECK_THROWS_WITH_AS(value.get_ref(), + "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); CHECK_NOTHROW(value.get_ref()); CHECK_THROWS_WITH_AS(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); } diff --git a/tests/src/unit-regression1.cpp b/tests/src/unit-regression1.cpp index f5ef5d80b..64853dde7 100644 --- a/tests/src/unit-regression1.cpp +++ b/tests/src/unit-regression1.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -11,6 +11,11 @@ // for some reason including this after the json header leads to linker errors with VS 2017... #include +// skip tests if JSON_DisableEnumSerialization=ON (#4384) +#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) + #define SKIP_TESTS_FOR_ENUM_SERIALIZATION +#endif + #define JSON_TESTS_PRIVATE #include using nlohmann::json; @@ -169,6 +174,7 @@ TEST_CASE("regression tests 1") } } +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION SECTION("pull request #71 - handle enum type") { enum { t = 0, u = 102}; @@ -191,6 +197,7 @@ TEST_CASE("regression tests 1") {"game_type", t} })); } +#endif SECTION("issue #76 - dump() / parse() not idempotent") { @@ -1328,10 +1335,10 @@ TEST_CASE("regression tests 1") { std::ifstream is; is.exceptions( - is.exceptions() - | std::ios_base::failbit - | std::ios_base::badbit - ); // handle different exceptions as 'file not found', 'permission denied' + is.exceptions() + | std::ios_base::failbit + | std::ios_base::badbit + ); // handle different exceptions as 'file not found', 'permission denied' is.open(TEST_DATA_DIRECTORY "/regression/working_file.json"); json _; @@ -1341,10 +1348,10 @@ TEST_CASE("regression tests 1") { std::ifstream is; is.exceptions( - is.exceptions() - | std::ios_base::failbit - | std::ios_base::badbit - ); // handle different exceptions as 'file not found', 'permission denied' + is.exceptions() + | std::ios_base::failbit + | std::ios_base::badbit + ); // handle different exceptions as 'file not found', 'permission denied' is.open(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json.cbor", std::ios_base::in | std::ios_base::binary); @@ -1393,14 +1400,24 @@ TEST_CASE("regression tests 1") auto p1 = R"([{"op": "move", "from": "/one/two/three", "path": "/a/b/c"}])"_json; +#if JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_AS(model.patch(p1), + "[json.exception.out_of_range.403] (bytes 0-158) key 'a' not found", json::out_of_range&); +#else CHECK_THROWS_WITH_AS(model.patch(p1), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); +#endif auto p2 = R"([{"op": "copy", "from": "/one/two/three", "path": "/a/b/c"}])"_json; +#if JSON_DIAGNOSTIC_POSITIONS + CHECK_THROWS_WITH_AS(model.patch(p2), + "[json.exception.out_of_range.403] (bytes 0-158) key 'a' not found", json::out_of_range&); +#else CHECK_THROWS_WITH_AS(model.patch(p2), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); +#endif } SECTION("issue #961 - incorrect parsing of indefinite length CBOR strings") diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index fab9aae3b..2c3977fef 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT // cmake/test.cmake selects the C++ standard versions with which to build a @@ -71,7 +71,7 @@ enum class for_1647 two }; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive +// NOLINTNEXTLINE(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive NLOHMANN_JSON_SERIALIZE_ENUM(for_1647, { {for_1647::one, "one"}, @@ -90,18 +90,18 @@ struct Data : a(std::move(a_)) , b(std::move(b_)) {} - std::string a{}; - std::string b{}; + std::string a{}; // NOLINT(readability-redundant-member-init) + std::string b{}; // NOLINT(readability-redundant-member-init) }; -void from_json(const json& j, Data& data); +void from_json(const json& j, Data& data); // NOLINT(misc-use-internal-linkage) void from_json(const json& j, Data& data) { j["a"].get_to(data.a); j["b"].get_to(data.b); } -bool operator==(Data const& lhs, Data const& rhs); +bool operator==(Data const& lhs, Data const& rhs); // NOLINT(misc-use-internal-linkage) bool operator==(Data const& lhs, Data const& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; @@ -162,11 +162,11 @@ struct adl_serializer // for #2824 ///////////////////////////////////////////////////////////////////// -class sax_no_exception : public nlohmann::detail::json_sax_dom_parser +class sax_no_exception : public nlohmann::detail::json_sax_dom_parser { public: explicit sax_no_exception(json& j) - : nlohmann::detail::json_sax_dom_parser(j, false) + : nlohmann::detail::json_sax_dom_parser(j, false) {} static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) @@ -218,10 +218,10 @@ class Foo class FooBar { public: - Foo foo{}; + Foo foo{}; // NOLINT(readability-redundant-member-init) }; -inline void from_json(const nlohmann::json& j, FooBar& fb) +inline void from_json(const nlohmann::json& j, FooBar& fb) // NOLINT(misc-use-internal-linkage) { j.at("value").get_to(fb.foo.value); } @@ -233,23 +233,80 @@ inline void from_json(const nlohmann::json& j, FooBar& fb) struct for_3171_base // NOLINT(cppcoreguidelines-special-member-functions) { for_3171_base(const std::string& /*unused*/ = {}) {} - virtual ~for_3171_base() = default; + virtual ~for_3171_base(); + + for_3171_base(const for_3171_base& other) // NOLINT(hicpp-use-equals-default,modernize-use-equals-default) + : str(other.str) + {} + + for_3171_base& operator=(const for_3171_base& other) + { + if (this != &other) + { + str = other.str; + } + return *this; + } + + for_3171_base(for_3171_base&& other) noexcept + : str(std::move(other.str)) + {} + + for_3171_base& operator=(for_3171_base&& other) noexcept + { + if (this != &other) + { + str = std::move(other.str); + } + return *this; + } virtual void _from_json(const json& j) { j.at("str").get_to(str); } - std::string str{}; + std::string str{}; // NOLINT(readability-redundant-member-init) }; +for_3171_base::~for_3171_base() = default; + struct for_3171_derived : public for_3171_base { for_3171_derived() = default; + ~for_3171_derived() override; explicit for_3171_derived(const std::string& /*unused*/) { } + + for_3171_derived(const for_3171_derived& other) // NOLINT(hicpp-use-equals-default,modernize-use-equals-default) + : for_3171_base(other) + {} + + for_3171_derived& operator=(const for_3171_derived& other) + { + if (this != &other) + { + for_3171_base::operator=(other); // Call base class assignment operator + } + return *this; + } + + for_3171_derived(for_3171_derived&& other) noexcept + : for_3171_base(std::move(other)) + {} + + for_3171_derived& operator=(for_3171_derived&& other) noexcept + { + if (this != &other) + { + for_3171_base::operator=(std::move(other)); // Call base class move assignment operator + } + return *this; + } }; -inline void from_json(const json& j, for_3171_base& tb) +for_3171_derived::~for_3171_derived() = default; + +inline void from_json(const json& j, for_3171_base& tb) // NOLINT(misc-use-internal-linkage) { tb._from_json(j); } @@ -264,7 +321,7 @@ struct for_3312 std::string name; }; -inline void from_json(const json& j, for_3312& obj) +inline void from_json(const json& j, for_3312& obj) // NOLINT(misc-use-internal-linkage) { j.at("name").get_to(obj.name); } @@ -320,6 +377,19 @@ inline for_3333::for_3333(const json& j) : for_3333(j.value("x", 0), j.value("y", 0)) {} +///////////////////////////////////////////////////////////////////// +// for #3810 +///////////////////////////////////////////////////////////////////// + +struct Example_3810 +{ + int bla{}; + + Example_3810() = default; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Example_3810, bla); // NOLINT(misc-use-internal-linkage) + TEST_CASE("regression tests 2") { SECTION("issue #1001 - Fix memory leak during parser callback") @@ -622,8 +692,8 @@ TEST_CASE("regression tests 2") // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060 const json j{{"x", "test"}}; const std::string defval = "default value"; - auto val = j.value("x", defval); - auto val2 = j.value("y", defval); + auto val = j.value("x", defval); // NOLINT(bugprone-unused-local-non-trivial-variable) + auto val2 = j.value("y", defval); // NOLINT(bugprone-unused-local-non-trivial-variable) } SECTION("issue #2293 - eof doesn't cause parsing to stop") @@ -675,15 +745,17 @@ TEST_CASE("regression tests 2") } #ifdef JSON_HAS_CPP_20 +#ifndef _LIBCPP_VERSION // see https://github.com/nlohmann/json/issues/4490 #if __has_include() SECTION("issue #2546 - parsing containers of std::byte") { - const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + const char DATA[] = R"("Hello, world!")"; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const auto s = std::as_bytes(std::span(DATA)); const json j = json::parse(s); CHECK(j.dump() == "\"Hello, world!\""); } #endif +#endif #endif SECTION("issue #2574 - Deserialization to std::array, std::pair, and std::tuple with non-default constructable types fails") @@ -755,6 +827,15 @@ TEST_CASE("regression tests 2") } } + SECTION("issue #4530 - Serialization of empty tuple") + { + const auto source_tuple = std::tuple<>(); + const nlohmann::json j = source_tuple; + + CHECK(j.get() == source_tuple); + CHECK("[]" == j.dump()); + } + SECTION("issue #2865 - ASAN detects memory leaks") { // the code below is expected to not leak memory @@ -866,7 +947,7 @@ TEST_CASE("regression tests 2") CHECK(j.dump() == "[1,4]"); } - SECTION("issue #3343 - json and ordered_json are not interchangable") + SECTION("issue #3343 - json and ordered_json are not interchangeable") { json::object_t jobj({ { "product", "one" } }); ordered_json::object_t ojobj({{"product", "one"}}); @@ -936,6 +1017,26 @@ TEST_CASE("regression tests 2") CHECK(p.x == 1); CHECK(p.y == 2); } + + SECTION("issue #3810 - ordered_json doesn't support construction from C array of custom type") + { + Example_3810 states[45]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + + // fix "not used" warning + states[0].bla = 1; + + const auto* const expected = R"([{"bla":1},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0},{"bla":0}])"; + + // This works: + nlohmann::json j; + j["test"] = states; + CHECK(j["test"].dump() == expected); + + // This doesn't compile: + nlohmann::ordered_json oj; + oj["test"] = states; + CHECK(oj["test"].dump() == expected); + } } DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-serialization.cpp b/tests/src/unit-serialization.cpp index e8f0e7e5b..14e4a7007 100644 --- a/tests/src/unit-serialization.cpp +++ b/tests/src/unit-serialization.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -165,7 +165,7 @@ TEST_CASE("serialization") } } -TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t) +TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t) // NOLINT(readability-math-missing-parentheses) { SECTION("minimum") { diff --git a/tests/src/unit-testsuites.cpp b/tests/src/unit-testsuites.cpp index 5807934ba..7e1600cc1 100644 --- a/tests/src/unit-testsuites.cpp +++ b/tests/src/unit-testsuites.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -163,7 +163,7 @@ TEST_CASE("compliance tests from nativejson-benchmark") TEST_DOUBLE("[2.2250738585072012e-308]", 2.2250738585072014e-308); - // More closer to normal/subnormal boundary + // Closer to normal/subnormal boundary // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308 TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164564e-308]", 2.2250738585072009e-308); @@ -312,7 +312,7 @@ TEST_CASE("test suite from json-test-suite") { SECTION("read all sample.json") { - // read a file with all unicode characters stored as single-character + // read a file with all Unicode characters stored as single-character // strings in a JSON array std::ifstream f(TEST_DATA_DIRECTORY "/json_testsuite/sample.json"); json j; @@ -326,6 +326,7 @@ TEST_CASE("test suite from json-test-suite") TEST_CASE("json.org examples") { // here, we list all JSON values from https://json.org/example + using FilePtr = std::unique_ptr; SECTION("1.json") { @@ -363,35 +364,35 @@ TEST_CASE("json.org examples") } SECTION("FILE 1.json") { - const std::unique_ptr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/1.json", "r"), &std::fclose); + const FilePtr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/1.json", "r"), &std::fclose); json _; CHECK_NOTHROW(_ = json::parse(f.get())); } SECTION("FILE 2.json") { - const std::unique_ptr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/2.json", "r"), &std::fclose); + const FilePtr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/2.json", "r"), &std::fclose); json _; CHECK_NOTHROW(_ = json::parse(f.get())); } SECTION("FILE 3.json") { - const std::unique_ptr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/3.json", "r"), &std::fclose); + const FilePtr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/3.json", "r"), &std::fclose); json _; CHECK_NOTHROW(_ = json::parse(f.get())); } SECTION("FILE 4.json") { - const std::unique_ptr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/4.json", "r"), &std::fclose); + const FilePtr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/4.json", "r"), &std::fclose); json _; CHECK_NOTHROW(_ = json::parse(f.get())); } SECTION("FILE 5.json") { - const std::unique_ptr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/5.json", "r"), &std::fclose); + const FilePtr f(std::fopen(TEST_DATA_DIRECTORY "/json.org/5.json", "r"), &std::fclose); json _; CHECK_NOTHROW(_ = json::parse(f.get())); } diff --git a/tests/src/unit-to_chars.cpp b/tests/src/unit-to_chars.cpp index 6d32e0656..4a5482809 100644 --- a/tests/src/unit-to_chars.cpp +++ b/tests/src/unit-to_chars.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT // XXX: diff --git a/tests/src/unit-type_traits.cpp b/tests/src/unit-type_traits.cpp index 4c78aa990..095786708 100644 --- a/tests/src/unit-type_traits.cpp +++ b/tests/src/unit-type_traits.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index 06611c5fe..895ccc89a 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -450,7 +450,7 @@ TEST_CASE("UBJSON") // check individual bytes CHECK(result[0] == 'I'); - auto const restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + auto const restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -655,7 +655,7 @@ TEST_CASE("UBJSON") // check individual bytes CHECK(result[0] == 'I'); - auto const restored = static_cast(static_cast(result[1]) * 256 + static_cast(result[2])); + auto const restored = static_cast((static_cast(result[1]) * 256) + static_cast(result[2])); CHECK(restored == i); // roundtrip @@ -1617,7 +1617,7 @@ TEST_CASE("UBJSON") CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&); json j; - nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; }); @@ -1631,7 +1631,7 @@ TEST_CASE("UBJSON") CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&); json j; - nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept + nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; }); diff --git a/tests/src/unit-udl.cpp b/tests/src/unit-udl.cpp index bb72ccbce..dc92ad6e2 100644 --- a/tests/src/unit-udl.cpp +++ b/tests/src/unit-udl.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-udt.cpp b/tests/src/unit-udt.cpp index b138aa46d..bc6bb7dc0 100644 --- a/tests/src/unit-udt.cpp +++ b/tests/src/unit-udt.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -12,6 +12,11 @@ DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +// skip tests if JSON_DisableEnumSerialization=ON (#4384) +#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) + #define SKIP_TESTS_FOR_ENUM_SERIALIZATION +#endif + #include using nlohmann::json; #ifdef JSON_TEST_NO_GLOBAL_UDLS @@ -52,27 +57,30 @@ struct address struct person { - age m_age{}; - name m_name{}; - country m_country{}; + age m_age{}; // NOLINT(readability-redundant-member-init) + name m_name{}; // NOLINT(readability-redundant-member-init) + country m_country{}; // NOLINT(readability-redundant-member-init) person() = default; person(const age& a, name n, const country& c) : m_age(a), m_name(std::move(n)), m_country(c) {} }; struct contact { - person m_person{}; - address m_address{}; + person m_person{}; // NOLINT(readability-redundant-member-init) + address m_address{}; // NOLINT(readability-redundant-member-init) contact() = default; contact(person p, address a) : m_person(std::move(p)), m_address(std::move(a)) {} }; +enum class book_id : std::uint64_t; + struct contact_book { - name m_book_name{}; - std::vector m_contacts{}; + name m_book_name{}; // NOLINT(readability-redundant-member-init) + book_id m_book_id{}; + std::vector m_contacts{}; // NOLINT(readability-redundant-member-init) contact_book() = default; - contact_book(name n, std::vector c) : m_book_name(std::move(n)), m_contacts(std::move(c)) {} + contact_book(name n, book_id i, std::vector c) : m_book_name(std::move(n)), m_book_id(i), m_contacts(std::move(c)) {} }; } // namespace udt @@ -129,7 +137,11 @@ static void to_json(nlohmann::json& j, const contact& c) static void to_json(nlohmann::json& j, const contact_book& cb) { - j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}}; + j = json{{"name", cb.m_book_name}, +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + {"id", cb.m_book_id}, +#endif + {"contacts", cb.m_contacts}}; } // operators @@ -161,8 +173,8 @@ static bool operator==(const contact& lhs, const contact& rhs) static bool operator==(const contact_book& lhs, const contact_book& rhs) { - return std::tie(lhs.m_book_name, lhs.m_contacts) == - std::tie(rhs.m_book_name, rhs.m_contacts); + return std::tie(lhs.m_book_name, lhs.m_book_id, lhs.m_contacts) == + std::tie(rhs.m_book_name, rhs.m_book_id, rhs.m_contacts); } } // namespace udt @@ -219,6 +231,9 @@ static void from_json(const nlohmann::json& j, contact& c) static void from_json(const nlohmann::json& j, contact_book& cb) { cb.m_book_name = j["name"].get(); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + cb.m_book_id = j["id"].get(); +#endif cb.m_contacts = j["contacts"].get>(); } } // namespace udt @@ -237,7 +252,8 @@ TEST_CASE("basic usage" * doctest::test_suite("udt")) const udt::person senior_programmer{{42}, {"王芳"}, udt::country::china}; const udt::address addr{"Paris"}; const udt::contact cpp_programmer{sfinae_addict, addr}; - const udt::contact_book book{{"C++"}, {cpp_programmer, {senior_programmer, addr}}}; + const udt::book_id large_id{static_cast(static_cast(1) << 63)}; // verify large unsigned enums are handled correctly + const udt::contact_book book{{"C++"}, static_cast(42u), {cpp_programmer, {senior_programmer, addr}}}; SECTION("conversion to json via free-functions") { @@ -248,21 +264,36 @@ TEST_CASE("basic usage" * doctest::test_suite("udt")) CHECK(json("Paris") == json(addr)); CHECK(json(cpp_programmer) == R"({"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"})"_json); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + CHECK(json(large_id) == json(static_cast(1) << 63)); + CHECK(json(large_id) > 0u); + CHECK(to_string(json(large_id)) == "9223372036854775808"); + CHECK(json(large_id).is_number_unsigned()); +#endif +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + CHECK( + json(book) == + R"({"name":"C++", "id":42, "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json); +#else CHECK( json(book) == R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json); +#endif } SECTION("conversion from json via free-functions") { const auto big_json = - R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json; + R"({"name":"C++", "id":42, "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json; SECTION("via explicit calls to get") { const auto parsed_book = big_json.get(); const auto book_name = big_json["name"].get(); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + const auto book_id = big_json["id"].get(); +#endif const auto contacts = big_json["contacts"].get>(); const auto contact_json = big_json["contacts"].at(0); @@ -282,7 +313,10 @@ TEST_CASE("basic usage" * doctest::test_suite("udt")) CHECK(contact == cpp_programmer); CHECK(contacts == book.m_contacts); CHECK(book_name == udt::name{"C++"}); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + CHECK(book_id == book.m_book_id); CHECK(book == parsed_book); +#endif } SECTION("via explicit calls to get_to") @@ -303,6 +337,9 @@ TEST_CASE("basic usage" * doctest::test_suite("udt")) { const udt::contact_book parsed_book = big_json; const udt::name book_name = big_json["name"]; +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + const udt::book_id book_id = big_json["id"]; +#endif const std::vector contacts = big_json["contacts"]; const auto contact_json = big_json["contacts"].at(0); const udt::contact contact = contact_json; @@ -320,7 +357,10 @@ TEST_CASE("basic usage" * doctest::test_suite("udt")) CHECK(contact == cpp_programmer); CHECK(contacts == book.m_contacts); CHECK(book_name == udt::name{"C++"}); +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + CHECK(book_id == static_cast(42u)); CHECK(book == parsed_book); +#endif } #endif } @@ -330,7 +370,7 @@ namespace udt { struct legacy_type { - std::string number{}; + std::string number{}; // NOLINT(readability-redundant-member-init) legacy_type() = default; legacy_type(std::string n) : number(std::move(n)) {} }; @@ -603,7 +643,7 @@ struct small_pod struct non_pod { - std::string s{}; + std::string s{}; // NOLINT(readability-redundant-member-init) non_pod() = default; non_pod(std::string S) : s(std::move(S)) {} }; diff --git a/tests/src/unit-udt_macro.cpp b/tests/src/unit-udt_macro.cpp index e2383f40d..5d204e451 100644 --- a/tests/src/unit-udt_macro.cpp +++ b/tests/src/unit-udt_macro.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include @@ -18,7 +18,7 @@ namespace persons class person_with_private_data { private: - std::string name{}; + std::string name{}; // NOLINT(readability-redundant-member-init) int age = 0; json metadata = nullptr; @@ -38,10 +38,30 @@ class person_with_private_data NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata) }; +class derived_person_with_private_data : public person_with_private_data +{ + private: + std::string hair_color{"blue"}; + + public: + bool operator==(const derived_person_with_private_data& rhs) const + { + return person_with_private_data::operator==(rhs) && hair_color == rhs.hair_color; + } + + derived_person_with_private_data() = default; + derived_person_with_private_data(std::string name_, int age_, json metadata_, std::string hair_color_) + : person_with_private_data(std::move(name_), age_, std::move(metadata_)) + , hair_color(std::move(hair_color_)) + {} + + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(derived_person_with_private_data, person_with_private_data, hair_color) +}; + class person_with_private_data_2 { private: - std::string name{}; + std::string name{}; // NOLINT(readability-redundant-member-init) int age = 0; json metadata = nullptr; @@ -74,10 +94,35 @@ class person_with_private_data_2 NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person_with_private_data_2, age, name, metadata) }; +class derived_person_with_private_data_2 : public person_with_private_data_2 +{ + private: + std::string hair_color{"blue"}; + + public: + bool operator==(const derived_person_with_private_data_2& rhs) const + { + return person_with_private_data_2::operator==(rhs) && hair_color == rhs.hair_color; + } + + derived_person_with_private_data_2() = default; + derived_person_with_private_data_2(std::string name_, int age_, json metadata_, std::string hair_color_) + : person_with_private_data_2(std::move(name_), age_, std::move(metadata_)) + , hair_color(std::move(hair_color_)) + {} + + std::string getHairColor() const + { + return hair_color; + } + + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(derived_person_with_private_data_2, person_with_private_data_2, hair_color) +}; + class person_without_private_data_1 { public: - std::string name{}; + std::string name{}; // NOLINT(readability-redundant-member-init) int age = 0; json metadata = nullptr; @@ -96,10 +141,30 @@ class person_without_private_data_1 NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata) }; +class derived_person_without_private_data_1 : public person_without_private_data_1 +{ + public: + std::string hair_color{"blue"}; + + public: + bool operator==(const derived_person_without_private_data_1& rhs) const + { + return person_without_private_data_1::operator==(rhs) && hair_color == rhs.hair_color; + } + + derived_person_without_private_data_1() = default; + derived_person_without_private_data_1(std::string name_, int age_, json metadata_, std::string hair_color_) + : person_without_private_data_1(std::move(name_), age_, std::move(metadata_)) + , hair_color(std::move(hair_color_)) + {} + + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(derived_person_without_private_data_1, person_without_private_data_1, hair_color) +}; + class person_without_private_data_2 { public: - std::string name{}; + std::string name{}; // NOLINT(readability-redundant-member-init) int age = 0; json metadata = nullptr; @@ -116,12 +181,34 @@ class person_without_private_data_2 {} }; +// NOLINTNEXTLINE(misc-use-internal-linkage) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata) +class derived_person_without_private_data_2 : public person_without_private_data_2 +{ + public: + std::string hair_color{"blue"}; + + public: + bool operator==(const derived_person_without_private_data_2& rhs) const + { + return person_without_private_data_2::operator==(rhs) && hair_color == rhs.hair_color; + } + + derived_person_without_private_data_2() = default; + derived_person_without_private_data_2(std::string name_, int age_, json metadata_, std::string hair_color_) + : person_without_private_data_2(std::move(name_), age_, std::move(metadata_)) + , hair_color(std::move(hair_color_)) + {} +}; + +// NOLINTNEXTLINE(misc-use-internal-linkage) +NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(derived_person_without_private_data_2, person_without_private_data_2, hair_color) + class person_without_private_data_3 { public: - std::string name{}; + std::string name{}; // NOLINT(readability-redundant-member-init) int age = 0; json metadata = nullptr; @@ -151,8 +238,35 @@ class person_without_private_data_3 } }; +// NOLINTNEXTLINE(misc-use-internal-linkage) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person_without_private_data_3, age, name, metadata) +class derived_person_without_private_data_3 : public person_without_private_data_3 +{ + public: + std::string hair_color{"blue"}; + + public: + bool operator==(const derived_person_without_private_data_3& rhs) const + { + return person_without_private_data_3::operator==(rhs) && hair_color == rhs.hair_color; + } + + derived_person_without_private_data_3() = default; + derived_person_without_private_data_3(std::string name_, int age_, json metadata_, std::string hair_color_) + : person_without_private_data_3(std::move(name_), age_, std::move(metadata_)) + , hair_color(std::move(hair_color_)) + {} + + std::string getHairColor() const + { + return hair_color; + } +}; + +// NOLINTNEXTLINE(misc-use-internal-linkage) +NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(derived_person_without_private_data_3, person_without_private_data_3, hair_color) + class person_with_private_alphabet { public: @@ -277,6 +391,7 @@ class person_with_public_alphabet int z = 0; }; +// NOLINTNEXTLINE(misc-use-internal-linkage) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_with_public_alphabet, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) class person_without_default_constructor_1 @@ -315,160 +430,280 @@ class person_without_default_constructor_2 {} }; +// NOLINTNEXTLINE(misc-use-internal-linkage) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(person_without_default_constructor_2, name, age) +class derived_person_only_serialize_public : public person_without_default_constructor_1 +{ + public: + std::string hair_color; + + derived_person_only_serialize_public(std::string name_, int age_, std::string hair_color_) + : person_without_default_constructor_1(std::move(name_), age_) + , hair_color(std::move(hair_color_)) + {} +}; + +// NOLINTNEXTLINE(misc-use-internal-linkage) +NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(derived_person_only_serialize_public, person_without_default_constructor_1, hair_color) + +class derived_person_only_serialize_private : person_without_default_constructor_1 +{ + private: + std::string hair_color; + public: + derived_person_only_serialize_private(std::string name_, int age_, std::string hair_color_) + : person_without_default_constructor_1(std::move(name_), age_) + , hair_color(std::move(hair_color_)) + {} + + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(derived_person_only_serialize_private, person_without_default_constructor_1, hair_color) +}; + } // namespace persons -TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T, - persons::person_with_private_data, - persons::person_without_private_data_1, - persons::person_without_private_data_2) +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair) { + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + SECTION("person") { // serialization T p1("Erik", 1, {{"haircuts", 2}}); - CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}"); + CHECK(Json(p1).dump() == (is_ordered ? + R"({"age":1,"name":"Erik","metadata":{"haircuts":2}})" : + R"({"age":1,"metadata":{"haircuts":2},"name":"Erik"})")); // deserialization - auto p2 = json(p1).get(); + auto p2 = Json(p1).template get(); CHECK(p2 == p1); // roundtrip - CHECK(T(json(p1)) == p1); - CHECK(json(T(json(p1))) == json(p1)); + CHECK(T(Json(p1)) == p1); + CHECK(Json(T(Json(p1))) == Json(p1)); // check exception in case of missing field - json j = json(p1); + Json j = Json(p1); j.erase("age"); - CHECK_THROWS_WITH_AS(j.get(), "[json.exception.out_of_range.403] key 'age' not found", json::out_of_range); + CHECK_THROWS_WITH_AS(j.template get(), "[json.exception.out_of_range.403] key 'age' not found", typename Json::out_of_range); } } -TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT", T, - persons::person_with_private_data_2, - persons::person_without_private_data_3) +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE and NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair) { + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + + SECTION("person") + { + // serialization + T p1("Erik", 1, {{"haircuts", 2}}, "red"); + CHECK(Json(p1).dump() == (is_ordered ? + R"({"age":1,"name":"Erik","metadata":{"haircuts":2},"hair_color":"red"})" : + R"({"age":1,"hair_color":"red","metadata":{"haircuts":2},"name":"Erik"})")); + + // deserialization + auto p2 = Json(p1).template get(); + CHECK(p2 == p1); + + // roundtrip + CHECK(T(Json(p1)) == p1); + CHECK(Json(T(Json(p1))) == Json(p1)); + + // check exception in case of missing field + Json j = Json(p1); + j.erase("age"); + CHECK_THROWS_WITH_AS(j.template get(), "[json.exception.out_of_range.403] key 'age' not found", typename Json::out_of_range); + } +} + +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair) +{ + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + SECTION("person with default values") { // serialization of default constructed object - T p0; - CHECK(json(p0).dump() == "{\"age\":0,\"metadata\":null,\"name\":\"\"}"); + const T p0{}; + CHECK(Json(p0).dump() == (is_ordered ? + R"({"age":0,"name":"","metadata":null})" : + R"({"age":0,"metadata":null,"name":""})")); // serialization T p1("Erik", 1, {{"haircuts", 2}}); - CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}"); + CHECK(Json(p1).dump() == (is_ordered ? + R"({"age":1,"name":"Erik","metadata":{"haircuts":2}})" : + R"({"age":1,"metadata":{"haircuts":2},"name":"Erik"})")); // deserialization - auto p2 = json(p1).get(); + auto p2 = Json(p1).template get(); CHECK(p2 == p1); // roundtrip - CHECK(T(json(p1)) == p1); - CHECK(json(T(json(p1))) == json(p1)); + CHECK(T(Json(p1)) == p1); + CHECK(Json(T(Json(p1))) == Json(p1)); // check default value in case of missing field - json j = json(p1); + Json j = Json(p1); j.erase("name"); j.erase("age"); j.erase("metadata"); - T p3 = j.get(); + const T p3 = j.template get(); CHECK(p3.getName() == ""); CHECK(p3.getAge() == 0); CHECK(p3.getMetadata() == nullptr); + + // check default value in case of empty json + const Json j4; + const T p4 = j4.template get(); + CHECK(p4.getName() == ""); + CHECK(p4.getAge() == 0); + CHECK(p4.getMetadata() == nullptr); } } -TEST_CASE_TEMPLATE("Serialization/deserialization of classes with 26 public/private member variables via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T, - persons::person_with_private_alphabet, - persons::person_with_public_alphabet) +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair) { + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + + SECTION("derived person with default values") + { + // serialization of default constructed object + const T p0{}; + CHECK(Json(p0).dump() == (is_ordered ? + R"({"age":0,"name":"","metadata":null,"hair_color":"blue"})" : + R"({"age":0,"hair_color":"blue","metadata":null,"name":""})")); + + // serialization + T p1("Erik", 1, {{"haircuts", 2}}, "red"); + CHECK(Json(p1).dump() == (is_ordered ? + R"({"age":1,"name":"Erik","metadata":{"haircuts":2},"hair_color":"red"})" : + R"({"age":1,"hair_color":"red","metadata":{"haircuts":2},"name":"Erik"})")); + + // deserialization + auto p2 = Json(p1).template get(); + CHECK(p2 == p1); + + // roundtrip + CHECK(T(Json(p1)) == p1); + CHECK(Json(T(Json(p1))) == Json(p1)); + + // check default value in case of missing field + Json j = Json(p1); + j.erase("name"); + j.erase("age"); + j.erase("metadata"); + j.erase("hair_color"); + const T p3 = j.template get(); + CHECK(p3.getName() == ""); + CHECK(p3.getAge() == 0); + CHECK(p3.getMetadata() == nullptr); + CHECK(p3.getHairColor() == "blue"); + } +} + +TEST_CASE_TEMPLATE("Serialization/deserialization of classes with 26 public/private member variables via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair) +{ + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + SECTION("alphabet") { - { - T obj1; - nlohmann::json const j = obj1; //via json object - T obj2; - j.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } - - { - T obj1; - nlohmann::json const j1 = obj1; //via json string - std::string const s = j1.dump(); - nlohmann::json const j2 = nlohmann::json::parse(s); - T obj2; - j2.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } - - { - T obj1; - nlohmann::json const j1 = obj1; //via msgpack - std::vector const buf = nlohmann::json::to_msgpack(j1); - nlohmann::json const j2 = nlohmann::json::from_msgpack(buf); - T obj2; - j2.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } - - { - T obj1; - nlohmann::json const j1 = obj1; //via bson - std::vector const buf = nlohmann::json::to_bson(j1); - nlohmann::json const j2 = nlohmann::json::from_bson(buf); - T obj2; - j2.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } - - { - T obj1; - nlohmann::json const j1 = obj1; //via cbor - std::vector const buf = nlohmann::json::to_cbor(j1); - nlohmann::json const j2 = nlohmann::json::from_cbor(buf); - T obj2; - j2.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } - - { - T obj1; - nlohmann::json const j1 = obj1; //via ubjson - std::vector const buf = nlohmann::json::to_ubjson(j1); - nlohmann::json const j2 = nlohmann::json::from_ubjson(buf); - T obj2; - j2.get_to(obj2); - bool ok = (obj1 == obj2); - CHECK(ok); - } + T obj1; + Json const j = obj1; + T obj2; + j.get_to(obj2); + CHECK(obj1 == obj2); } } -TEST_CASE_TEMPLATE("Serialization of non-default-constructible classes via NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE", T, - persons::person_without_default_constructor_1, - persons::person_without_default_constructor_2) +TEST_CASE_TEMPLATE("Serialization of non-default-constructible classes via NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair) { + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + SECTION("person") { - { - // serialization of a single object - T person{"Erik", 1}; - CHECK(json(person).dump() == "{\"age\":1,\"name\":\"Erik\"}"); + // serialization of a single object + const T person{"Erik", 1}; + CHECK(Json(person).dump() == (is_ordered ? + R"({"name":"Erik","age":1})" : + R"({"age":1,"name":"Erik"})")); - // serialization of a container with objects - std::vector const two_persons - { - {"Erik", 1}, - {"Kyle", 2} - }; - CHECK(json(two_persons).dump() == "[{\"age\":1,\"name\":\"Erik\"},{\"age\":2,\"name\":\"Kyle\"}]"); - } + // serialization of a container with objects + std::vector const two_persons + { + {"Erik", 1}, + {"Kyle", 2} + }; + CHECK(Json(two_persons).dump() == (is_ordered ? + R"([{"name":"Erik","age":1},{"name":"Kyle","age":2}])" : + R"([{"age":1,"name":"Erik"},{"age":2,"name":"Kyle"}])")); + } +} + +TEST_CASE_TEMPLATE("Serialization of non-default-constructible classes via NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE and NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE", Pair, // NOLINT(readability-math-missing-parentheses) + std::pair, + std::pair, + std::pair, + std::pair) +{ + using Json = typename Pair::first_type; + using T = typename Pair::second_type; + constexpr bool is_ordered = std::is_same::value; + + SECTION("derived person only serialize") + { + // serialization of a single object + const T person{"Erik", 1, "brown"}; + CHECK(Json(person).dump() == (is_ordered ? + R"({"name":"Erik","age":1,"hair_color":"brown"})" : + R"({"age":1,"hair_color":"brown","name":"Erik"})")); + + // serialization of a container with objects + std::vector const two_persons + { + {"Erik", 1, "brown"}, + {"Kyle", 2, "black"} + }; + CHECK(Json(two_persons).dump() == (is_ordered ? + R"([{"name":"Erik","age":1,"hair_color":"brown"},{"name":"Kyle","age":2,"hair_color":"black"}])" : + R"([{"age":1,"hair_color":"brown","name":"Erik"},{"age":2,"hair_color":"black","name":"Kyle"}])")); } } diff --git a/tests/src/unit-unicode1.cpp b/tests/src/unit-unicode1.cpp index e4405c474..d3de191c0 100644 --- a/tests/src/unit-unicode1.cpp +++ b/tests/src/unit-unicode1.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" @@ -155,7 +155,7 @@ TEST_CASE("Unicode (1/5)" * doctest::skip()) SECTION("read all unicode characters") { - // read a file with all unicode characters stored as single-character + // read a file with all Unicode characters stored as single-character // strings in a JSON array std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json"); json j; diff --git a/tests/src/unit-unicode2.cpp b/tests/src/unit-unicode2.cpp index ebc29db52..1d765fca7 100644 --- a/tests/src/unit-unicode2.cpp +++ b/tests/src/unit-unicode2.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-unicode3.cpp b/tests/src/unit-unicode3.cpp index dffb1cfa6..7d505235f 100644 --- a/tests/src/unit-unicode3.cpp +++ b/tests/src/unit-unicode3.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-unicode4.cpp b/tests/src/unit-unicode4.cpp index 6a0e08989..874b4ca87 100644 --- a/tests/src/unit-unicode4.cpp +++ b/tests/src/unit-unicode4.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-unicode5.cpp b/tests/src/unit-unicode5.cpp index 217d3b38d..7b56d85d5 100644 --- a/tests/src/unit-unicode5.cpp +++ b/tests/src/unit-unicode5.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-user_defined_input.cpp b/tests/src/unit-user_defined_input.cpp index 5483f6a0c..befc4b17a 100644 --- a/tests/src/unit-user_defined_input.cpp +++ b/tests/src/unit-user_defined_input.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-windows_h.cpp b/tests/src/unit-windows_h.cpp index 9c1535854..0c654e7ab 100644 --- a/tests/src/unit-windows_h.cpp +++ b/tests/src/unit-windows_h.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit-wstring.cpp b/tests/src/unit-wstring.cpp index 1aaa13ba8..13d115b29 100644 --- a/tests/src/unit-wstring.cpp +++ b/tests/src/unit-wstring.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" diff --git a/tests/src/unit.cpp b/tests/src/unit.cpp index adb39dba1..7eb86e315 100644 --- a/tests/src/unit.cpp +++ b/tests/src/unit.cpp @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann // SPDX-License-Identifier: MIT #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN diff --git a/tests/thirdparty/imapdl/filterbr.py b/tests/thirdparty/imapdl/filterbr.py index e8714c7ef..49e37aa60 100755 --- a/tests/thirdparty/imapdl/filterbr.py +++ b/tests/thirdparty/imapdl/filterbr.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # 2017, Georg Sauthoff , GPLv3 +# 2022, Alexander Stohr, ZF Friedrichshafen AG: benign handling of UTF-8 violations import sys @@ -49,7 +50,7 @@ def cond_lines(lines): p = n continue if (p == 0 or not line[p-1].isalpha()) \ - and (p+2 == len(line) or not line[p+2].isalpha()): + and (p+2 == len(line) or not line[p+2].isalpha()): do_yield = True state = 1 p += 2 @@ -93,7 +94,9 @@ def filter_lcov_trace(lines): yield line def filter_lcov_trace_file(s_filename, d_file): - with open(s_filename) as f: + # encoding is anyways the python default: utf-8 + # standard error is "strict"; python style escaping is "backslashreplace"; alternate benign handler is "surrogateescape" + with open(s_filename, encoding="utf-8", errors="backslashreplace") as f: for l in filter_lcov_trace(f): print(l, end='', file=d_file) @@ -106,4 +109,3 @@ if __name__ == '__main__': #with open(sys.argv[1]) as f: # for l in skip_comments(f): # print(l) - diff --git a/tools/amalgamate/README.md b/tools/amalgamate/README.md index 975ca0bdf..8e088c4d2 100644 --- a/tools/amalgamate/README.md +++ b/tools/amalgamate/README.md @@ -1,4 +1,3 @@ - # amalgamate.py - Amalgamate C source and header files Origin: https://bitbucket.org/erikedlund/amalgamate diff --git a/tools/astyle/.astylerc b/tools/astyle/.astylerc new file mode 100644 index 000000000..580a3fca5 --- /dev/null +++ b/tools/astyle/.astylerc @@ -0,0 +1,80 @@ +# Configuration for Artistic Style +# see https://astyle.sourceforge.net/astyle.html + +####################### +# Brace Style Options # +####################### + +# use Allman style for braces +--style=allman + +############### +# Tab Options # +############### + +# indent using 4 spaces +--indent=spaces=4 + +####################### +# Indentation Options # +####################### + +# indent access modifiers one half indent +--indent-modifiers + +# indent switch cases to the switch block +--indent-switches + +# indent preprocessor blocks +--indent-preproc-block + +# indent preprocessor defines +--indent-preproc-define + +# indent C++ comments +--indent-col1-comments + +################### +# Padding Options # +################### + +# insert space padding around operators +--pad-oper + +# insert space between if/for/while... and the following parentheses +--pad-header + +# attach the pointer to the variable type (left) +--align-pointer=type + +# attach the reference to the variable type (left) +--align-reference=type + +###################### +# Formatting Options # +###################### + +# add braces to unbraced one line conditional statements +--add-braces + +# convert tabs to spaces +--convert-tabs + +# closes whitespace between the ending angle brackets of template definitions +--close-templates + +################# +# Other Options # +################# + +# do not create backup files +--suffix=none + +# preserve the original file date +--preserve-date + +# display only the files that have been formatted +--formatted + +# for the linux (LF) line end style +--lineend=linux diff --git a/tools/astyle/requirements.txt b/tools/astyle/requirements.txt new file mode 100644 index 000000000..99458a860 --- /dev/null +++ b/tools/astyle/requirements.txt @@ -0,0 +1 @@ +astyle==3.4.13 diff --git a/tools/gdb_pretty_printer/README.md b/tools/gdb_pretty_printer/README.md index c1a3651d4..4a95776df 100644 --- a/tools/gdb_pretty_printer/README.md +++ b/tools/gdb_pretty_printer/README.md @@ -1,6 +1,7 @@ # GDB Pretty Printer -File [nlohmann-json.py](nlohmann-json.py) contains a pretty printer for GDB for JSON values of this library. It was originally published as [Gist](https://gist.github.com/ssbssa/60da5339c6e6036b2afce17de06050ea#file-nlohmann-json-py) by [Hannes Domani](https://github.com/ssbssa). +File [nlohmann-json.py](nlohmann-json.py) contains a pretty printer for GDB for JSON values of this library. It was +originally published as [Gist](https://gist.github.com/ssbssa/60da5339c6e6036b2afce17de06050ea#file-nlohmann-json-py) by [Hannes Domani](https://github.com/ssbssa). ## How to use diff --git a/tools/gdb_pretty_printer/nlohmann-json.py b/tools/gdb_pretty_printer/nlohmann-json.py index 299152aed..2c120befd 100644 --- a/tools/gdb_pretty_printer/nlohmann-json.py +++ b/tools/gdb_pretty_printer/nlohmann-json.py @@ -15,18 +15,21 @@ class JsonValuePrinter: def json_lookup_function(val): if m := ns_pattern.fullmatch(str(val.type.strip_typedefs().name)): - name = m.group('name') - if name and name.startswith('basic_json<') and name.endswith('>'): - m = ns_pattern.fullmatch(str(val['m_type'])) - t = m.group('name') - if t and t.startswith('detail::value_t::'): - try: - union_val = val['m_value'][t.removeprefix('detail::value_t::')] - if union_val.type.code == gdb.TYPE_CODE_PTR: - return gdb.default_visualizer(union_val.dereference()) - else: - return JsonValuePrinter(union_val) - except Exception: - return JsonValuePrinter(val['m_type']) + name = m.group('name') + if name and name.startswith('basic_json<') and name.endswith('>'): + m_data = val['m_data'] + m_type = m_data['m_type'] + m = ns_pattern.fullmatch(str(m_type)) + t = m.group('name') + prefix = 'detail::value_t::' + if t and t.startswith(prefix): + try: + union_val = m_data['m_value'][t.replace(prefix, '', 1)] + if union_val.type.code == gdb.TYPE_CODE_PTR: + return gdb.default_visualizer(union_val.dereference()) + else: + return JsonValuePrinter(union_val) + except Exception: + return JsonValuePrinter(m_type) gdb.pretty_printers.append(json_lookup_function) diff --git a/tools/generate_natvis/README.md b/tools/generate_natvis/README.md index b4d3a7d7f..e11f29eec 100644 --- a/tools/generate_natvis/README.md +++ b/tools/generate_natvis/README.md @@ -1,10 +1,9 @@ -generate_natvis.py -================== +# generate_natvis.py Generate the Natvis debugger visualization file for all supported namespace combinations. ## Usage -``` +```shell ./generate_natvis.py --version X.Y.Z output_directory/ ``` diff --git a/tools/generate_natvis/nlohmann_json.natvis.j2 b/tools/generate_natvis/nlohmann_json.natvis.j2 index d6b728935..c3eafa54b 100644 --- a/tools/generate_natvis/nlohmann_json.natvis.j2 +++ b/tools/generate_natvis/nlohmann_json.natvis.j2 @@ -8,21 +8,21 @@ {% for ns in namespaces %} - null - {*(m_value.object)} - {*(m_value.array)} - {*(m_value.string)} - {m_value.boolean} - {m_value.number_integer} - {m_value.number_unsigned} - {m_value.number_float} - discarded + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded - - *(m_value.object),view(simple) + + *(m_data.m_value.object),view(simple) - - *(m_value.array),view(simple) + + *(m_data.m_value.array),view(simple) diff --git a/tools/generate_natvis/requirements.txt b/tools/generate_natvis/requirements.txt new file mode 100644 index 000000000..6bbf6aa1d --- /dev/null +++ b/tools/generate_natvis/requirements.txt @@ -0,0 +1 @@ +jinja2==3.1.6 diff --git a/tools/serve_header/requirements.txt b/tools/serve_header/requirements.txt index d32eed3bd..c399c52b4 100644 --- a/tools/serve_header/requirements.txt +++ b/tools/serve_header/requirements.txt @@ -1,2 +1,2 @@ -PyYAML==6.0 -watchdog==2.1.7 +PyYAML==6.0.2 +watchdog==6.0.0 diff --git a/wsjcpp.yml b/wsjcpp.yml deleted file mode 100644 index e6443cf82..000000000 --- a/wsjcpp.yml +++ /dev/null @@ -1,26 +0,0 @@ -wsjcpp_version: "v0.1.1" -cmake_minimum_required: "3.0" -cmake_cxx_standard: "11" -name: "nlohmann/json" -version: "v3.11.3" -description: "JSON for Modern C++" -issues: "https://github.com/nlohmann/json/issues" -keywords: - - "c++" - - "json" - -repositories: - - type: main - url: "https://github.com/nlohmann/json" - -authors: - - name: "Niels Lohmann" - email: "mail@nlohmann.me" - -distribution: - - source-file: "single_include/nlohmann/json.hpp" - target-file: "json.hpp" - type: "source-code" - - source-file: "single_include/nlohmann/json_fwd.hpp" - target-file: "json_fwd.hpp" - type: "source-code"