diff --git a/.gitignore b/.gitignore index a13ad89a5c..e4f92117ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,21 @@ -json_unit -json_benchmarks -json_benchmarks_simple -fuzz-testing - *.dSYM *.o *.gcno *.gcda - -build -build_coverage -clang_analyze_build - -benchmarks/files/numbers/*.json +.DS_Store .wsjcpp-logs/* .wsjcpp/* -.idea +/.idea /cmake-build-* -test/test-* /.vs -doc/html -doc/mkdocs/venv/ -doc/mkdocs/docs/examples -doc/mkdocs/site -doc/mkdocs/docs/__pycache__/ +/doc/mkdocs/docs/examples/ +/doc/mkdocs/docs/__pycache__/ +/doc/mkdocs/site/ +/doc/mkdocs/venv/ /doc/docset/JSON_for_Modern_C++.docset/ /doc/docset/JSON_for_Modern_C++.tgz +/doc/mkdocs/docs/images/json.gif diff --git a/README.md b/README.md index 9d9bd2c913..20e7c48eaf 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/t ## Examples -Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). +Beside the examples below, you may want to check the [documentation](https://json.nlohmann.me/) where each function contains a separate code example (e.g., check out [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). ### JSON as first-class data type @@ -162,7 +162,7 @@ json j2 = { }; ``` -Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/api/basic_json/array/) and [`json::object()`](https://nlohmann.github.io/json/api/basic_json/object/) will help: +Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://json.nlohmann.me/api/basic_json/array/) and [`json::object()`](https://json.nlohmann.me/api/basic_json/object/) will help: ```cpp // a way to express the empty array [] @@ -197,7 +197,7 @@ auto j2 = R"( Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. -The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/api/basic_json/parse/): +The above example can also be expressed explicitly using [`json::parse()`](https://json.nlohmann.me/api/basic_json/parse/): ```cpp // parse explicitly @@ -240,9 +240,9 @@ std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.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://nlohmann.github.io/json/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. +* 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 @@ -1647,7 +1647,7 @@ The library supports **Unicode input** as follows: - [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - 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/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. +- When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. - To store wide strings (e.g., `std::wstring`), you need to convert them to a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling). ### Comments in JSON @@ -1682,7 +1682,7 @@ 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://nlohmann.github.io/json/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://nlohmann.github.io/json/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)`. - 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). diff --git a/doc/examples/nlohmann_define_type_intrusive_explicit.cpp b/doc/examples/nlohmann_define_type_intrusive_explicit.cpp new file mode 100644 index 0000000000..fb7701dec8 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_explicit.cpp @@ -0,0 +1,59 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +class person +{ + private: + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + public: + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} + + friend void to_json(nlohmann::json& 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) + { + nlohmann_json_t.name = nlohmann_json_j.at("name"); + nlohmann_json_t.address = nlohmann_json_j.at("address"); + nlohmann_json_t.age = nlohmann_json_j.at("age"); + } +}; +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + try + { + auto p3 = j3.get(); + } + catch (json::exception& e) + { + std::cout << "deserialization failed: " << e.what() << std::endl; + } +} diff --git a/doc/examples/nlohmann_define_type_intrusive_explicit.output b/doc/examples/nlohmann_define_type_intrusive_explicit.output new file mode 100644 index 0000000000..37f4eb4141 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_explicit.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +deserialization failed: [json.exception.out_of_range.403] key 'age' not found diff --git a/doc/examples/nlohmann_define_type_intrusive_macro.cpp b/doc/examples/nlohmann_define_type_intrusive_macro.cpp new file mode 100644 index 0000000000..ce292659a0 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_macro.cpp @@ -0,0 +1,47 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +class person +{ + private: + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + public: + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person, name, address, age) +}; +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + try + { + auto p3 = j3.get(); + } + catch (json::exception& e) + { + std::cout << "deserialization failed: " << e.what() << std::endl; + } +} diff --git a/doc/examples/nlohmann_define_type_intrusive_macro.output b/doc/examples/nlohmann_define_type_intrusive_macro.output new file mode 100644 index 0000000000..37f4eb4141 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_macro.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +deserialization failed: [json.exception.out_of_range.403] key 'age' not found diff --git a/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp b/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp new file mode 100644 index 0000000000..621ed14521 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.cpp @@ -0,0 +1,54 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +class person +{ + private: + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + public: + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} + + friend void to_json(nlohmann::json& 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) + { + person nlohmann_json_default_obj; + nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name); + nlohmann_json_t.address = nlohmann_json_j.value("address", nlohmann_json_default_obj.address); + nlohmann_json_t.age = nlohmann_json_j.value("age", nlohmann_json_default_obj.age); + } +}; +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + auto p3 = j3.get(); + std::cout << "roundtrip: " << json(p3) << std::endl; +} diff --git a/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.output b/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.output new file mode 100644 index 0000000000..1a255f65c6 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_with_default_explicit.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"} diff --git a/doc/examples/nlohmann_define_type_intrusive_with_default_macro.cpp b/doc/examples/nlohmann_define_type_intrusive_with_default_macro.cpp new file mode 100644 index 0000000000..7851f526ea --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_with_default_macro.cpp @@ -0,0 +1,41 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +class person +{ + private: + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + public: + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person, name, address, age) +}; +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + auto p3 = j3.get(); + std::cout << "roundtrip: " << json(p3) << std::endl; +} diff --git a/doc/examples/nlohmann_define_type_intrusive_with_default_macro.output b/doc/examples/nlohmann_define_type_intrusive_with_default_macro.output new file mode 100644 index 0000000000..1a255f65c6 --- /dev/null +++ b/doc/examples/nlohmann_define_type_intrusive_with_default_macro.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_explicit.cpp b/doc/examples/nlohmann_define_type_non_intrusive_explicit.cpp new file mode 100644 index 0000000000..b9d30dd8f8 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_explicit.cpp @@ -0,0 +1,52 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +struct person +{ + std::string name; + std::string address; + int age; +}; + +void to_json(nlohmann::json& 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) +{ + nlohmann_json_t.name = nlohmann_json_j.at("name"); + nlohmann_json_t.address = nlohmann_json_j.at("address"); + nlohmann_json_t.age = nlohmann_json_j.at("age"); +} +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + try + { + auto p3 = j3.get(); + } + catch (json::exception& e) + { + std::cout << "deserialization failed: " << e.what() << std::endl; + } +} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_explicit.output b/doc/examples/nlohmann_define_type_non_intrusive_explicit.output new file mode 100644 index 0000000000..37f4eb4141 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_explicit.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +deserialization failed: [json.exception.out_of_range.403] key 'age' not found diff --git a/doc/examples/nlohmann_define_type_non_intrusive_macro.cpp b/doc/examples/nlohmann_define_type_non_intrusive_macro.cpp new file mode 100644 index 0000000000..b073ef615a --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_macro.cpp @@ -0,0 +1,40 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +struct person +{ + std::string name; + std::string address; + int age; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + try + { + auto p3 = j3.get(); + } + catch (json::exception& e) + { + std::cout << "deserialization failed: " << e.what() << std::endl; + } +} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_macro.output b/doc/examples/nlohmann_define_type_non_intrusive_macro.output new file mode 100644 index 0000000000..37f4eb4141 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_macro.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +deserialization failed: [json.exception.out_of_range.403] key 'age' not found diff --git a/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp b/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp new file mode 100644 index 0000000000..21967b6382 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp @@ -0,0 +1,52 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +struct person +{ + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} +}; + +void to_json(nlohmann::json& 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) +{ + person nlohmann_json_default_obj; + nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name); + nlohmann_json_t.address = nlohmann_json_j.value("address", nlohmann_json_default_obj.address); + nlohmann_json_t.age = nlohmann_json_j.value("age", nlohmann_json_default_obj.age); +} +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + auto p3 = j3.get(); + std::cout << "roundtrip: " << json(p3) << std::endl; +} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output b/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output new file mode 100644 index 0000000000..1a255f65c6 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_with_default_explicit.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp b/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp new file mode 100644 index 0000000000..470fed69c9 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp @@ -0,0 +1,39 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +struct person +{ + std::string name = "John Doe"; + std::string address = "123 Fake St"; + int age = -1; + + person() = default; + person(std::string name_, std::string address_, int age_) + : name(std::move(name_)), address(std::move(address_)), age(age_) + {} +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person, name, address, age) +} // namespace ns + +int main() +{ + ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + + // serialization: person -> json + json j = p; + std::cout << "serialization: " << j << std::endl; + + // deserialization: json -> person + json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json; + auto p2 = j2.get(); + + // incomplete deserialization: + json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json; + auto p3 = j3.get(); + std::cout << "roundtrip: " << json(p3) << std::endl; +} diff --git a/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.output b/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.output new file mode 100644 index 0000000000..1a255f65c6 --- /dev/null +++ b/doc/examples/nlohmann_define_type_non_intrusive_with_default_macro.output @@ -0,0 +1,2 @@ +serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} +roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"} diff --git a/doc/examples/nlohmann_json_serialize_enum.cpp b/doc/examples/nlohmann_json_serialize_enum.cpp new file mode 100644 index 0000000000..f9e472c64b --- /dev/null +++ b/doc/examples/nlohmann_json_serialize_enum.cpp @@ -0,0 +1,59 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +enum TaskState +{ + TS_STOPPED, + TS_RUNNING, + TS_COMPLETED, + TS_INVALID = -1 +}; + +NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, +{ + { TS_INVALID, nullptr }, + { TS_STOPPED, "stopped" }, + { TS_RUNNING, "running" }, + { TS_COMPLETED, "completed" } +}) + +enum class Color +{ + red, green, blue, unknown +}; + +NLOHMANN_JSON_SERIALIZE_ENUM(Color, +{ + { Color::unknown, "unknown" }, { Color::red, "red" }, + { Color::green, "green" }, { Color::blue, "blue" } +}) +} // namespace ns + +int main() +{ + // serialization + json j_stopped = ns::TS_STOPPED; + json j_red = ns::Color::red; + std::cout << "ns::TS_STOPPED -> " << j_stopped + << ", ns::Color::red -> " << j_red << std::endl; + + // deserialization + json j_running = "running"; + json j_blue = "blue"; + auto running = j_running.get(); + auto blue = j_blue.get(); + std::cout << j_running << " -> " << running + << ", " << j_blue << " -> " << static_cast(blue) << std::endl; + + // deserializing undefined JSON value to enum + // (where the first map entry above is the default) + json j_pi = 3.14; + auto invalid = j_pi.get(); + auto unknown = j_pi.get(); + std::cout << j_pi << " -> " << invalid << ", " + << j_pi << " -> " << static_cast(unknown) << std::endl; +} diff --git a/doc/examples/nlohmann_json_serialize_enum.output b/doc/examples/nlohmann_json_serialize_enum.output new file mode 100644 index 0000000000..f512563dda --- /dev/null +++ b/doc/examples/nlohmann_json_serialize_enum.output @@ -0,0 +1,3 @@ +ns::TS_STOPPED -> "stopped", ns::Color::red -> "red" +"running" -> 1, "blue" -> 2 +3.14 -> -1, 3.14 -> 3 diff --git a/doc/examples/nlohmann_json_serialize_enum_2.cpp b/doc/examples/nlohmann_json_serialize_enum_2.cpp new file mode 100644 index 0000000000..fd27226ca9 --- /dev/null +++ b/doc/examples/nlohmann_json_serialize_enum_2.cpp @@ -0,0 +1,33 @@ +#include +#include + +using json = nlohmann::json; + +namespace ns +{ +enum class Color +{ + red, green, blue, unknown +}; + +NLOHMANN_JSON_SERIALIZE_ENUM(Color, +{ + { Color::unknown, "unknown" }, { Color::red, "red" }, + { Color::green, "green" }, { Color::blue, "blue" }, + { Color::red, "rot" } // a second conversion for Color::red +}) +} + +int main() +{ + // serialization + json j_red = ns::Color::red; + std::cout << static_cast(ns::Color::red) << " -> " << j_red << std::endl; + + // deserialization + json j_rot = "rot"; + auto rot = j_rot.get(); + auto red = j_red.get(); + std::cout << j_rot << " -> " << static_cast(rot) << std::endl; + std::cout << j_red << " -> " << static_cast(red) << std::endl; +} diff --git a/doc/examples/nlohmann_json_serialize_enum_2.output b/doc/examples/nlohmann_json_serialize_enum_2.output new file mode 100644 index 0000000000..5dec31b4ad --- /dev/null +++ b/doc/examples/nlohmann_json_serialize_enum_2.output @@ -0,0 +1,3 @@ +0 -> "red" +"rot" -> 0 +"red" -> 0 diff --git a/doc/mkdocs/Makefile b/doc/mkdocs/Makefile index 3d3d5e7c67..3f894d0980 100644 --- a/doc/mkdocs/Makefile +++ b/doc/mkdocs/Makefile @@ -1,18 +1,21 @@ # serve the site locally -serve: prepare_files +serve: prepare_files style_check venv/bin/mkdocs serve -build: prepare_files +serve_dirty: prepare_files style_check + venv/bin/mkdocs serve --dirtyreload + +build: prepare_files style_check venv/bin/mkdocs build -# create files that are not versioned inside the mkdocs folder +# create files that are not versioned inside the mkdocs folder (images, examples) prepare_files: clean - # create subfolders mkdir docs/examples - # copy images - cp -vr ../json.gif docs/images - # copy examples - cp -vr ../examples/*.cpp ../examples/*.output 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 # clean subfolders clean: diff --git a/doc/mkdocs/docs/api/basic_json/back.md b/doc/mkdocs/docs/api/basic_json/back.md index 96e1dec75c..1a715284dc 100644 --- a/doc/mkdocs/docs/api/basic_json/back.md +++ b/doc/mkdocs/docs/api/basic_json/back.md @@ -35,9 +35,9 @@ Constant. ## Notes -!!! danger +!!! info "Precondition" - Calling `back` on an empty array or object is undefined behavior and is **guarded by an assertion**! + The array or object must not be empty. Calling `back` on an empty array or object yields undefined behavior. ## Examples diff --git a/doc/mkdocs/docs/api/basic_json/basic_json.md b/doc/mkdocs/docs/api/basic_json/basic_json.md index ab3fea4708..afa3901d1e 100644 --- a/doc/mkdocs/docs/api/basic_json/basic_json.md +++ b/doc/mkdocs/docs/api/basic_json/basic_json.md @@ -250,17 +250,15 @@ basic_json(basic_json&& other) noexcept; !!! info "Preconditions" - - Iterators `first` and `last` must be initialized. **This precondition is enforced with an assertion (see - warning).** If assertions are switched off, a violation of this precondition yields undefined behavior. + - Iterators `first` and `last` must be initialized. **This precondition is enforced with a + [runtime assertion](../../features/assertions.md). - Range `[first, last)` is valid. Usually, this precondition cannot be checked efficiently. Only certain edge cases are detected; see the description of the exceptions above. A violation of this precondition yields undefined behavior. - !!! warning + !!! danger "Runtime assertion" - A precondition is enforced with a runtime assertion that will result in calling `std::abort` if this - precondition is not met. Assertions can be disabled by defining `NDEBUG` at compile time. See - for more information. + A precondition is enforced with a [runtime assertion](../../features/assertions.md). - Overload 8: diff --git a/doc/mkdocs/docs/api/basic_json/front.md b/doc/mkdocs/docs/api/basic_json/front.md index 909f0b59b0..e258c36a06 100644 --- a/doc/mkdocs/docs/api/basic_json/front.md +++ b/doc/mkdocs/docs/api/basic_json/front.md @@ -28,9 +28,9 @@ Constant. ## Notes -!!! danger +!!! info "Precondition" - Calling `front` on an empty array or object is undefined behavior and is **guarded by an assertion**! + The array or object must not be empty. Calling `front` on an empty array or object yields undefined behavior. ## Examples diff --git a/doc/mkdocs/docs/api/basic_json/get.md b/doc/mkdocs/docs/api/basic_json/get.md index 0a0bc3babc..96fc221daa 100644 --- a/doc/mkdocs/docs/api/basic_json/get.md +++ b/doc/mkdocs/docs/api/basic_json/get.md @@ -90,7 +90,7 @@ Depends on what `json_serializer` `from_json()` method throws ## Notes -!!! warning +!!! danger "Undefined behavior" Writing data to the pointee (overload 3) of the result yields an undefined state. diff --git a/doc/mkdocs/docs/api/basic_json/get_ptr.md b/doc/mkdocs/docs/api/basic_json/get_ptr.md index 72517cd7e1..2441e1156e 100644 --- a/doc/mkdocs/docs/api/basic_json/get_ptr.md +++ b/doc/mkdocs/docs/api/basic_json/get_ptr.md @@ -33,7 +33,7 @@ Constant. ## Notes -!!! warning +!!! danger "Undefined behavior" Writing data to the pointee of the result yields an undefined state. diff --git a/doc/mkdocs/docs/api/basic_json/get_ref.md b/doc/mkdocs/docs/api/basic_json/get_ref.md index 1140836e41..b1219742ca 100644 --- a/doc/mkdocs/docs/api/basic_json/get_ref.md +++ b/doc/mkdocs/docs/api/basic_json/get_ref.md @@ -16,7 +16,7 @@ Implicit reference access to the internally stored JSON value. No copies are mad : reference type; must be a reference to [`array_t`](array_t.md), [`object_t`](object_t.md), [`string_t`](string_t.md), [`boolean_t`](boolean_t.md), [`number_integer_t`](number_integer_t.md), or [`number_unsigned_t`](number_unsigned_t.md), [`number_float_t`](number_float_t.md), or [`binary_t`](binary_t.md). - Enforced by static assertion. + Enforced by a static assertion. ## Return value @@ -38,7 +38,7 @@ Constant. ## Notes -!!! warning +!!! danger "Undefined behavior" Writing data to the referee of the result yields an undefined state. diff --git a/doc/mkdocs/docs/api/basic_json/index.md b/doc/mkdocs/docs/api/basic_json/index.md index f8828dbd81..286fea2b49 100644 --- a/doc/mkdocs/docs/api/basic_json/index.md +++ b/doc/mkdocs/docs/api/basic_json/index.md @@ -292,7 +292,7 @@ Access to the JSON value - [**std::hash<basic_json>**](std_hash.md) - return a hash value for a JSON object - [**std::swap<basic_json>**](std_swap.md) - exchanges the values of two JSON objects -## Example +## Examples ??? example diff --git a/doc/mkdocs/docs/api/basic_json/is_discarded.md b/doc/mkdocs/docs/api/basic_json/is_discarded.md index 6de31c937e..663cbf889e 100644 --- a/doc/mkdocs/docs/api/basic_json/is_discarded.md +++ b/doc/mkdocs/docs/api/basic_json/is_discarded.md @@ -24,7 +24,7 @@ Constant. ## Notes -!!! note +!!! note "Comparisons" Discarded values are never compared equal with [`operator==`](operator_eq.md). That is, checking whether a JSON value `j` is discarded will only work via: @@ -41,7 +41,7 @@ Constant. will always be `#!cpp false`. -!!! note +!!! note "Removal during parsing with callback functions" When a value is discarded by a callback function (see [`parser_callback_t`](parser_callback_t.md)) during parsing, then it is removed when it is part of a structured value. For instance, if the second value of an array is discarded, diff --git a/doc/mkdocs/docs/api/basic_json/items.md b/doc/mkdocs/docs/api/basic_json/items.md index b388824f91..0b34ddcba3 100644 --- a/doc/mkdocs/docs/api/basic_json/items.md +++ b/doc/mkdocs/docs/api/basic_json/items.md @@ -63,7 +63,7 @@ Constant. When iterating over an array, `key()` will return the index of the element as string (see example). For primitive types (e.g., numbers), `key()` returns an empty string. -!!! warning +!!! danger "Lifetime issues" Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See for more information. diff --git a/doc/mkdocs/docs/api/basic_json/meta.md b/doc/mkdocs/docs/api/basic_json/meta.md index e2b312e0cb..87767e4d55 100644 --- a/doc/mkdocs/docs/api/basic_json/meta.md +++ b/doc/mkdocs/docs/api/basic_json/meta.md @@ -45,6 +45,10 @@ Constant. --8<-- "examples/meta.output" ``` +## See also + +- [**NLOHMANN_JSON_VERSION_MAJOR**/**NLOHMANN_JSON_VERSION_MINOR**/**NLOHMANN_JSON_VERSION_PATCH**](../macros/nlohmann_json_version_major.md) - library version information + ## Version history - Added in version 2.1.0. diff --git a/doc/mkdocs/docs/api/basic_json/object_comparator_t.md b/doc/mkdocs/docs/api/basic_json/object_comparator_t.md index 44509a94b2..e2bc79d059 100644 --- a/doc/mkdocs/docs/api/basic_json/object_comparator_t.md +++ b/doc/mkdocs/docs/api/basic_json/object_comparator_t.md @@ -8,7 +8,7 @@ using object_comparator_t = std::less<>; // since C++14 The comparator used in [`object_t`](object_t.md). -When C++14 is detected, a transparent com parator is used which, when combined with perfect forwarding on find() and +When C++14 is detected, a transparent comparator is used which, when combined with perfect forwarding on find() and count() calls, prevents unnecessary string construction. ## Version history diff --git a/doc/mkdocs/docs/api/basic_json/operator[].md b/doc/mkdocs/docs/api/basic_json/operator[].md index 5b6512a21c..cc9eae7f36 100644 --- a/doc/mkdocs/docs/api/basic_json/operator[].md +++ b/doc/mkdocs/docs/api/basic_json/operator[].md @@ -74,10 +74,11 @@ Strong exception safety: if an exception occurs, the original value stays intact ## Notes -!!! danger +!!! danger "Undefined behavior and runtime assertions" 1. If the element with key `idx` does not exist, the behavior is undefined. - 2. If the element with key `key` does not exist, the behavior is undefined and is **guarded by an assertion**! + 2. If the element with key `key` does not exist, the behavior is undefined and is **guarded by a + [runtime assertion](../../features/assertions.md)**! 1. The non-const version may add values: If `idx` is beyond the range of the array (i.e., `idx >= size()`), then the array is silently filled up with `#!json null` values to make `idx` a valid reference to the last stored element. In diff --git a/doc/mkdocs/docs/api/basic_json/operator_ValueType.md b/doc/mkdocs/docs/api/basic_json/operator_ValueType.md index 1eec13553f..7875887811 100644 --- a/doc/mkdocs/docs/api/basic_json/operator_ValueType.md +++ b/doc/mkdocs/docs/api/basic_json/operator_ValueType.md @@ -27,33 +27,44 @@ Linear in the size of the JSON value. ## Notes -By default `JSON_EXPLICIT` defined to the empty string, so the signature is: +!!! note "Definition of `JSON_EXPLICIT`" -```cpp -template -operator ValueType() const; -``` + By default `JSON_EXPLICIT` is defined to the empty string, so the signature is: + + ```cpp + template + operator ValueType() const; + ``` + + If [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) is set to `0`, + `JSON_EXPLICIT` is defined to `#!cpp explicit`: -If [`JSON_USE_IMPLICIT_CONVERSIONS`](../../features/macros.md#json_use_implicit_conversions) is set to `0`, -`JSON_EXPLICIT` is defined to `#!cpp explicit`: + ```cpp + template + explicit operator ValueType() const; + ``` + + That is, implicit conversions can be switched off by defining + [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) to `0`. -```cpp -template -explicit operator ValueType() const; -``` +!!! info "Future behavior change" + + Implicit conversions will be switched off by default in the next major release of the library. That is, + `JSON_EXPLICIT` will be set to `#!cpp explicit` by default. + + You can prepare existing code by already defining + [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) to `0` and replace any implicit + conversions with calls to [`get`](../basic_json/get.md). -That is, implicit conversions can be switched off by defining -[`JSON_USE_IMPLICIT_CONVERSIONS`](../../features/macros.md#json_use_implicit_conversions) to `0`. ## Examples ??? example - The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers, (2) A JSON array can be converted to a standard - `std::vector`, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`. + The example below shows several conversions from JSON values to other types. There are a few things to note: (1) + Floating-point numbers can be converted to integers, (2) A JSON array can be converted to a standard + `std::vector`, (3) A JSON object can be converted to C++ associative containers such as + `std::unordered_map`. ```cpp --8<-- "examples/operator__ValueType.cpp" diff --git a/doc/mkdocs/docs/api/basic_json/value.md b/doc/mkdocs/docs/api/basic_json/value.md index 0b4f1cc19a..1844c41fb0 100644 --- a/doc/mkdocs/docs/api/basic_json/value.md +++ b/doc/mkdocs/docs/api/basic_json/value.md @@ -36,7 +36,7 @@ ValueType value(const json_pointer& ptr, } ``` -!!! note +!!! note "Differences to `at` and `operator[]`" - Unlike [`at`](at.md), this function does not throw if the given `key`/`ptr` was not found. - Unlike [`operator[]`](operator[].md), this function does not implicitly add an element to the position defined by diff --git a/doc/mkdocs/docs/api/json_pointer/index.md b/doc/mkdocs/docs/api/json_pointer/index.md index 3504c9ff78..dca9c382c5 100644 --- a/doc/mkdocs/docs/api/json_pointer/index.md +++ b/doc/mkdocs/docs/api/json_pointer/index.md @@ -16,7 +16,13 @@ are the base for JSON patches. ## Notes -For backwards compatibility `RefStringType` may also be a specialization of [`basic_json`](../basic_json/index.md) in which case `string_t` will be deduced as [`basic_json::string_t`](../basic_json/string_t.md). This feature is deprecated and may be removed in a future major version. +For backwards compatibility `RefStringType` may also be a specialization of [`basic_json`](../basic_json/index.md) in +which case `string_t` will be deduced as [`basic_json::string_t`](../basic_json/string_t.md). This feature is deprecated +and may be removed in a future major version. + +## Member types + +- [**string_t**](string_t.md) - the string type used for the reference tokens ## Member functions @@ -31,10 +37,6 @@ For backwards compatibility `RefStringType` may also be a specialization of [`ba - [**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 -## Member types - -- [**string_t**](string_t.md) - the string type used for the reference tokens - ## See also - [operator""_json_pointer](../basic_json/operator_literal_json_pointer.md) - user-defined string literal for JSON pointers diff --git a/doc/mkdocs/docs/api/macros/index.md b/doc/mkdocs/docs/api/macros/index.md index 4c723c6a6f..56924da445 100644 --- a/doc/mkdocs/docs/api/macros/index.md +++ b/doc/mkdocs/docs/api/macros/index.md @@ -1,22 +1,37 @@ # Macros -!!! note - - This page is under construction. See the [macro overview page](../../features/macros.md) until then. - -Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header. - -- [`JSON_ASSERT(x)`](json_assert.md) -- `JSON_CATCH_USER(exception)` -- `JSON_DIAGNOSTICS` -- `JSON_HAS_CPP_11`, `JSON_HAS_CPP_14`, `JSON_HAS_CPP_17`, `JSON_HAS_CPP_20` -- `JSON_NOEXCEPTION` -- `JSON_NO_IO` -- `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK` -- `JSON_THROW_USER(exception)` -- `JSON_TRY_USER` -- `JSON_USE_IMPLICIT_CONVERSIONS` -- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)` -- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)` -- `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)` -- `NLOHMANN_JSON_VERSION_MAJOR`, `NLOHMANN_JSON_VERSION_MINOR`, `NLOHMANN_JSON_VERSION_PATCH` +Some aspects of the library can be configured by defining preprocessor macros **before** including the `json.hpp` +header. See also the [macro overview page](../../features/macros.md). + +## Runtime assertions + +- [**JSON_ASSERT(x)**](json_assert.md) - control behavior of runtime assertions + +## Exceptions + +- [**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_NOEXCEPTION**](json_noexception.md) - switch off exceptions + +## Language support + +- [**JSON_HAS_CPP_11**
**JSON_HAS_CPP_14**
**JSON_HAS_CPP_17**
**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard +- [**JSON_HAS_FILESYSTEM**
**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support +- [**JSON_NO_IO**](json_no_io.md) - switch off functions relying on certain C++ I/O headers +- [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers + +## Library version + +- [**JSON_SKIP_LIBRARY_VERSION_CHECK**](json_skip_library_version_check.md) - skip library version check +- [**NLOHMANN_JSON_VERSION_MAJOR**
**NLOHMANN_JSON_VERSION_MINOR**
**NLOHMANN_JSON_VERSION_PATCH**](nlohmann_json_version_major.md) - library version information + +## Type conversions + +- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions + +## Serialization/deserialization macros + +- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)**
**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)**](nlohmann_define_type_intrusive.md) - 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.md) - serialization/deserialization of types _without_ access to private variables +- [**NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)**](nlohmann_json_serialize_enum.md) - serialization/deserialization of enum + types diff --git a/doc/mkdocs/docs/api/macros/json_assert.md b/doc/mkdocs/docs/api/macros/json_assert.md index 63d4ae0762..a093341a1b 100644 --- a/doc/mkdocs/docs/api/macros/json_assert.md +++ b/doc/mkdocs/docs/api/macros/json_assert.md @@ -1,11 +1,84 @@ -# JSON_ASSERT(x) +# JSON_ASSERT ```cpp -JSON_ASSERT(x) +#define JSON_ASSERT(x) /* value */ ``` -## Default implementation +This macro controls which code is executed for [runtime assertions](../../features/assertions.md) of the library. + +## Parameters + +`x` (in) +: expression of scalar type + +## Default definition + +The default value is [`#!cpp assert(x)`](https://en.cppreference.com/w/cpp/error/assert). ```cpp -assert(x); +#define JSON_ASSERT(x) assert(x) ``` + +Therefore, assertions can be switched off by defining `NDEBUG`. + +## Notes + +- The library uses numerous assertions to guarantee invariants and to abort in case of otherwise undefined behavior + (e.g., when calling [operator[]](../basic_json/operator%5B%5D.md) with a missing object key on a `const` object). See + page [runtime assertions](../../features/assertions.md) for more information. +- Defining the macro to code that does not call `std::abort` may leave the library in an undefined state. +- The macro is undefined outside the library. + +## Examples + +??? example "Example 1: default behavior" + + The following code will trigger an assertion at runtime: + + ```cpp + #include + + 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. + ``` + +??? example "Example 2: user-defined behavior" + + The assertion reporting can be changed by defining `JSON_ASSERT(x)` differently. + + ```cpp + #include + #include + #define JSON_ASSERT(x) if(!(x)){fprintf(stderr, "assertion error in %s\n", __FUNCTION__); std::abort();} + + #include + + using json = nlohmann::json; + + int main() + { + const json j = {{"key", "value"}}; + auto v = j["missing"]; + } + ``` + + Output: + + ``` + assertion error in operator[] + ``` + +## Version history + +- Added in version 3.9.0. diff --git a/doc/mkdocs/docs/api/macros/json_diagnostics.md b/doc/mkdocs/docs/api/macros/json_diagnostics.md new file mode 100644 index 0000000000..d42025092c --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_diagnostics.md @@ -0,0 +1,67 @@ +# JSON_DIAGNOSTICS + +```cpp +#define JSON_DIAGNOSTICS /* value */ +``` + +This macro enables [extended diagnostics for exception messages](../../home/exceptions.md#extended-diagnostic-messages). +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. + +The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets +`JSON_DIAGNOSTICS` accordingly. + +## Default definition + +The default value is `0` (extended diagnostics are switched off). + +```cpp +#define JSON_DIAGNOSTICS 0 +``` + +When the macro is not defined, the library will define it to its default value. + +## Notes + +!!! danger "ABI incompatibility" + + 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: `basic_json` objects with differently defined `JSON_DIAGNOSTICS` macros are + not compatible! + +## Examples + +??? example "Example 1: default behavior" + + ```cpp + --8<-- "examples/diagnostics_standard.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostics_standard.output" + ``` + + This exception can be hard to debug if storing the value `#!c "12"` and accessing it is further apart. + +??? example "Example 2: extended diagnostic messages" + + ```cpp + --8<-- "examples/diagnostics_extended.cpp" + ``` + + Output: + + ``` + --8<-- "examples/diagnostics_extended.output" + ``` + + Now the exception message contains a JSON Pointer `/address/housenumber` that indicates which value has the wrong type. + +## Version history + +- Added in version 3.10.0. diff --git a/doc/mkdocs/docs/api/macros/json_has_cpp_11.md b/doc/mkdocs/docs/api/macros/json_has_cpp_11.md new file mode 100644 index 0000000000..3bee843245 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_has_cpp_11.md @@ -0,0 +1,28 @@ +# JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20 + +```cpp +#define JSON_HAS_CPP_11 +#define JSON_HAS_CPP_14 +#define JSON_HAS_CPP_17 +#define JSON_HAS_CPP_20 +``` + +The library targets C++11, but also supports some features introduced in later C++ versions (e.g., `std::string_view` +support for C++17). For these new features, the library implements some preprocessor checks to determine the C++ +standard. By defining any of these symbols, the internal check is overridden and the provided C++ version is +unconditionally assumed. This can be helpful for compilers that only implement parts of the standard and would be +detected incorrectly. + +## Default definition + +The default value is detected based on preprocessor macros such as `#!cpp __cplusplus`, `#!cpp _HAS_CXX17`, or +`#!cpp _MSVC_LANG`. + +## Notes + +- `#!cpp JSON_HAS_CPP_11` is always defined. +- All macros are undefined outside the library. + +## Version history + +- Added in version 3.10.5. diff --git a/doc/mkdocs/docs/api/macros/json_has_filesystem.md b/doc/mkdocs/docs/api/macros/json_has_filesystem.md new file mode 100644 index 0000000000..160ad8c244 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_has_filesystem.md @@ -0,0 +1,30 @@ +# JSON_HAS_FILESYSTEM / JSON_HAS_EXPERIMENTAL_FILESYSTEM + +```cpp +#define JSON_HAS_FILESYSTEM /* value */ +#define JSON_HAS_EXPERIMENTAL_FILESYSTEM /* value */ +``` + +When compiling with C++17, the library provides conversions from and to +[`std::filesystem::path`](https://en.cppreference.com/w/cpp/filesystem/path). As compiler support for filesystem is +limited, the library tries to detect whether +[``/`std::filesystem`](https://en.cppreference.com/w/cpp/header/filesystem) (`JSON_HAS_FILESYSTEM`) or +[``/`std::experimental::filesystem`](https://en.cppreference.com/w/cpp/header/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`. + +## Default definition + +The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_filesystem`, +`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include()`, or +`#!cpp __has_include()`. + +## Notes + +- Note that older compilers or older versions of libstd++ also require the library `stdc++fs` to be linked to for + filesystem support. +- Both macros are undefined outside the library. + +## Version history + +- Added in version 3.10.5. diff --git a/doc/mkdocs/docs/api/macros/json_no_io.md b/doc/mkdocs/docs/api/macros/json_no_io.md new file mode 100644 index 0000000000..10ae24c8a8 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_no_io.md @@ -0,0 +1,21 @@ +# JSON_NO_IO + +```cpp +#define JSON_NO_IO +``` + +When defined, headers ``, ``, ``, ``, and `` are not included and parse functions +relying on these headers are excluded. This is relevant for environments where these I/O functions are disallowed for +security reasons (e.g., Intel Software Guard Extensions (SGX)). + +## Default definition + +By default, `#!cpp JSON_NO_IO` is not defined. + +```cpp +#undef JSON_NO_IO +``` + +## Version history + +- Added in version 3.10.0. diff --git a/doc/mkdocs/docs/api/macros/json_noexception.md b/doc/mkdocs/docs/api/macros/json_noexception.md new file mode 100644 index 0000000000..0f32b63e9e --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_noexception.md @@ -0,0 +1,32 @@ +# JSON_NOEXCEPTION + +```cpp +#define 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()`. + +The same effect is achieved by setting the compiler flag `-fno-exceptions`. + +## Default definition + +By default, the macro is not defined. + +```cpp +#undef JSON_NOEXCEPTION +``` + +## Notes + +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 also + +- [Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for more information how to switch off exceptions + +## Version history + +Added in version 2.1.0. diff --git a/doc/mkdocs/docs/api/macros/json_skip_library_version_check.md b/doc/mkdocs/docs/api/macros/json_skip_library_version_check.md new file mode 100644 index 0000000000..c9a743c18d --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_skip_library_version_check.md @@ -0,0 +1,37 @@ +# JSON_SKIP_LIBRARY_VERSION_CHECK + +```cpp +#define 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. + +## Default definition + +By default, the macro is not defined. + +```cpp +#undef JSON_SKIP_LIBRARY_VERSION_CHECK +``` + +## Notes + +!!! danger "ABI compatibility" + + Mixing different library versions in the same code can be a problem as the different versions may not be ABI + compatible. + +## Examples + +!!! example + + The following warning will be shown in case a different version of the library was already included: + + ``` + Already included a different version of the library! + ``` + +## Version history + +Added in version 3.11.0. diff --git a/doc/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md b/doc/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md new file mode 100644 index 0000000000..c58d0ea850 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md @@ -0,0 +1,20 @@ +# JSON_SKIP_UNSUPPORTED_COMPILER_CHECK + +```cpp +#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. + +## Default definition + +By default, the macro is not defined. + +```cpp +#undef JSON_SKIP_UNSUPPORTED_COMPILER_CHECK +``` + +## Version history + +Added in version 3.2.0. diff --git a/doc/mkdocs/docs/api/macros/json_throw_user.md b/doc/mkdocs/docs/api/macros/json_throw_user.md new file mode 100644 index 0000000000..e10db90e46 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_throw_user.md @@ -0,0 +1,75 @@ +# JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER + +```cpp +// (1) +#define JSON_CATCH_USER(exception) /* value */ +// (2) +#define JSON_THROW_USER(exception) /* value */ +// (3) +#define JSON_TRY_USER /* value */ +``` + +Controls how exceptions are handled by the library. + +1. 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. +2. 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. +3. This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope. + +## Parameters + +`exception` (in) +: an exception type + +## Default definition + +By default, the macros map to their respective C++ keywords: + +```cpp +#define JSON_CATCH_USER(exception) catch(exception) +#define JSON_THROW_USER(exception) throw exception +#define JSON_TRY_USER try +``` + +When exceptions are switched off, the `#!cpp try` block is executed unconditionally, and throwing exceptions is +replaced by calling [`std::abort`](https://en.cppreference.com/w/cpp/utility/program/abort) to make reaching the +`#!cpp throw` branch abort the process. + +```cpp +#define JSON_THROW_USER(exception) std::abort() +#define JSON_TRY_USER if (true) +#define JSON_CATCH_USER(exception) if (false) +``` + +## Examples + +??? example + + The code below switches off exceptions and creates a log entry with a detailed error message in case of errors. + + ```cpp + #include + + #define JSON_TRY_USER if(true) + #define JSON_CATCH_USER(exception) if(false) + #define JSON_THROW_USER(exception) \ + {std::clog << "Error in " << __FILE__ << ":" << __LINE__ \ + << " (function " << __FUNCTION__ << ") - " \ + << (exception).what() << std::endl; \ + std::abort();} + + #include + ``` + +## See also + +- [Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for more information how to switch off exceptions +- [JSON_NOEXCEPTION](JSON_NOEXCEPTION) - switch off exceptions + +## Version history + +- Added in version 3.1.0. diff --git a/doc/mkdocs/docs/api/macros/json_use_implicit_conversions.md b/doc/mkdocs/docs/api/macros/json_use_implicit_conversions.md new file mode 100644 index 0000000000..3ee81b0619 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/json_use_implicit_conversions.md @@ -0,0 +1,56 @@ +# JSON_USE_IMPLICIT_CONVERSIONS + +```cpp +#define JSON_USE_IMPLICIT_CONVERSIONS /* value */ +``` + +When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on. The +value directly affects [`operator ValueType`](../basic_json/operator_ValueType.md). + +Implicit conversions can also be controlled with the CMake option `JSON_ImplicitConversions` (`ON` by default) which +sets `JSON_USE_IMPLICIT_CONVERSIONS` accordingly. + +## Default definition + +By default, implicit conversions are enabled. + +```cpp +#define JSON_USE_IMPLICIT_CONVERSIONS 1 +``` + +## Notes + +!!! info "Future behavior change" + + Implicit conversions will be switched off by default in the next major release of the library. + + You can prepare existing code by already defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` and replace any implicit + conversions with calls to [`get`](../basic_json/get.md). + +## Examples + +??? 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(); + ``` + +## See also + +- [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit) +- [**get**](../basic_json/get.md) - get a value (explicit) + +## Version history + +- Added in version 3.9.0. diff --git a/doc/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md b/doc/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md new file mode 100644 index 0000000000..7269ef0814 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md @@ -0,0 +1,124 @@ +# NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT + +```cpp +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...) // (1) +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...) // (2) +``` + +These macros can be used to simplify the serialization/deserialization of 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. The macro is to be defined +**inside** the class/struct to create code for. +Unlike [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](nlohmann_define_type_non_intrusive.md), it can access private members. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +1. 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. +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. + +## Parameters + +`type` (in) +: 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 + +## 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&); +``` + +See examples below for the concrete generated code. + +## Notes + +!!! info "Prerequisites" + + 1. The type `type` must be default constructible. See [How can I use `get()` for non-default constructible/non-copyable types?](../../features/arbitrary_types.md#how-can-i-use-get-for-non-default-constructiblenon-copyable-types) + for how to overcome this limitation. + 2. The macro must be used inside the type (class/struct). + +!!! warning "Implementation limits" + + - 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 + +??? example "Example (1): NLOHMANN_DEFINE_TYPE_INTRUSIVE" + + Consider the following complete example: + + ```cpp hl_lines="21" + --8<-- "examples/nlohmann_define_type_intrusive_macro.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_define_type_intrusive_macro.output" + ``` + + Notes: + + - `ns::person` is default-constructible. This is a requirement for using the macro. + - `ns::person` has private member variables. This makes `NLOHMANN_DEFINE_TYPE_INTRUSIVE` applicable, but not + `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. + - The macro `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is used _inside_ the class. + - A missing key "age" in the deserialization yields an exception. To fall back to the default value, + `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` can be used. + + The macro is equivalent to: + + ```cpp hl_lines="21 22 23 24 25 26 27 28 29 30 31 32 33" + --8<-- "examples/nlohmann_define_type_intrusive_explicit.cpp" + ``` + +??? example "Example (2): NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT" + + Consider the following complete example: + + ```cpp hl_lines="21" + --8<-- "examples/nlohmann_define_type_intrusive_with_default_macro.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_define_type_intrusive_with_default_macro.output" + ``` + + Notes: + + - `ns::person` is default-constructible. This is a requirement for using the macro. + - `ns::person` has private member variables. This makes `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` applicable, + but not `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`. + - The macro `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` is used _inside_ the class. + - A missing key "age" in the deserialization does not yield an exception. Instead, the default value `-1` is used. + + The macro is equivalent to: + + ```cpp hl_lines="21 22 23 24 25 26 27 28 29 30 31 32 33 34" + --8<-- "examples/nlohmann_define_type_intrusive_with_default_explicit.cpp" + ``` + + Note how a default-initialized `person` object is used in the `from_json` to fill missing values. + +## See also + +- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE / NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_non_intrusive.md) + for a similar macro that can be defined _outside_ the type. +- [Arbitrary Types Conversions](../../features/arbitrary_types.md) for an overview. + +## Version history + +1. Added in version 3.9.0. +2. Added in version 3.11.0. diff --git a/doc/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md b/doc/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md new file mode 100644 index 0000000000..7ed5a6b436 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md @@ -0,0 +1,124 @@ +# NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT + +```cpp +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...) // (1) +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...) // (2) +``` + +These macros can be used to simplify the serialization/deserialization of 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. The macro is to be defined +**outside** the class/struct to create code for, but **inside** its namespace. +Unlike [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](nlohmann_define_type_intrusive.md), it **cannot** access private members. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +1. 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. +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. + +## Parameters + +`type` (in) +: 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 + +## 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&); +``` + +See examples below for the concrete generated code. + +## Notes + +!!! info "Prerequisites" + + 1. The type `type` must be default constructible. See [How can I use `get()` for non-default constructible/non-copyable types?](../../features/arbitrary_types.md#how-can-i-use-get-for-non-default-constructiblenon-copyable-types) + for how to overcome this limitation. + 2. The macro must be used outside the type (class/struct). + 3. The passed members must be public. + +!!! warning "Implementation limits" + + - 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 + +??? example "Example (1): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE" + + Consider the following complete example: + + ```cpp hl_lines="15" + --8<-- "examples/nlohmann_define_type_non_intrusive_macro.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_define_type_non_intrusive_macro.output" + ``` + + Notes: + + - `ns::person` is default-constructible. This is a requirement for using the macro. + - `ns::person` has only public member variables. This makes `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` applicable. + - The macro `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` is used _outside_ the class, but _inside_ its namespace `ns`. + - A missing key "age" in the deserialization yields an exception. To fall back to the default value, + `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT` can be used. + + The macro is equivalent to: + + ```cpp hl_lines="15 16 17 18 19 20 21 22 23 24 25 26 27" + --8<-- "examples/nlohmann_define_type_non_intrusive_explicit.cpp" + ``` + +??? example "Example (2): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT" + + Consider the following complete example: + + ```cpp hl_lines="20" + --8<-- "examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_define_type_non_intrusive_with_default_macro.output" + ``` + + Notes: + + - `ns::person` is default-constructible. This is a requirement for using the macro. + - `ns::person` has only public member variables. This makes `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT` + applicable. + - The macro `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT` is used _outside_ the class, but _inside_ its namespace `ns`. + - A missing key "age" in the deserialization does not yield an exception. Instead, the default value `-1` is used. + + The macro is equivalent to: + + ```cpp hl_lines="20 21 22 23 24 25 26 27 28 29 30 31 32 33" + --8<-- "examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp" + ``` + + Note how a default-initialized `person` object is used in the `from_json` to fill missing values. + +## See also + +- [NLOHMANN_DEFINE_TYPE_INTRUSIVE / NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_intrusive.md) + for a similar macro that can be defined _inside_ the type. +- [Arbitrary Types Conversions](../../features/arbitrary_types.md) for an overview. + +## Version history + +1. Added in version 3.9.0. +2. Added in version 3.11.0. diff --git a/doc/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md b/doc/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md new file mode 100644 index 0000000000..7b0f898021 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md @@ -0,0 +1,84 @@ +# NLOHMANN_JSON_SERIALIZE_ENUM + +```cpp +#define NLOHMANN_JSON_SERIALIZE_ENUM(type, 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 +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. + +## Parameters + +`type` (in) +: name of the enum to serialize/deserialize + +`conversion` (in) +: a pair of an enumerator and a JSON serialization; arbitrary pairs can can be given as comma-separated list + +## Default definition + +The macros add two friend functions to the class which take care of the serialization and deserialization: + +```cpp +template +inline void to_json(BasicJsonType& j, const type& e); +template +inline void from_json(const BasicJsonType& j, type& e); +``` + +## Notes + +!!! info "Prerequisites" + + The macro must be used inside the namespace of the enum. + +!!! important "Important notes" + + - When using [`get()`](../basic_json/get.md), undefined JSON values will default to the first specified + conversion. Select this default pair carefully. See example 1 below. + - If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the + list will be returned when converting to or from JSON. See example 2 below. + +## Examples + +??? example "Example 1: Basic usage" + + The example shows how `NLOHMANN_JSON_SERIALIZE_ENUM` can be used to serialize/deserialize both classical enums and + C++11 enum classes: + + ```cpp hl_lines="16 17 18 19 20 21 22 29 30 31 32 33" + --8<-- "examples/nlohmann_json_serialize_enum.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_json_serialize_enum.output" + ``` + +??? example "Example 2: Multiple conversions for one enumerator" + + The example shows how to use multiple conversions for a single enumerator. In the example, `Color::red` will always + be *serialized* to `"red"`, because the first occurring conversion. The second conversion, however, offers an + alternative *deserialization* from `"rot"` to `Color::red`. + + ```cpp hl_lines="17" + --8<-- "examples/nlohmann_json_serialize_enum_2.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_json_serialize_enum_2.output" + ``` + +## See also + +- [Specializing enum conversion](../../features/enum_conversion.md) + +## Version history + +Added in version 3.4.0. diff --git a/doc/mkdocs/docs/api/macros/nlohmann_json_version_major.md b/doc/mkdocs/docs/api/macros/nlohmann_json_version_major.md new file mode 100644 index 0000000000..8267852923 --- /dev/null +++ b/doc/mkdocs/docs/api/macros/nlohmann_json_version_major.md @@ -0,0 +1,23 @@ +# NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH + +```cpp +#define NLOHMANN_JSON_VERSION_MAJOR /* value */ +#define NLOHMANN_JSON_VERSION_MINOR /* value */ +#define NLOHMANN_JSON_VERSION_PATCH /* value */ +``` + +These macros are defined by the library and contain the version numbers according to +[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). + +## Default definition + +The macros are defined according to the current library version. + +## See also + +- [meta](../basic_json/meta.md) - returns version information on the library +- [JSON_SKIP_LIBRARY_VERSION_CHECK](json_skip_library_version_check.md) - skip library version check + +## Version history + +- Added in version 3.1.0. diff --git a/doc/mkdocs/docs/features/arbitrary_types.md b/doc/mkdocs/docs/features/arbitrary_types.md index 67e8a45549..49a541ef5c 100644 --- a/doc/mkdocs/docs/features/arbitrary_types.md +++ b/doc/mkdocs/docs/features/arbitrary_types.md @@ -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` **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 diff --git a/doc/mkdocs/docs/features/assertions.md b/doc/mkdocs/docs/features/assertions.md new file mode 100644 index 0000000000..a0b1187224 --- /dev/null +++ b/doc/mkdocs/docs/features/assertions.md @@ -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 + + 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 + + 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 + + using json = nlohmann::json; + + int main() + { + json::iterator it; + ++it; + } + ``` + + Output: + + ``` + Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368. + ``` diff --git a/doc/mkdocs/docs/features/element_access/unchecked_access.md b/doc/mkdocs/docs/features/element_access/unchecked_access.md index bb7228777e..4fdef35c7f 100644 --- a/doc/mkdocs/docs/features/element_access/unchecked_access.md +++ b/doc/mkdocs/docs/features/element_access/unchecked_access.md @@ -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 | diff --git a/doc/mkdocs/docs/features/enum_conversion.md b/doc/mkdocs/docs/features/enum_conversion.md index 8f474a702c..7e61f67bb8 100644 --- a/doc/mkdocs/docs/features/enum_conversion.md +++ b/doc/mkdocs/docs/features/enum_conversion.md @@ -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() == 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: diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index 576ec935de..e04a426a54 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -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 ``/`s or ``/`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()`, or - `#!cpp __has_include()`. - -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()`. - -!!! info "Default behavior" - - By default, the macro is not defined. - - ```cpp - #undef JSON_NOEXCEPTION - ``` +Exceptions can be switched off by defining the symbol `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 ``, ``, ``, ``, and `(); - ``` - -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). diff --git a/doc/mkdocs/docs/features/types/number_handling.md b/doc/mkdocs/docs/features/types/number_handling.md index dd65073532..03d8c9c693 100644 --- a/doc/mkdocs/docs/features/types/number_handling.md +++ b/doc/mkdocs/docs/features/types/number_handling.md @@ -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 diff --git a/doc/mkdocs/docs/home/exceptions.md b/doc/mkdocs/docs/home/exceptions.md index 1241926cf4..666d225bd2 100644 --- a/doc/mkdocs/docs/home/exceptions.md +++ b/doc/mkdocs/docs/home/exceptions.md @@ -28,9 +28,9 @@ class json::parse_error { ### Switch off exceptions -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 `#!cpp throw`), `JSON_TRY_USER` (overriding `#!cpp try`), and `JSON_CATCH_USER` (overriding `#!cpp catch`). +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`](../api/macros/json_noexception.md). In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `#!cpp throw`), `JSON_TRY_USER` (overriding `#!cpp try`), and `JSON_CATCH_USER` (overriding `#!cpp 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 that [`JSON_THROW_USER`](../api/macros/json_throw_user.md) should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. ??? example @@ -52,6 +52,8 @@ Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or 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 [documentation of `JSON_TRY_USER`, `JSON_CATCH_USER` and `JSON_THROW_USER`](../api/macros/json_throw_user.md) for more information. + ### Extended diagnostic messages Exceptions in the library are thrown in the local context of the JSON value they are detected. This makes detailed diagnostics messages, and hence debugging, difficult. @@ -88,6 +90,7 @@ As this global context comes at the price of storing one additional pointer per Now the exception message contains a JSON Pointer `/address/housenumber` that indicates which value has the wrong type. +See [documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) for more information. ## Parse errors diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index ddd55e5c95..59f0ae700b 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -64,6 +64,7 @@ nav: - 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: @@ -232,7 +233,30 @@ nav: - 'ordered_map': api/ordered_map.md - macros: - 'Overview': api/macros/index.md - - 'JSON_ASSERT(x)': api/macros/json_assert.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_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_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_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.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_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 # Extras extra: @@ -289,6 +313,7 @@ plugins: lang: en - minify: minify_html: true + - git-revision-date-localized extra_javascript: - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML diff --git a/doc/mkdocs/requirements.txt b/doc/mkdocs/requirements.txt index b64e9b8731..aa9fcaf0e2 100644 --- a/doc/mkdocs/requirements.txt +++ b/doc/mkdocs/requirements.txt @@ -1,29 +1,48 @@ -click>=7.1.2 -future>=0.18.2 -htmlmin>=0.1.12 -httplib2>=0.18.1 -importlib-metadata>=1.6.0 -Jinja2>=2.11.2 -joblib>=0.15.1 -jsmin>=2.2.2 -livereload>=2.6.1 -lunr>=0.5.8 -Markdown>=3.2.2 -markdown-include>=0.5.1 -MarkupSafe>=1.1.1 -mkdocs>=1.1.2 -mkdocs-material>=5.2.1 -mkdocs-material-extensions>=1.0 -mkdocs-minify-plugin>=0.3.0 -mkdocs-simple-hooks>=0.1.1 -nltk>=3.5 -plantuml>=0.3.0 -plantuml-markdown>=3.2.2 -Pygments>=2.6.1 -pymdown-extensions>=7.1 -PyYAML>=5.3.1 -regex>=2020.5.14 -six>=1.15.0 -tornado>=6.0.4 -tqdm>=4.46.0 -zipp>=3.1.0 +Babel==2.10.1 +certifi==2021.10.8 +charset-normalizer==2.0.12 +click==8.1.2 +csscompressor==0.9.5 +future==0.18.2 +ghp-import==2.0.2 +gitdb==4.0.9 +GitPython==3.1.27 +htmlmin==0.1.12 +httplib2==0.20.4 +idna==3.3 +importlib-metadata==4.11.3 +Jinja2==3.1.1 +joblib==1.1.0 +jsmin==3.0.1 +livereload==2.6.3 +lunr==0.6.2 +Markdown==3.3.6 +markdown-include==0.6.0 +MarkupSafe==2.1.1 +mergedeep==1.3.4 +mkdocs==1.3.0 +mkdocs-git-revision-date-localized-plugin==1.0.1 +mkdocs-material==8.2.10 +mkdocs-material-extensions==1.0.3 +mkdocs-minify-plugin==0.5.0 +mkdocs-simple-hooks==0.1.5 +nltk==3.7 +packaging==21.3 +plantuml==0.3.0 +plantuml-markdown==3.5.2 +Pygments==2.11.0 +pymdown-extensions==9.3 +pyparsing==3.0.8 +python-dateutil==2.8.2 +pytz==2022.1 +PyYAML==6.0 +pyyaml_env_tag==0.1 +regex==2022.4.24 +requests==2.27.1 +six==1.16.0 +smmap==5.0.0 +tornado==6.1 +tqdm==4.64.0 +urllib3==1.26.9 +watchdog==2.1.7 +zipp==3.8.0 diff --git a/doc/mkdocs/scripts/check_structure.py b/doc/mkdocs/scripts/check_structure.py old mode 100644 new mode 100755 index cacc51cb4a..92f6ff1820 --- a/doc/mkdocs/scripts/check_structure.py +++ b/doc/mkdocs/scripts/check_structure.py @@ -2,10 +2,19 @@ import glob import os.path +import re + +warnings = 0 + + +def report(rule, location, description): + global warnings + warnings += 1 + print(f'{warnings:3}. {location}: {description} [{rule}]') def check_structure(): - expected_headers = [ + expected_sections = [ 'Template parameters', 'Specializations', 'Iterator invalidation', @@ -23,13 +32,14 @@ def check_structure(): 'Exceptions', 'Complexity', 'Possible implementation', + 'Default definition', 'Notes', 'Examples', 'See also', 'Version history' ] - required_headers = [ + required_sections = [ 'Examples', 'Version history' ] @@ -37,8 +47,8 @@ def check_structure(): files = sorted(glob.glob('api/**/*.md', recursive=True)) for file in files: with open(file) as file_content: - header_idx = -1 - existing_headers = [] + section_idx = -1 + existing_sections = [] in_initial_code_example = False previous_line = None h1sections = 0 @@ -51,50 +61,55 @@ def check_structure(): # there should only be one top-level title if h1sections > 1: - print(f'{file}:{lineno+1}: Error: 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': - print(f'{file}:{lineno+1}: Error: overview pages should have a better title!') + 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: - print(f'{file}:{lineno+1}: Error: line is too long ({len(line)} vs. 160 chars)!') + report('whitespace/line_length', f'{file}:{lineno+1}', f'line is too long ({len(line)} vs. 160 chars)') - # check if headers are correct + # check if sections are correct if line.startswith('## '): - header = line.strip('## ') - existing_headers.append(header) - - if header in expected_headers: - idx = expected_headers.index(header) - if idx <= header_idx: - print(f'{file}:{lineno+1}: Error: header "{header}" is in an unexpected order (should be before "{expected_headers[header_idx]}")!') - header_idx = idx + 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]}")') + section_idx = idx else: - print(f'{file}:{lineno+1}: Error: header "{header}" is not part of the expected headers!') + report('structure/unknown_section', f'{file}:{lineno+1}', f'section "{current_section}" is not part of the expected sections') # code example - if line == '```cpp' and header_idx == -1: + if line == '```cpp' and section_idx == -1: in_initial_code_example = True if in_initial_code_example and line.startswith('//'): if any(map(str.isdigit, line)) and '(' not in line: - print(f'{file}:{lineno+1}: Number should be in parentheses: {line}') + report('style/numbering', f'{file}:{lineno+1}', 'number should be in parentheses: {line}') if line == '```' and in_initial_code_example: in_initial_code_example = False # consecutive blank lines are bad if line == '' and previous_line == '': - print(f'{file}:{lineno}-{lineno+1}: Error: Consecutive blank lines!') + report('whitespace/blank_lines', f'{file}:{lineno}-{lineno+1}', '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}', f'"{untitled_admonition.group(2)}" admonitions should have a title') previous_line = line - for required_header in required_headers: - if required_header not in existing_headers: - print(f'{file}:{lineno+1}: Error: required header "{required_header}" was not found!') + 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') def check_examples(): @@ -113,9 +128,11 @@ def check_examples(): break if not found: - print(f'{example_file}: Error: 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 * '-') check_structure() check_examples() + print(120 * '-')