Overwork documentation (#3444)

* 📝 overwork macro documentation

* 📝 address review comments

* 🔧 add style check to Makefile

* 🙈 overwork .gitignore

* 📌 Pygments 2.12.0 is broken

* ✏️ fix links

* 🚸 adjust output to cppcheck

* 📝 add titles to more admonitions

* ✏️ fix typos

* 📝 document future behavior change
This commit is contained in:
Niels Lohmann
2022-04-25 22:40:45 +02:00
committed by GitHub
parent fcc36f99ba
commit a6ee8bf9d9
63 changed files with 1689 additions and 366 deletions

View File

@@ -77,7 +77,7 @@ 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 `get<your_type>()`, `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://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) 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.
* 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.
@@ -87,16 +87,19 @@ If you just want to serialize/deserialize some structs, the `to_json`/`from_json
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:
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` 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, ...)` 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_INTRUSIVE(name, member1, member2, ...)` 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, ...)` 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_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_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.
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).
!!! note
!!! info "Implementation limits"
At most 64 member variables can be passed to these macros.
- 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

View File

@@ -0,0 +1,104 @@
# 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
detect bugs in client code.
## Switch off runtime assertions
Runtime assertions can be switched off by defining the preprocessor macro `NDEBUG` (see the
[documentation of assert](https://en.cppreference.com/w/cpp/error/assert)) which is the default for release builds.
## Change assertion behavior
The behavior of runtime assertions can be changes by defining macro [`JSON_ASSERT(x)`](../api/macros/json_assert.md)
before including the `json.hpp` header.
## Function with runtime assertions
### 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.
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.
See also the documentation on [element access](element_access/index.md).
??? example "Example 1: Missing object key"
The following code will trigger an assertion at runtime:
```cpp
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
const json j = {{"key", "value"}};
auto v = j["missing"];
}
```
Output:
```
Assertion failed: (m_value.object->find(key) != m_value.object->end()), function operator[], file json.hpp, line 2144.
```
### Constructing from an uninitialized iterator range
Constructing a JSON value from an iterator range (see [constructor](../api/basic_json/basic_json.md)) with an
uninitialized iterator is undefined behavior and yields a runtime assertion.
??? example "Example 2: Uninitialized iterator range"
The following code will trigger an assertion at runtime:
```cpp
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
json::iterator it1, it2;
json j(it1, it2);
}
```
Output:
```
Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368.
```
### Operations on uninitialized iterators
Any operation on uninitialized iterators (i.e., iterators that are not associated with any JSON value) is undefined
behavior and yields a runtime assertion.
??? example "Example 3: Uninitialized iterator"
The following code will trigger an assertion at runtime:
```cpp
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
json::iterator it;
++it;
}
```
Output:
```
Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368.
```

View File

@@ -94,9 +94,9 @@ When accessing an invalid index (i.e., an index greater than or equal to the arr
## Summary
| scenario | non-const value | const value |
|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|
| access to existing object key | reference to existing value is returned | const reference to existing value is returned |
| access to valid array index | reference to existing value is returned | const reference to existing value is returned |
| access to non-existing object key | reference to newly inserted `#!json null` value is returned | **undefined behavior**; assertion in debug mode |
| access to invalid array index | reference to newly inserted `#!json null` value is returned; any index between previous maximal index and passed index are filled with `#!json null` | **undefined behavior**; assertion in debug mode |
| scenario | non-const value | const value |
|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| access to existing object key | reference to existing value is returned | const reference to existing value is returned |
| access to valid array index | reference to existing value is returned | const reference to existing value is returned |
| access to non-existing object key | reference to newly inserted `#!json null` value is returned | **undefined behavior**; [runtime assertion](../assertions.md) in debug mode |
| access to invalid array index | reference to newly inserted `#!json null` value is returned; any index between previous maximal index and passed index are filled with `#!json null` | **undefined behavior**; [runtime assertion](../assertions.md) in debug mode |

View File

@@ -24,8 +24,8 @@ NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
})
```
The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState`
while avoiding repetition and boilerplate serialization code.
The [`NLOHMANN_JSON_SERIALIZE_ENUM()` macro](../api/macros/nlohmann_json_serialize_enum.md) declares a set of
`to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serialization code.
## Usage
@@ -45,10 +45,11 @@ assert(jPi.get<TaskState>() == TS_INVALID );
## Notes
Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above,
Just as in [Arbitrary Type Conversions](arbitrary_types.md) 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.
- [`NLOHMANN_JSON_SERIALIZE_ENUM()`](../api/macros/nlohmann_json_serialize_enum.md) 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:

View File

@@ -1,47 +1,19 @@
# Supported Macros
Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header.
See also the [API documentation for macros](../api/macros/index.md) for examples and more information.
## `JSON_ASSERT(x)`
This macro controls which code is executed for runtime assertions of the libraries.
This macro controls which code is executed for [runtime assertions](assertions.md) of the library.
!!! info "Default behavior"
The default value is [`#!cpp assert(x)`](https://en.cppreference.com/w/cpp/error/assert).
```cpp
#define JSON_ASSERT(x) assert(x)
```
The macro was introduced in version 3.9.0.
See [full documentation of `JSON_ASSERT(x)`](../api/macros/json_assert.md).
## `JSON_CATCH_USER(exception)`
This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/try_catch) calls inside the library.
The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range`
exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The
macro is always followed by a scope.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
!!! info "Default behavior"
When exceptions are enabled, the default value is
[`#!cpp catch(exception)`](https://en.cppreference.com/w/cpp/language/try_catch).
```cpp
#define JSON_CATCH_USER(exception) catch(exception)
```
When exceptions are switched off by the compiler, the default value is `#!cpp if (false)` to make the catch block
unreachable.
```cpp
#define JSON_CATCH_USER(exception) if (false)
```
The macro was introduced in version 3.1.0.
See [full documentation of `JSON_CATCH_USER(exception)`](../api/macros/json_throw_user.md).
## `JSON_DIAGNOSTICS`
@@ -55,19 +27,7 @@ that enabling this macro increases the size of every JSON value by one pointer a
The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets
`JSON_DIAGNOSTICS` accordingly.
!!! warning
As this macro changes the definition of the `basic_json` object, it MUST be defined in the same way globally, even
across different compilation units; DO NOT link together code compiled with different definitions of
`JSON_DIAGNOSTICS` as this is a violation of the One Definition Rule and will cause undefined behaviour.
!!! info "Default behavior"
```cpp
#define JSON_DIAGNOSTICS 0
```
The macro was introduced in version 3.10.0.
See [full documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md).
## `JSON_HAS_CPP_11`, `JSON_HAS_CPP_14`, `JSON_HAS_CPP_17`, `JSON_HAS_CPP_20`
@@ -77,12 +37,7 @@ standard. By defining any of these symbols, the internal check is overridden and
unconditionally assumed. This can be helpful for compilers that only implement parts of the standard and would be
detected incorrectly.
!!! info "Default behavior"
The default value is detected based on the preprocessor macros `#!cpp __cplusplus`, `#!cpp _HAS_CXX17`, or
`#!cpp _MSVC_LANG`.
The macros were introduced in version 3.10.5.
See [full documentation of `JSON_HAS_CPP_11`, `JSON_HAS_CPP_14`, `JSON_HAS_CPP_17`, and `JSON_HAS_CPP_20`](../api/macros/json_has_cpp_11.md).
## `JSON_HAS_FILESYSTEM`, `JSON_HAS_EXPERIMENTAL_FILESYSTEM`
@@ -91,37 +46,13 @@ for filesystem is limited, the library tries to detect whether `<filesystem>`/`s
or `<experimental/filesystem>`/`std::experimental::filesystem` (`JSON_HAS_EXPERIMENTAL_FILESYSTEM`) should be used.
To override the built-in check, define `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` to `1`.
!!! info "Default behavior"
The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_filesystem`,
`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or
`#!cpp __has_include(<experimental/filesystem>)`.
Note that older compilers or older versions of libstd++ also require the library `stdc++fs` to be linked to for
filesystem support.
The macros were introduced in version 3.10.5.
See [full documentation of `JSON_HAS_FILESYSTEM` and `JSON_HAS_EXPERIMENTAL_FILESYSTEM`](../api/macros/json_has_filesystem.md).
## `JSON_NOEXCEPTION`
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. When defining `JSON_NOEXCEPTION`, `#!cpp try`
is replaced by `#!cpp if (true)`, `#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by
`#!cpp std::abort()`.
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
!!! info "Default behavior"
By default, the macro is not defined.
```cpp
#undef JSON_NOEXCEPTION
```
The same effect is achieved by setting the compiler flag `-fno-exceptions`.
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).
The macro was introduced in version 2.1.0.
See [full documentation of `JSON_NOEXCEPTION`](../api/macros/json_noexception.md).
## `JSON_NO_IO`
@@ -129,128 +60,39 @@ When defined, headers `<cstdio>`, `<ios>`, `<iosfwd>`, `<istream>`, and `<ostrea
relying on these headers are excluded. This is relevant for environment where these I/O functions are disallowed for
security reasons (e.g., Intel Software Guard Extensions (SGX)).
!!! info "Default behavior"
By default, the macro is not defined.
```cpp
#undef JSON_NO_IO
```
The macro was introduced in version 3.10.0.
See [full documentation of `JSON_NO_IO`](../api/macros/json_no_io.md).
## `JSON_SKIP_LIBRARY_VERSION_CHECK`
When defined, the library will not create a compiler warning when a different version of the library was already
included.
!!! info "Default behavior"
By default, the macro is not defined.
```cpp
#undef JSON_SKIP_LIBRARY_VERSION_CHECK
```
The macro was introduced in version 3.11.0.
See [full documentation of `JSON_SKIP_LIBRARY_VERSION_CHECK`](../api/macros/json_skip_library_version_check.md).
## `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.
!!! info "Default behavior"
By default, the macro is not defined.
```cpp
#undef JSON_SKIP_UNSUPPORTED_COMPILER_CHECK
```
The macro was introduced in version 3.2.0.
See [full documentation of `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`](../api/macros/json_skip_unsupported_compiler_check.md).
## `JSON_THROW_USER(exception)`
This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that
`JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield
undefined behavior.
This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown.
!!! info "Default behavior"
When exceptions are enabled, the default value is
[`#!cpp throw exception`](https://en.cppreference.com/w/cpp/language/throw).
```cpp
#define JSON_THROW_USER(exception) throw exception
```
When exceptions are switched off by the compiler, the default value is
[`#!cpp std::abort()`](https://en.cppreference.com/w/cpp/utility/program/abort) to make reaching the throw branch
abort the process.
```cpp
#define JSON_THROW_USER(exception) std::abort()
```
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
The macro was introduced in version 3.1.0.
See [full documentation of `JSON_THROW_USER(exception)`](../api/macros/json_throw_user.md).
## `JSON_TRY_USER`
This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope.
This macro overrides `#!cpp try` calls inside the library.
!!! info "Default behavior"
When exceptions are enabled, the default value is
[`#!cpp try`](https://en.cppreference.com/w/cpp/language/try_catch).
```cpp
#define JSON_TRY_USER try
```
When exceptions are switched off by the compiler, the default value is `#!cpp if (true)` to unconditionally execute
the following code block.
```cpp
#define JSON_TRY_USER if (true)
```
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
The macro was introduced in version 3.1.0.
See [full documentation of `JSON_TRY_USER`](../api/macros/json_throw_user.md).
## `JSON_USE_IMPLICIT_CONVERSIONS`
When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on.
??? example
This is an example for an implicit conversion:
```cpp
json j = "Hello, world!";
std::string s = j;
```
When `JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`, the code above does no longer compile. Instead, it must be
written like this:
```cpp
json j = "Hello, world!";
auto s = j.get<std::string>();
```
Implicit conversions can also be controlled with the CMake option `JSON_ImplicitConversions` (`ON` by default) which
sets `JSON_USE_IMPLICIT_CONVERSIONS` accordingly.
!!! info "Default behavior"
```cpp
#define JSON_USE_IMPLICIT_CONVERSIONS 1
```
The macro was introduced in version 3.9.0.
See [full documentation of `JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md).
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)`
@@ -261,18 +103,15 @@ 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 [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
The macro was introduced in version 3.9.0.
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. In order to support that it requires that the
type be default constructible. The `from_json()` function default constructs an object and uses its values as the
defaults when calling the `value()` function.
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.
The macro was introduced in version 3.11.0.
See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_intrusive.md).
## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)`
@@ -283,29 +122,26 @@ The macro is to be defined inside the namespace of the class/struct to create co
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 [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
The macro was introduced in version 3.9.0.
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. In order to support that it requires that the
type be default constructible. The `from_json()` function default constructs an object and uses its values as the
defaults when calling the `value()` function.
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.
The macro was introduced in version 3.11.0.
See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_non_intrusive.md).
## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)`
This macro simplifies the serialization/deserialization of enum types. See
[Specializing enum conversion](enum_conversion.md) for more information.
The macro was introduced in version 3.4.0.
See [full documentation of `NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md).
## `NLOHMANN_JSON_VERSION_MAJOR`, `NLOHMANN_JSON_VERSION_MINOR`, `NLOHMANN_JSON_VERSION_PATCH`
These macros are defined by the library and contain the version numbers according to
[Semantic Versioning 2.0.0](https://semver.org).
[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
The macros were introduced in version 3.1.0.
See [full documentation of `NLOHMANN_JSON_VERSION_MAJOR`, `NLOHMANN_JSON_VERSION_MINOR`, and `NLOHMANN_JSON_VERSION_PATCH`](../api/macros/nlohmann_json_version_major.md).

View File

@@ -275,7 +275,7 @@ The rationale is twofold:
### Determine number types
As the example in [Number conversion](#number_conversion) shows, there are different functions to determine the type of
As the example in [Number conversion](#number-conversion) shows, there are different functions to determine the type of
the stored number:
- [`is_number()`](../../api/basic_json/is_number.md) returns `#!c true` for any number type